Merge branch 'feature/meta' into develop
This commit is contained in:
commit
795889d934
@ -109,4 +109,3 @@ add_subdirectory(api/logic)
|
|||||||
add_subdirectory(api/gui)
|
add_subdirectory(api/gui)
|
||||||
|
|
||||||
add_subdirectory(application)
|
add_subdirectory(application)
|
||||||
add_subdirectory(wonkoclient)
|
|
||||||
|
@ -23,7 +23,6 @@
|
|||||||
#include "settings/Setting.h"
|
#include "settings/Setting.h"
|
||||||
#include "settings/OverrideSetting.h"
|
#include "settings/OverrideSetting.h"
|
||||||
|
|
||||||
#include "minecraft/MinecraftVersionList.h"
|
|
||||||
#include "FileSystem.h"
|
#include "FileSystem.h"
|
||||||
#include "Commandline.h"
|
#include "Commandline.h"
|
||||||
|
|
||||||
|
@ -30,7 +30,7 @@ BaseVersionPtr BaseVersionList::findVersion(const QString &descriptor)
|
|||||||
return BaseVersionPtr();
|
return BaseVersionPtr();
|
||||||
}
|
}
|
||||||
|
|
||||||
BaseVersionPtr BaseVersionList::getLatestStable() const
|
BaseVersionPtr BaseVersionList::getRecommended() const
|
||||||
{
|
{
|
||||||
if (count() <= 0)
|
if (count() <= 0)
|
||||||
return BaseVersionPtr();
|
return BaseVersionPtr();
|
||||||
@ -38,11 +38,6 @@ BaseVersionPtr BaseVersionList::getLatestStable() const
|
|||||||
return at(0);
|
return at(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
BaseVersionPtr BaseVersionList::getRecommended() const
|
|
||||||
{
|
|
||||||
return getLatestStable();
|
|
||||||
}
|
|
||||||
|
|
||||||
QVariant BaseVersionList::data(const QModelIndex &index, int role) const
|
QVariant BaseVersionList::data(const QModelIndex &index, int role) const
|
||||||
{
|
{
|
||||||
if (!index.isValid())
|
if (!index.isValid())
|
||||||
@ -93,7 +88,7 @@ QHash<int, QByteArray> BaseVersionList::roleNames() const
|
|||||||
QHash<int, QByteArray> roles = QAbstractListModel::roleNames();
|
QHash<int, QByteArray> roles = QAbstractListModel::roleNames();
|
||||||
roles.insert(VersionRole, "version");
|
roles.insert(VersionRole, "version");
|
||||||
roles.insert(VersionIdRole, "versionId");
|
roles.insert(VersionIdRole, "versionId");
|
||||||
roles.insert(ParentGameVersionRole, "parentGameVersion");
|
roles.insert(ParentVersionRole, "parentGameVersion");
|
||||||
roles.insert(RecommendedRole, "recommended");
|
roles.insert(RecommendedRole, "recommended");
|
||||||
roles.insert(LatestRole, "latest");
|
roles.insert(LatestRole, "latest");
|
||||||
roles.insert(TypeRole, "type");
|
roles.insert(TypeRole, "type");
|
||||||
|
@ -22,6 +22,7 @@
|
|||||||
#include "BaseVersion.h"
|
#include "BaseVersion.h"
|
||||||
#include "tasks/Task.h"
|
#include "tasks/Task.h"
|
||||||
#include "multimc_logic_export.h"
|
#include "multimc_logic_export.h"
|
||||||
|
#include "QObjectPtr.h"
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \brief Class that each instance type's version list derives from.
|
* \brief Class that each instance type's version list derives from.
|
||||||
@ -44,7 +45,7 @@ public:
|
|||||||
VersionPointerRole = Qt::UserRole,
|
VersionPointerRole = Qt::UserRole,
|
||||||
VersionRole,
|
VersionRole,
|
||||||
VersionIdRole,
|
VersionIdRole,
|
||||||
ParentGameVersionRole,
|
ParentVersionRole,
|
||||||
RecommendedRole,
|
RecommendedRole,
|
||||||
LatestRole,
|
LatestRole,
|
||||||
TypeRole,
|
TypeRole,
|
||||||
@ -63,7 +64,7 @@ public:
|
|||||||
* The task returned by this function should reset the model when it's done.
|
* The task returned by this function should reset the model when it's done.
|
||||||
* \return A pointer to a task that reloads the version list.
|
* \return A pointer to a task that reloads the version list.
|
||||||
*/
|
*/
|
||||||
virtual Task *getLoadTask() = 0;
|
virtual shared_qobject_ptr<Task> getLoadTask() = 0;
|
||||||
|
|
||||||
//! Checks whether or not the list is loaded. If this returns false, the list should be
|
//! Checks whether or not the list is loaded. If this returns false, the list should be
|
||||||
//loaded.
|
//loaded.
|
||||||
@ -76,27 +77,22 @@ public:
|
|||||||
virtual int count() const = 0;
|
virtual int count() const = 0;
|
||||||
|
|
||||||
//////// List Model Functions ////////
|
//////// List Model Functions ////////
|
||||||
virtual QVariant data(const QModelIndex &index, int role) const;
|
QVariant data(const QModelIndex &index, int role) const override;
|
||||||
virtual int rowCount(const QModelIndex &parent) const;
|
int rowCount(const QModelIndex &parent) const override;
|
||||||
virtual int columnCount(const QModelIndex &parent) const;
|
int columnCount(const QModelIndex &parent) const override;
|
||||||
virtual QHash<int, QByteArray> roleNames() const override;
|
virtual QHash<int, QByteArray> roleNames() const;
|
||||||
|
|
||||||
//! which roles are provided by this version list?
|
//! which roles are provided by this version list?
|
||||||
virtual RoleList providesRoles() const;
|
virtual RoleList providesRoles() const;
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \brief Finds a version by its descriptor.
|
* \brief Finds a version by its descriptor.
|
||||||
* \param The descriptor of the version to find.
|
* \param descriptor The descriptor of the version to find.
|
||||||
* \return A const pointer to the version with the given descriptor. NULL if
|
* \return A const pointer to the version with the given descriptor. NULL if
|
||||||
* one doesn't exist.
|
* one doesn't exist.
|
||||||
*/
|
*/
|
||||||
virtual BaseVersionPtr findVersion(const QString &descriptor);
|
virtual BaseVersionPtr findVersion(const QString &descriptor);
|
||||||
|
|
||||||
/*!
|
|
||||||
* \brief Gets the latest stable version from this list
|
|
||||||
*/
|
|
||||||
virtual BaseVersionPtr getLatestStable() const;
|
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \brief Gets the recommended version from this list
|
* \brief Gets the recommended version from this list
|
||||||
* If the list doesn't support recommended versions, this works exactly as getLatestStable
|
* If the list doesn't support recommended versions, this works exactly as getLatestStable
|
||||||
|
@ -252,10 +252,6 @@ set(MINECRAFT_SOURCES
|
|||||||
minecraft/JarMod.h
|
minecraft/JarMod.h
|
||||||
minecraft/MinecraftInstance.cpp
|
minecraft/MinecraftInstance.cpp
|
||||||
minecraft/MinecraftInstance.h
|
minecraft/MinecraftInstance.h
|
||||||
minecraft/MinecraftVersion.cpp
|
|
||||||
minecraft/MinecraftVersion.h
|
|
||||||
minecraft/MinecraftVersionList.cpp
|
|
||||||
minecraft/MinecraftVersionList.h
|
|
||||||
minecraft/Rule.cpp
|
minecraft/Rule.cpp
|
||||||
minecraft/Rule.h
|
minecraft/Rule.h
|
||||||
minecraft/OpSys.cpp
|
minecraft/OpSys.cpp
|
||||||
@ -271,6 +267,7 @@ set(MINECRAFT_SOURCES
|
|||||||
minecraft/VersionBuildError.h
|
minecraft/VersionBuildError.h
|
||||||
minecraft/VersionFile.cpp
|
minecraft/VersionFile.cpp
|
||||||
minecraft/VersionFile.h
|
minecraft/VersionFile.h
|
||||||
|
minecraft/ProfilePatch.cpp
|
||||||
minecraft/ProfilePatch.h
|
minecraft/ProfilePatch.h
|
||||||
minecraft/VersionFilterData.h
|
minecraft/VersionFilterData.h
|
||||||
minecraft/VersionFilterData.cpp
|
minecraft/VersionFilterData.cpp
|
||||||
@ -300,22 +297,10 @@ set(MINECRAFT_SOURCES
|
|||||||
minecraft/AssetsUtils.cpp
|
minecraft/AssetsUtils.cpp
|
||||||
|
|
||||||
# Forge and all things forge related
|
# Forge and all things forge related
|
||||||
minecraft/forge/ForgeVersion.h
|
|
||||||
minecraft/forge/ForgeVersion.cpp
|
|
||||||
minecraft/forge/ForgeVersionList.h
|
|
||||||
minecraft/forge/ForgeVersionList.cpp
|
|
||||||
minecraft/forge/ForgeXzDownload.h
|
minecraft/forge/ForgeXzDownload.h
|
||||||
minecraft/forge/ForgeXzDownload.cpp
|
minecraft/forge/ForgeXzDownload.cpp
|
||||||
minecraft/forge/LegacyForge.h
|
|
||||||
minecraft/forge/LegacyForge.cpp
|
|
||||||
minecraft/forge/ForgeInstaller.h
|
|
||||||
minecraft/forge/ForgeInstaller.cpp
|
|
||||||
|
|
||||||
# Liteloader and related things
|
# Skin upload utilities
|
||||||
minecraft/liteloader/LiteLoaderInstaller.h
|
|
||||||
minecraft/liteloader/LiteLoaderInstaller.cpp
|
|
||||||
minecraft/liteloader/LiteLoaderVersionList.h
|
|
||||||
minecraft/liteloader/LiteLoaderVersionList.cpp
|
|
||||||
minecraft/SkinUpload.cpp
|
minecraft/SkinUpload.cpp
|
||||||
minecraft/SkinUpload.h
|
minecraft/SkinUpload.h
|
||||||
)
|
)
|
||||||
@ -430,32 +415,22 @@ set(TOOLS_SOURCES
|
|||||||
tools/MCEditTool.h
|
tools/MCEditTool.h
|
||||||
)
|
)
|
||||||
|
|
||||||
set(WONKO_SOURCES
|
set(META_SOURCES
|
||||||
# Wonko
|
# Metadata sources
|
||||||
wonko/tasks/BaseWonkoEntityRemoteLoadTask.cpp
|
meta/JsonFormat.cpp
|
||||||
wonko/tasks/BaseWonkoEntityRemoteLoadTask.h
|
meta/JsonFormat.h
|
||||||
wonko/tasks/BaseWonkoEntityLocalLoadTask.cpp
|
meta/BaseEntity.cpp
|
||||||
wonko/tasks/BaseWonkoEntityLocalLoadTask.h
|
meta/BaseEntity.h
|
||||||
wonko/format/WonkoFormatV1.cpp
|
meta/VersionList.cpp
|
||||||
wonko/format/WonkoFormatV1.h
|
meta/VersionList.h
|
||||||
wonko/format/WonkoFormat.cpp
|
meta/Version.cpp
|
||||||
wonko/format/WonkoFormat.h
|
meta/Version.h
|
||||||
wonko/BaseWonkoEntity.cpp
|
meta/Index.cpp
|
||||||
wonko/BaseWonkoEntity.h
|
meta/Index.h
|
||||||
wonko/WonkoVersionList.cpp
|
|
||||||
wonko/WonkoVersionList.h
|
|
||||||
wonko/WonkoVersion.cpp
|
|
||||||
wonko/WonkoVersion.h
|
|
||||||
wonko/WonkoIndex.cpp
|
|
||||||
wonko/WonkoIndex.h
|
|
||||||
wonko/WonkoUtil.cpp
|
|
||||||
wonko/WonkoUtil.h
|
|
||||||
wonko/WonkoReference.cpp
|
|
||||||
wonko/WonkoReference.h
|
|
||||||
)
|
)
|
||||||
|
|
||||||
add_unit_test(WonkoIndex
|
add_unit_test(Index
|
||||||
SOURCES wonko/WonkoIndex_test.cpp
|
SOURCES meta/Index_test.cpp
|
||||||
LIBS MultiMC_logic
|
LIBS MultiMC_logic
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -480,7 +455,7 @@ set(LOGIC_SOURCES
|
|||||||
${JAVA_SOURCES}
|
${JAVA_SOURCES}
|
||||||
${TRANSLATIONS_SOURCES}
|
${TRANSLATIONS_SOURCES}
|
||||||
${TOOLS_SOURCES}
|
${TOOLS_SOURCES}
|
||||||
${WONKO_SOURCES}
|
${META_SOURCES}
|
||||||
${ICONS_SOURCES}
|
${ICONS_SOURCES}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
#include <QNetworkAccessManager>
|
#include <QNetworkAccessManager>
|
||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
#include "tasks/Task.h"
|
#include "tasks/Task.h"
|
||||||
#include "wonko/WonkoIndex.h"
|
#include "meta/Index.h"
|
||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
|
|
||||||
|
|
||||||
@ -18,8 +18,7 @@ public:
|
|||||||
shared_qobject_ptr<HttpMetaCache> m_metacache;
|
shared_qobject_ptr<HttpMetaCache> m_metacache;
|
||||||
std::shared_ptr<IIconList> m_iconlist;
|
std::shared_ptr<IIconList> m_iconlist;
|
||||||
QMap<QString, std::shared_ptr<BaseVersionList>> m_versionLists;
|
QMap<QString, std::shared_ptr<BaseVersionList>> m_versionLists;
|
||||||
shared_qobject_ptr<WonkoIndex> m_wonkoIndex;
|
shared_qobject_ptr<Meta::Index> m_metadataIndex;
|
||||||
QString m_wonkoRootUrl;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static Env * instance;
|
static Env * instance;
|
||||||
@ -99,13 +98,13 @@ void Env::registerVersionList(QString name, std::shared_ptr< BaseVersionList > v
|
|||||||
d->m_versionLists[name] = vlist;
|
d->m_versionLists[name] = vlist;
|
||||||
}
|
}
|
||||||
|
|
||||||
shared_qobject_ptr<WonkoIndex> Env::wonkoIndex()
|
shared_qobject_ptr<Meta::Index> Env::metadataIndex()
|
||||||
{
|
{
|
||||||
if (!d->m_wonkoIndex)
|
if (!d->m_metadataIndex)
|
||||||
{
|
{
|
||||||
d->m_wonkoIndex.reset(new WonkoIndex());
|
d->m_metadataIndex.reset(new Meta::Index());
|
||||||
}
|
}
|
||||||
return d->m_wonkoIndex;
|
return d->m_metadataIndex;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -125,7 +124,7 @@ void Env::initHttpMetaCache()
|
|||||||
m_metacache->addBase("root", QDir::currentPath());
|
m_metacache->addBase("root", QDir::currentPath());
|
||||||
m_metacache->addBase("translations", QDir("translations").absolutePath());
|
m_metacache->addBase("translations", QDir("translations").absolutePath());
|
||||||
m_metacache->addBase("icons", QDir("cache/icons").absolutePath());
|
m_metacache->addBase("icons", QDir("cache/icons").absolutePath());
|
||||||
m_metacache->addBase("wonko", QDir("cache/wonko").absolutePath());
|
m_metacache->addBase("meta", QDir("meta").absolutePath());
|
||||||
m_metacache->Load();
|
m_metacache->Load();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -191,14 +190,4 @@ void Env::updateProxySettings(QString proxyTypeStr, QString addr, int port, QStr
|
|||||||
qDebug() << proxyDesc;
|
qDebug() << proxyDesc;
|
||||||
}
|
}
|
||||||
|
|
||||||
QString Env::wonkoRootUrl() const
|
|
||||||
{
|
|
||||||
return d->m_wonkoRootUrl;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Env::setWonkoRootUrl(const QString& url)
|
|
||||||
{
|
|
||||||
d->m_wonkoRootUrl = url;
|
|
||||||
}
|
|
||||||
|
|
||||||
#include "Env.moc"
|
#include "Env.moc"
|
@ -13,7 +13,11 @@ class QNetworkAccessManager;
|
|||||||
class HttpMetaCache;
|
class HttpMetaCache;
|
||||||
class BaseVersionList;
|
class BaseVersionList;
|
||||||
class BaseVersion;
|
class BaseVersion;
|
||||||
class WonkoIndex;
|
|
||||||
|
namespace Meta
|
||||||
|
{
|
||||||
|
class Index;
|
||||||
|
}
|
||||||
|
|
||||||
#if defined(ENV)
|
#if defined(ENV)
|
||||||
#undef ENV
|
#undef ENV
|
||||||
@ -53,10 +57,7 @@ public:
|
|||||||
|
|
||||||
void registerIconList(std::shared_ptr<IIconList> iconlist);
|
void registerIconList(std::shared_ptr<IIconList> iconlist);
|
||||||
|
|
||||||
shared_qobject_ptr<WonkoIndex> wonkoIndex();
|
shared_qobject_ptr<Meta::Index> metadataIndex();
|
||||||
|
|
||||||
QString wonkoRootUrl() const;
|
|
||||||
void setWonkoRootUrl(const QString &url);
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
Private * d;
|
Private * d;
|
||||||
|
@ -4,7 +4,6 @@
|
|||||||
#include "FileSystem.h"
|
#include "FileSystem.h"
|
||||||
|
|
||||||
//FIXME: remove this
|
//FIXME: remove this
|
||||||
#include "minecraft/MinecraftVersion.h"
|
|
||||||
#include "minecraft/onesix/OneSixInstance.h"
|
#include "minecraft/onesix/OneSixInstance.h"
|
||||||
|
|
||||||
InstanceCreationTask::InstanceCreationTask(SettingsObjectPtr settings, BaseInstanceProvider* target, BaseVersionPtr version,
|
InstanceCreationTask::InstanceCreationTask(SettingsObjectPtr settings, BaseInstanceProvider* target, BaseVersionPtr version,
|
||||||
@ -21,12 +20,14 @@ InstanceCreationTask::InstanceCreationTask(SettingsObjectPtr settings, BaseInsta
|
|||||||
void InstanceCreationTask::executeTask()
|
void InstanceCreationTask::executeTask()
|
||||||
{
|
{
|
||||||
setStatus(tr("Creating instance from version %1").arg(m_version->name()));
|
setStatus(tr("Creating instance from version %1").arg(m_version->name()));
|
||||||
|
/*
|
||||||
auto minecraftVersion = std::dynamic_pointer_cast<MinecraftVersion>(m_version);
|
auto minecraftVersion = std::dynamic_pointer_cast<MinecraftVersion>(m_version);
|
||||||
if(!minecraftVersion)
|
if(!minecraftVersion)
|
||||||
{
|
{
|
||||||
emitFailed(tr("The supplied version is not a Minecraft version."));
|
emitFailed(tr("The supplied version is not a Minecraft version."));
|
||||||
return ;
|
return ;
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
QString stagingPath = m_target->getStagedInstancePath();
|
QString stagingPath = m_target->getStagedInstancePath();
|
||||||
QDir rootDir(stagingPath);
|
QDir rootDir(stagingPath);
|
||||||
@ -34,7 +35,6 @@ void InstanceCreationTask::executeTask()
|
|||||||
auto instanceSettings = std::make_shared<INISettingsObject>(FS::PathCombine(stagingPath, "instance.cfg"));
|
auto instanceSettings = std::make_shared<INISettingsObject>(FS::PathCombine(stagingPath, "instance.cfg"));
|
||||||
instanceSettings->registerSetting("InstanceType", "Legacy");
|
instanceSettings->registerSetting("InstanceType", "Legacy");
|
||||||
|
|
||||||
auto mcVer = std::dynamic_pointer_cast<MinecraftVersion>(m_version);
|
|
||||||
instanceSettings->set("InstanceType", "OneSix");
|
instanceSettings->set("InstanceType", "OneSix");
|
||||||
InstancePtr inst(new OneSixInstance(m_globalSettings, instanceSettings, stagingPath));
|
InstancePtr inst(new OneSixInstance(m_globalSettings, instanceSettings, stagingPath));
|
||||||
inst->setIntendedVersionId(m_version->descriptor());
|
inst->setIntendedVersionId(m_version->descriptor());
|
||||||
|
61
api/logic/ProblemProvider.h
Normal file
61
api/logic/ProblemProvider.h
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
enum class ProblemSeverity
|
||||||
|
{
|
||||||
|
None,
|
||||||
|
Warning,
|
||||||
|
Error
|
||||||
|
};
|
||||||
|
|
||||||
|
class PatchProblem
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
PatchProblem(ProblemSeverity severity, const QString & description)
|
||||||
|
{
|
||||||
|
m_severity = severity;
|
||||||
|
m_description = description;
|
||||||
|
}
|
||||||
|
const QString & getDescription() const
|
||||||
|
{
|
||||||
|
return m_description;
|
||||||
|
}
|
||||||
|
const ProblemSeverity getSeverity() const
|
||||||
|
{
|
||||||
|
return m_severity;
|
||||||
|
}
|
||||||
|
private:
|
||||||
|
ProblemSeverity m_severity;
|
||||||
|
QString m_description;
|
||||||
|
};
|
||||||
|
|
||||||
|
class ProblemProvider
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
virtual const QList<PatchProblem> getProblems() = 0;
|
||||||
|
virtual ProblemSeverity getProblemSeverity() = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
class ProblemContainer : public ProblemProvider
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
const QList<PatchProblem> getProblems() override
|
||||||
|
{
|
||||||
|
return m_problems;
|
||||||
|
}
|
||||||
|
ProblemSeverity getProblemSeverity() override
|
||||||
|
{
|
||||||
|
return m_problemSeverity;
|
||||||
|
}
|
||||||
|
virtual void addProblem(ProblemSeverity severity, const QString &description)
|
||||||
|
{
|
||||||
|
if(severity > m_problemSeverity)
|
||||||
|
{
|
||||||
|
m_problemSeverity = severity;
|
||||||
|
}
|
||||||
|
m_problems.append(PatchProblem(severity, description));
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
QList<PatchProblem> m_problems;
|
||||||
|
ProblemSeverity m_problemSeverity = ProblemSeverity::None;
|
||||||
|
};
|
@ -75,6 +75,7 @@ void Version::parse()
|
|||||||
{
|
{
|
||||||
m_sections.clear();
|
m_sections.clear();
|
||||||
|
|
||||||
|
// FIXME: this is bad. versions can contain a lot more separators...
|
||||||
QStringList parts = m_string.split('.');
|
QStringList parts = m_string.split('.');
|
||||||
|
|
||||||
for (const auto part : parts)
|
for (const auto part : parts)
|
||||||
@ -82,59 +83,3 @@ void Version::parse()
|
|||||||
m_sections.append(Section(part));
|
m_sections.append(Section(part));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool versionIsInInterval(const QString &version, const QString &interval)
|
|
||||||
{
|
|
||||||
return versionIsInInterval(Version(version), interval);
|
|
||||||
}
|
|
||||||
bool versionIsInInterval(const Version &version, const QString &interval)
|
|
||||||
{
|
|
||||||
if (interval.isEmpty() || version.toString() == interval)
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Interval notation is used
|
|
||||||
QRegularExpression exp(
|
|
||||||
"(?<start>[\\[\\]\\(\\)])(?<bottom>.*?)(,(?<top>.*?))?(?<end>[\\[\\]\\(\\)]),?");
|
|
||||||
QRegularExpressionMatch match = exp.match(interval);
|
|
||||||
if (match.hasMatch())
|
|
||||||
{
|
|
||||||
const QChar start = match.captured("start").at(0);
|
|
||||||
const QChar end = match.captured("end").at(0);
|
|
||||||
const QString bottom = match.captured("bottom");
|
|
||||||
const QString top = match.captured("top");
|
|
||||||
|
|
||||||
// check if in range (bottom)
|
|
||||||
if (!bottom.isEmpty())
|
|
||||||
{
|
|
||||||
const auto bottomVersion = Version(bottom);
|
|
||||||
if ((start == '[') && !(version >= bottomVersion))
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
else if ((start == '(') && !(version > bottomVersion))
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// check if in range (top)
|
|
||||||
if (!top.isEmpty())
|
|
||||||
{
|
|
||||||
const auto topVersion = Version(top);
|
|
||||||
if ((end == ']') && !(version <= topVersion))
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
else if ((end == ')') && !(version < topVersion))
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
@ -104,7 +104,3 @@ private:
|
|||||||
|
|
||||||
void parse();
|
void parse();
|
||||||
};
|
};
|
||||||
|
|
||||||
MULTIMC_LOGIC_EXPORT bool versionIsInInterval(const QString &version, const QString &interval);
|
|
||||||
MULTIMC_LOGIC_EXPORT bool versionIsInInterval(const Version &version, const QString &interval);
|
|
||||||
|
|
||||||
|
@ -60,44 +60,6 @@ private slots:
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void test_versionIsInInterval_data()
|
|
||||||
{
|
|
||||||
QTest::addColumn<QString>("version");
|
|
||||||
QTest::addColumn<QString>("interval");
|
|
||||||
QTest::addColumn<bool>("result");
|
|
||||||
|
|
||||||
QTest::newRow("empty, true") << "1.2.3" << "" << true;
|
|
||||||
QTest::newRow("one version, true") << "1.2.3" << "1.2.3" << true;
|
|
||||||
QTest::newRow("one version, false") << "1.2.3" << "1.2.2" << false;
|
|
||||||
|
|
||||||
QTest::newRow("one version inclusive <-> infinity, true") << "1.2.3" << "[1.2.3,)" << true;
|
|
||||||
QTest::newRow("one version exclusive <-> infinity, true") << "1.2.3" << "(1.2.2,)" << true;
|
|
||||||
QTest::newRow("one version inclusive <-> infitity, false") << "1.2.3" << "[1.2.4,)" << false;
|
|
||||||
QTest::newRow("one version exclusive <-> infinity, false") << "1.2.3" << "(1.2.3,)" << false;
|
|
||||||
|
|
||||||
QTest::newRow("infinity <-> one version inclusive, true") << "1.2.3" << "(,1.2.3]" << true;
|
|
||||||
QTest::newRow("infinity <-> one version exclusive, true") << "1.2.3" << "(,1.2.4)" << true;
|
|
||||||
QTest::newRow("infinity <-> one version inclusive, false") << "1.2.3" << "(,1.2.2]" << false;
|
|
||||||
QTest::newRow("infinity <-> one version exclusive, false") << "1.2.3" << "(,1.2.3)" << false;
|
|
||||||
|
|
||||||
QTest::newRow("inclusive <-> inclusive, true") << "1.2.3" << "[1.2.2,1.2.3]" << true;
|
|
||||||
QTest::newRow("inclusive <-> exclusive, true") << "1.2.3" << "[1.2.3,1.2.4)" << true;
|
|
||||||
QTest::newRow("exclusive <-> inclusive, true") << "1.2.3" << "(1.2.2,1.2.3]" << true;
|
|
||||||
QTest::newRow("exclusive <-> exclusive, true") << "1.2.3" << "(1.2.2,1.2.4)" << true;
|
|
||||||
QTest::newRow("inclusive <-> inclusive, false") << "1.2.3" << "[1.0.0,1.2.2]" << false;
|
|
||||||
QTest::newRow("inclusive <-> exclusive, false") << "1.2.3" << "[1.0.0,1.2.3)" << false;
|
|
||||||
QTest::newRow("exclusive <-> inclusive, false") << "1.2.3" << "(1.2.3,2.0.0]" << false;
|
|
||||||
QTest::newRow("exclusive <-> exclusive, false") << "1.2.3" << "(1.0.0,1.2.3)" << false;
|
|
||||||
}
|
|
||||||
void test_versionIsInInterval()
|
|
||||||
{
|
|
||||||
QFETCH(QString, version);
|
|
||||||
QFETCH(QString, interval);
|
|
||||||
QFETCH(bool, result);
|
|
||||||
|
|
||||||
QCOMPARE(versionIsInInterval(version, interval), result);
|
|
||||||
}
|
|
||||||
|
|
||||||
void test_versionCompare_data()
|
void test_versionCompare_data()
|
||||||
{
|
{
|
||||||
setupVersions();
|
setupVersions();
|
||||||
|
@ -29,7 +29,7 @@ JavaInstallList::JavaInstallList(QObject *parent) : BaseVersionList(parent)
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
Task *JavaInstallList::getLoadTask()
|
shared_qobject_ptr<Task> JavaInstallList::getLoadTask()
|
||||||
{
|
{
|
||||||
return new JavaListLoadTask(this);
|
return new JavaListLoadTask(this);
|
||||||
}
|
}
|
||||||
|
@ -34,17 +34,17 @@ class MULTIMC_LOGIC_EXPORT JavaInstallList : public BaseVersionList
|
|||||||
public:
|
public:
|
||||||
explicit JavaInstallList(QObject *parent = 0);
|
explicit JavaInstallList(QObject *parent = 0);
|
||||||
|
|
||||||
virtual Task *getLoadTask() override;
|
shared_qobject_ptr<Task> getLoadTask() override;
|
||||||
virtual bool isLoaded() override;
|
bool isLoaded() override;
|
||||||
virtual const BaseVersionPtr at(int i) const override;
|
const BaseVersionPtr at(int i) const override;
|
||||||
virtual int count() const override;
|
int count() const override;
|
||||||
virtual void sortVersions() override;
|
void sortVersions() override;
|
||||||
|
|
||||||
virtual QVariant data(const QModelIndex &index, int role) const override;
|
QVariant data(const QModelIndex &index, int role) const override;
|
||||||
virtual RoleList providesRoles() const override;
|
RoleList providesRoles() const override;
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
virtual void updateListData(QList<BaseVersionPtr> versions) override;
|
void updateListData(QList<BaseVersionPtr> versions) override;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
QList<BaseVersionPtr> m_vlist;
|
QList<BaseVersionPtr> m_vlist;
|
||||||
@ -60,7 +60,7 @@ public:
|
|||||||
explicit JavaListLoadTask(JavaInstallList *vlist);
|
explicit JavaListLoadTask(JavaInstallList *vlist);
|
||||||
~JavaListLoadTask();
|
~JavaListLoadTask();
|
||||||
|
|
||||||
virtual void executeTask();
|
void executeTask() override;
|
||||||
public slots:
|
public slots:
|
||||||
void javaCheckerFinished(QList<JavaCheckResult> results);
|
void javaCheckerFinished(QList<JavaCheckResult> results);
|
||||||
|
|
||||||
|
@ -3,6 +3,14 @@
|
|||||||
#include "multimc_logic_export.h"
|
#include "multimc_logic_export.h"
|
||||||
#include <QString>
|
#include <QString>
|
||||||
|
|
||||||
|
// NOTE: apparently the GNU C library pollutes the global namespace with these... undef them.
|
||||||
|
#ifdef major
|
||||||
|
#undef major
|
||||||
|
#endif
|
||||||
|
#ifdef minor
|
||||||
|
#undef minor
|
||||||
|
#endif
|
||||||
|
|
||||||
class MULTIMC_LOGIC_EXPORT JavaVersion
|
class MULTIMC_LOGIC_EXPORT JavaVersion
|
||||||
{
|
{
|
||||||
friend class JavaVersionTest;
|
friend class JavaVersionTest;
|
||||||
|
153
api/logic/meta/BaseEntity.cpp
Normal file
153
api/logic/meta/BaseEntity.cpp
Normal file
@ -0,0 +1,153 @@
|
|||||||
|
/* Copyright 2015-2017 MultiMC Contributors
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "BaseEntity.h"
|
||||||
|
|
||||||
|
#include "Json.h"
|
||||||
|
|
||||||
|
#include "net/Download.h"
|
||||||
|
#include "net/HttpMetaCache.h"
|
||||||
|
#include "net/NetJob.h"
|
||||||
|
|
||||||
|
#include "Env.h"
|
||||||
|
#include "Json.h"
|
||||||
|
|
||||||
|
class ParsingValidator : public Net::Validator
|
||||||
|
{
|
||||||
|
public: /* con/des */
|
||||||
|
ParsingValidator(Meta::BaseEntity *entity) : m_entity(entity)
|
||||||
|
{
|
||||||
|
};
|
||||||
|
virtual ~ParsingValidator()
|
||||||
|
{
|
||||||
|
};
|
||||||
|
|
||||||
|
public: /* methods */
|
||||||
|
bool init(QNetworkRequest &) override
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
bool write(QByteArray & data) override
|
||||||
|
{
|
||||||
|
this->data.append(data);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
bool abort() override
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
bool validate(QNetworkReply &) override
|
||||||
|
{
|
||||||
|
auto fname = m_entity->localFilename();
|
||||||
|
try
|
||||||
|
{
|
||||||
|
m_entity->parse(Json::requireObject(Json::requireDocument(data, fname), fname));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
catch (Exception &e)
|
||||||
|
{
|
||||||
|
qWarning() << "Unable to parse response:" << e.cause();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private: /* data */
|
||||||
|
QByteArray data;
|
||||||
|
Meta::BaseEntity *m_entity;
|
||||||
|
};
|
||||||
|
|
||||||
|
Meta::BaseEntity::~BaseEntity()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
QUrl Meta::BaseEntity::url() const
|
||||||
|
{
|
||||||
|
return QUrl("https://meta.multimc.org").resolved(localFilename());
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Meta::BaseEntity::loadLocalFile()
|
||||||
|
{
|
||||||
|
const QString fname = QDir("meta").absoluteFilePath(localFilename());
|
||||||
|
if (!QFile::exists(fname))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// TODO: check if the file has the expected checksum
|
||||||
|
try
|
||||||
|
{
|
||||||
|
parse(Json::requireObject(Json::requireDocument(fname, fname), fname));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
catch (Exception &e)
|
||||||
|
{
|
||||||
|
qDebug() << QString("Unable to parse file %1: %2").arg(fname, e.cause());
|
||||||
|
// just make sure it's gone and we never consider it again.
|
||||||
|
QFile::remove(fname);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Meta::BaseEntity::load()
|
||||||
|
{
|
||||||
|
// load local file if nothing is loaded yet
|
||||||
|
if(!isLoaded())
|
||||||
|
{
|
||||||
|
if(loadLocalFile())
|
||||||
|
{
|
||||||
|
m_loadStatus = LoadStatus::Local;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// if we need remote update, run the update task
|
||||||
|
if(!shouldStartRemoteUpdate())
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
NetJob *job = new NetJob(QObject::tr("Download of meta file %1").arg(localFilename()));
|
||||||
|
auto url = this->url();
|
||||||
|
auto entry = ENV.metacache()->resolveEntry("meta", localFilename());
|
||||||
|
entry->setStale(true);
|
||||||
|
auto dl = Net::Download::makeCached(url, entry);
|
||||||
|
/*
|
||||||
|
* The validator parses the file and loads it into the object.
|
||||||
|
* If that fails, the file is not written to storage.
|
||||||
|
*/
|
||||||
|
dl->addValidator(new ParsingValidator(this));
|
||||||
|
job->addNetAction(dl);
|
||||||
|
m_updateStatus = UpdateStatus::InProgress;
|
||||||
|
m_updateTask.reset(job);
|
||||||
|
QObject::connect(job, &NetJob::succeeded, [&]()
|
||||||
|
{
|
||||||
|
m_loadStatus = LoadStatus::Remote;
|
||||||
|
m_updateStatus = UpdateStatus::Succeeded;
|
||||||
|
m_updateTask.reset();
|
||||||
|
});
|
||||||
|
QObject::connect(job, &NetJob::failed, [&]()
|
||||||
|
{
|
||||||
|
m_updateStatus = UpdateStatus::Failed;
|
||||||
|
m_updateTask.reset();
|
||||||
|
});
|
||||||
|
m_updateTask->start();
|
||||||
|
}
|
||||||
|
|
||||||
|
shared_qobject_ptr<Task> Meta::BaseEntity::getCurrentTask()
|
||||||
|
{
|
||||||
|
if(m_updateStatus == UpdateStatus::InProgress)
|
||||||
|
{
|
||||||
|
return m_updateTask;
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
#include "BaseEntity.moc"
|
74
api/logic/meta/BaseEntity.h
Normal file
74
api/logic/meta/BaseEntity.h
Normal file
@ -0,0 +1,74 @@
|
|||||||
|
/* Copyright 2015-2017 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 <QJsonObject>
|
||||||
|
#include <QObject>
|
||||||
|
#include "QObjectPtr.h"
|
||||||
|
|
||||||
|
#include "multimc_logic_export.h"
|
||||||
|
|
||||||
|
class Task;
|
||||||
|
namespace Meta
|
||||||
|
{
|
||||||
|
class MULTIMC_LOGIC_EXPORT BaseEntity
|
||||||
|
{
|
||||||
|
public: /* types */
|
||||||
|
using Ptr = std::shared_ptr<BaseEntity>;
|
||||||
|
enum class LoadStatus
|
||||||
|
{
|
||||||
|
NotLoaded,
|
||||||
|
Local,
|
||||||
|
Remote
|
||||||
|
};
|
||||||
|
enum class UpdateStatus
|
||||||
|
{
|
||||||
|
NotDone,
|
||||||
|
InProgress,
|
||||||
|
Failed,
|
||||||
|
Succeeded
|
||||||
|
};
|
||||||
|
|
||||||
|
public:
|
||||||
|
virtual ~BaseEntity();
|
||||||
|
|
||||||
|
virtual void merge(const std::shared_ptr<BaseEntity> &other) = 0;
|
||||||
|
virtual void parse(const QJsonObject &obj) = 0;
|
||||||
|
|
||||||
|
virtual QString localFilename() const = 0;
|
||||||
|
virtual QUrl url() const;
|
||||||
|
|
||||||
|
bool isLoaded() const
|
||||||
|
{
|
||||||
|
return m_loadStatus > LoadStatus::NotLoaded;
|
||||||
|
}
|
||||||
|
bool shouldStartRemoteUpdate() const
|
||||||
|
{
|
||||||
|
return m_updateStatus == UpdateStatus::NotDone;
|
||||||
|
}
|
||||||
|
|
||||||
|
void load();
|
||||||
|
shared_qobject_ptr<Task> getCurrentTask();
|
||||||
|
|
||||||
|
protected: /* methods */
|
||||||
|
bool loadLocalFile();
|
||||||
|
|
||||||
|
private:
|
||||||
|
LoadStatus m_loadStatus = LoadStatus::NotLoaded;
|
||||||
|
UpdateStatus m_updateStatus = UpdateStatus::NotDone;
|
||||||
|
shared_qobject_ptr<Task> m_updateTask;
|
||||||
|
};
|
||||||
|
}
|
@ -13,18 +13,18 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "WonkoIndex.h"
|
#include "Index.h"
|
||||||
|
|
||||||
#include "WonkoVersionList.h"
|
#include "VersionList.h"
|
||||||
#include "tasks/BaseWonkoEntityLocalLoadTask.h"
|
#include "JsonFormat.h"
|
||||||
#include "tasks/BaseWonkoEntityRemoteLoadTask.h"
|
|
||||||
#include "format/WonkoFormat.h"
|
|
||||||
|
|
||||||
WonkoIndex::WonkoIndex(QObject *parent)
|
namespace Meta
|
||||||
|
{
|
||||||
|
Index::Index(QObject *parent)
|
||||||
: QAbstractListModel(parent)
|
: QAbstractListModel(parent)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
WonkoIndex::WonkoIndex(const QVector<WonkoVersionListPtr> &lists, QObject *parent)
|
Index::Index(const QVector<VersionListPtr> &lists, QObject *parent)
|
||||||
: QAbstractListModel(parent), m_lists(lists)
|
: QAbstractListModel(parent), m_lists(lists)
|
||||||
{
|
{
|
||||||
for (int i = 0; i < m_lists.size(); ++i)
|
for (int i = 0; i < m_lists.size(); ++i)
|
||||||
@ -34,14 +34,14 @@ WonkoIndex::WonkoIndex(const QVector<WonkoVersionListPtr> &lists, QObject *paren
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
QVariant WonkoIndex::data(const QModelIndex &index, int role) const
|
QVariant Index::data(const QModelIndex &index, int role) const
|
||||||
{
|
{
|
||||||
if (index.parent().isValid() || index.row() < 0 || index.row() >= m_lists.size())
|
if (index.parent().isValid() || index.row() < 0 || index.row() >= m_lists.size())
|
||||||
{
|
{
|
||||||
return QVariant();
|
return QVariant();
|
||||||
}
|
}
|
||||||
|
|
||||||
WonkoVersionListPtr list = m_lists.at(index.row());
|
VersionListPtr list = m_lists.at(index.row());
|
||||||
switch (role)
|
switch (role)
|
||||||
{
|
{
|
||||||
case Qt::DisplayRole:
|
case Qt::DisplayRole:
|
||||||
@ -56,15 +56,15 @@ QVariant WonkoIndex::data(const QModelIndex &index, int role) const
|
|||||||
}
|
}
|
||||||
return QVariant();
|
return QVariant();
|
||||||
}
|
}
|
||||||
int WonkoIndex::rowCount(const QModelIndex &parent) const
|
int Index::rowCount(const QModelIndex &parent) const
|
||||||
{
|
{
|
||||||
return m_lists.size();
|
return m_lists.size();
|
||||||
}
|
}
|
||||||
int WonkoIndex::columnCount(const QModelIndex &parent) const
|
int Index::columnCount(const QModelIndex &parent) const
|
||||||
{
|
{
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
QVariant WonkoIndex::headerData(int section, Qt::Orientation orientation, int role) const
|
QVariant Index::headerData(int section, Qt::Orientation orientation, int role) const
|
||||||
{
|
{
|
||||||
if (orientation == Qt::Horizontal && role == Qt::DisplayRole && section == 0)
|
if (orientation == Qt::Horizontal && role == Qt::DisplayRole && section == 0)
|
||||||
{
|
{
|
||||||
@ -76,36 +76,36 @@ QVariant WonkoIndex::headerData(int section, Qt::Orientation orientation, int ro
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<Task> WonkoIndex::remoteUpdateTask()
|
bool Index::hasUid(const QString &uid) const
|
||||||
{
|
|
||||||
return std::unique_ptr<WonkoIndexRemoteLoadTask>(new WonkoIndexRemoteLoadTask(this, this));
|
|
||||||
}
|
|
||||||
std::unique_ptr<Task> WonkoIndex::localUpdateTask()
|
|
||||||
{
|
|
||||||
return std::unique_ptr<WonkoIndexLocalLoadTask>(new WonkoIndexLocalLoadTask(this, this));
|
|
||||||
}
|
|
||||||
|
|
||||||
QJsonObject WonkoIndex::serialized() const
|
|
||||||
{
|
|
||||||
return WonkoFormat::serializeIndex(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool WonkoIndex::hasUid(const QString &uid) const
|
|
||||||
{
|
{
|
||||||
return m_uids.contains(uid);
|
return m_uids.contains(uid);
|
||||||
}
|
}
|
||||||
WonkoVersionListPtr WonkoIndex::getList(const QString &uid) const
|
|
||||||
|
VersionListPtr Index::get(const QString &uid)
|
||||||
{
|
{
|
||||||
return m_uids.value(uid, nullptr);
|
VersionListPtr out = m_uids.value(uid, nullptr);
|
||||||
}
|
if(!out)
|
||||||
WonkoVersionListPtr WonkoIndex::getListGuaranteed(const QString &uid) const
|
{
|
||||||
{
|
out = std::make_shared<VersionList>(uid);
|
||||||
return m_uids.value(uid, std::make_shared<WonkoVersionList>(uid));
|
m_uids[uid] = out;
|
||||||
|
}
|
||||||
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
void WonkoIndex::merge(const Ptr &other)
|
VersionPtr Index::get(const QString &uid, const QString &version)
|
||||||
{
|
{
|
||||||
const QVector<WonkoVersionListPtr> lists = std::dynamic_pointer_cast<WonkoIndex>(other)->m_lists;
|
auto list = get(uid);
|
||||||
|
return list->getVersion(version);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Index::parse(const QJsonObject& obj)
|
||||||
|
{
|
||||||
|
parseIndex(obj, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Index::merge(const Ptr &other)
|
||||||
|
{
|
||||||
|
const QVector<VersionListPtr> lists = std::dynamic_pointer_cast<Index>(other)->m_lists;
|
||||||
// initial load, no need to merge
|
// initial load, no need to merge
|
||||||
if (m_lists.isEmpty())
|
if (m_lists.isEmpty())
|
||||||
{
|
{
|
||||||
@ -120,7 +120,7 @@ void WonkoIndex::merge(const Ptr &other)
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
for (const WonkoVersionListPtr &list : lists)
|
for (const VersionListPtr &list : lists)
|
||||||
{
|
{
|
||||||
if (m_uids.contains(list->uid()))
|
if (m_uids.contains(list->uid()))
|
||||||
{
|
{
|
||||||
@ -138,10 +138,11 @@ void WonkoIndex::merge(const Ptr &other)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void WonkoIndex::connectVersionList(const int row, const WonkoVersionListPtr &list)
|
void Index::connectVersionList(const int row, const VersionListPtr &list)
|
||||||
{
|
{
|
||||||
connect(list.get(), &WonkoVersionList::nameChanged, this, [this, row]()
|
connect(list.get(), &VersionList::nameChanged, this, [this, row]()
|
||||||
{
|
{
|
||||||
emit dataChanged(index(row), index(row), QVector<int>() << Qt::DisplayRole);
|
emit dataChanged(index(row), index(row), QVector<int>() << Qt::DisplayRole);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
}
|
@ -18,19 +18,23 @@
|
|||||||
#include <QAbstractListModel>
|
#include <QAbstractListModel>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
#include "BaseWonkoEntity.h"
|
#include "BaseEntity.h"
|
||||||
|
|
||||||
#include "multimc_logic_export.h"
|
#include "multimc_logic_export.h"
|
||||||
|
|
||||||
class Task;
|
class Task;
|
||||||
using WonkoVersionListPtr = std::shared_ptr<class WonkoVersionList>;
|
|
||||||
|
|
||||||
class MULTIMC_LOGIC_EXPORT WonkoIndex : public QAbstractListModel, public BaseWonkoEntity
|
namespace Meta
|
||||||
|
{
|
||||||
|
using VersionListPtr = std::shared_ptr<class VersionList>;
|
||||||
|
using VersionPtr = std::shared_ptr<class Version>;
|
||||||
|
|
||||||
|
class MULTIMC_LOGIC_EXPORT Index : public QAbstractListModel, public BaseEntity
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
explicit WonkoIndex(QObject *parent = nullptr);
|
explicit Index(QObject *parent = nullptr);
|
||||||
explicit WonkoIndex(const QVector<WonkoVersionListPtr> &lists, QObject *parent = nullptr);
|
explicit Index(const QVector<VersionListPtr> &lists, QObject *parent = nullptr);
|
||||||
|
|
||||||
enum
|
enum
|
||||||
{
|
{
|
||||||
@ -44,25 +48,24 @@ public:
|
|||||||
int columnCount(const QModelIndex &parent) const override;
|
int columnCount(const QModelIndex &parent) const override;
|
||||||
QVariant headerData(int section, Qt::Orientation orientation, int role) const override;
|
QVariant headerData(int section, Qt::Orientation orientation, int role) const override;
|
||||||
|
|
||||||
std::unique_ptr<Task> remoteUpdateTask() override;
|
|
||||||
std::unique_ptr<Task> localUpdateTask() override;
|
|
||||||
|
|
||||||
QString localFilename() const override { return "index.json"; }
|
QString localFilename() const override { return "index.json"; }
|
||||||
QJsonObject serialized() const override;
|
|
||||||
|
|
||||||
// queries
|
// queries
|
||||||
|
VersionListPtr get(const QString &uid);
|
||||||
|
VersionPtr get(const QString &uid, const QString &version);
|
||||||
bool hasUid(const QString &uid) const;
|
bool hasUid(const QString &uid) const;
|
||||||
WonkoVersionListPtr getList(const QString &uid) const;
|
|
||||||
WonkoVersionListPtr getListGuaranteed(const QString &uid) const;
|
|
||||||
|
|
||||||
QVector<WonkoVersionListPtr> lists() const { return m_lists; }
|
QVector<VersionListPtr> lists() const { return m_lists; }
|
||||||
|
|
||||||
public: // for usage by parsers only
|
public: // for usage by parsers only
|
||||||
void merge(const BaseWonkoEntity::Ptr &other);
|
void merge(const BaseEntity::Ptr &other) override;
|
||||||
|
void parse(const QJsonObject &obj) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QVector<WonkoVersionListPtr> m_lists;
|
QVector<VersionListPtr> m_lists;
|
||||||
QHash<QString, WonkoVersionListPtr> m_uids;
|
QHash<QString, VersionListPtr> m_uids;
|
||||||
|
|
||||||
void connectVersionList(const int row, const WonkoVersionListPtr &list);
|
void connectVersionList(const int row, const VersionListPtr &list);
|
||||||
};
|
};
|
||||||
|
}
|
||||||
|
|
44
api/logic/meta/Index_test.cpp
Normal file
44
api/logic/meta/Index_test.cpp
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
#include <QTest>
|
||||||
|
#include "TestUtil.h"
|
||||||
|
|
||||||
|
#include "meta/Index.h"
|
||||||
|
#include "meta/VersionList.h"
|
||||||
|
#include "Env.h"
|
||||||
|
|
||||||
|
class IndexTest : public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
private
|
||||||
|
slots:
|
||||||
|
void test_isProvidedByEnv()
|
||||||
|
{
|
||||||
|
QVERIFY(ENV.metadataIndex());
|
||||||
|
QCOMPARE(ENV.metadataIndex(), ENV.metadataIndex());
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_hasUid_and_getList()
|
||||||
|
{
|
||||||
|
Meta::Index windex({std::make_shared<Meta::VersionList>("list1"), std::make_shared<Meta::VersionList>("list2"), std::make_shared<Meta::VersionList>("list3")});
|
||||||
|
QVERIFY(windex.hasUid("list1"));
|
||||||
|
QVERIFY(!windex.hasUid("asdf"));
|
||||||
|
QVERIFY(windex.get("list2") != nullptr);
|
||||||
|
QCOMPARE(windex.get("list2")->uid(), QString("list2"));
|
||||||
|
QVERIFY(windex.get("adsf") != nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_merge()
|
||||||
|
{
|
||||||
|
Meta::Index windex({std::make_shared<Meta::VersionList>("list1"), std::make_shared<Meta::VersionList>("list2"), std::make_shared<Meta::VersionList>("list3")});
|
||||||
|
QCOMPARE(windex.lists().size(), 3);
|
||||||
|
windex.merge(std::shared_ptr<Meta::Index>(new Meta::Index({std::make_shared<Meta::VersionList>("list1"), std::make_shared<Meta::VersionList>("list2"), std::make_shared<Meta::VersionList>("list3")})));
|
||||||
|
QCOMPARE(windex.lists().size(), 3);
|
||||||
|
windex.merge(std::shared_ptr<Meta::Index>(new Meta::Index({std::make_shared<Meta::VersionList>("list4"), std::make_shared<Meta::VersionList>("list2"), std::make_shared<Meta::VersionList>("list5")})));
|
||||||
|
QCOMPARE(windex.lists().size(), 5);
|
||||||
|
windex.merge(std::shared_ptr<Meta::Index>(new Meta::Index({std::make_shared<Meta::VersionList>("list6")})));
|
||||||
|
QCOMPARE(windex.lists().size(), 6);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
QTEST_GUILESS_MAIN(IndexTest)
|
||||||
|
|
||||||
|
#include "Index_test.moc"
|
150
api/logic/meta/JsonFormat.cpp
Normal file
150
api/logic/meta/JsonFormat.cpp
Normal file
@ -0,0 +1,150 @@
|
|||||||
|
/* Copyright 2015-2017 MultiMC Contributors
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "JsonFormat.h"
|
||||||
|
|
||||||
|
// FIXME: remove this from here... somehow
|
||||||
|
#include "minecraft/onesix/OneSixVersionFormat.h"
|
||||||
|
#include "Json.h"
|
||||||
|
|
||||||
|
#include "Index.h"
|
||||||
|
#include "Version.h"
|
||||||
|
#include "VersionList.h"
|
||||||
|
|
||||||
|
using namespace Json;
|
||||||
|
|
||||||
|
namespace Meta
|
||||||
|
{
|
||||||
|
|
||||||
|
static const int currentFormatVersion = 0;
|
||||||
|
|
||||||
|
// Index
|
||||||
|
static BaseEntity::Ptr parseIndexInternal(const QJsonObject &obj)
|
||||||
|
{
|
||||||
|
const QVector<QJsonObject> objects = requireIsArrayOf<QJsonObject>(obj, "packages");
|
||||||
|
QVector<VersionListPtr> lists;
|
||||||
|
lists.reserve(objects.size());
|
||||||
|
std::transform(objects.begin(), objects.end(), std::back_inserter(lists), [](const QJsonObject &obj)
|
||||||
|
{
|
||||||
|
VersionListPtr list = std::make_shared<VersionList>(requireString(obj, "uid"));
|
||||||
|
list->setName(ensureString(obj, "name", QString()));
|
||||||
|
return list;
|
||||||
|
});
|
||||||
|
return std::make_shared<Index>(lists);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Version
|
||||||
|
static VersionPtr parseCommonVersion(const QString &uid, const QJsonObject &obj)
|
||||||
|
{
|
||||||
|
VersionPtr version = std::make_shared<Version>(uid, requireString(obj, "version"));
|
||||||
|
version->setTime(QDateTime::fromString(requireString(obj, "releaseTime"), Qt::ISODate).toMSecsSinceEpoch() / 1000);
|
||||||
|
version->setType(ensureString(obj, "type", QString()));
|
||||||
|
version->setParentUid(ensureString(obj, "parentUid", QString()));
|
||||||
|
version->setRecommended(ensureBoolean(obj, QString("recommended"), false));
|
||||||
|
if(obj.contains("requires"))
|
||||||
|
{
|
||||||
|
QHash<QString, QString> requires;
|
||||||
|
auto reqobj = requireObject(obj, "requires");
|
||||||
|
auto iter = reqobj.begin();
|
||||||
|
while(iter != reqobj.end())
|
||||||
|
{
|
||||||
|
requires[iter.key()] = requireString(iter.value());
|
||||||
|
iter++;
|
||||||
|
}
|
||||||
|
version->setRequires(requires);
|
||||||
|
}
|
||||||
|
return version;
|
||||||
|
}
|
||||||
|
|
||||||
|
static BaseEntity::Ptr parseVersionInternal(const QJsonObject &obj)
|
||||||
|
{
|
||||||
|
VersionPtr version = parseCommonVersion(requireString(obj, "uid"), obj);
|
||||||
|
|
||||||
|
version->setData(OneSixVersionFormat::versionFileFromJson(QJsonDocument(obj),
|
||||||
|
QString("%1/%2.json").arg(version->uid(), version->version()),
|
||||||
|
obj.contains("order")));
|
||||||
|
return version;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Version list / package
|
||||||
|
static BaseEntity::Ptr parseVersionListInternal(const QJsonObject &obj)
|
||||||
|
{
|
||||||
|
const QString uid = requireString(obj, "uid");
|
||||||
|
|
||||||
|
const QVector<QJsonObject> versionsRaw = requireIsArrayOf<QJsonObject>(obj, "versions");
|
||||||
|
QVector<VersionPtr> versions;
|
||||||
|
versions.reserve(versionsRaw.size());
|
||||||
|
std::transform(versionsRaw.begin(), versionsRaw.end(), std::back_inserter(versions), [uid](const QJsonObject &vObj)
|
||||||
|
{
|
||||||
|
auto version = parseCommonVersion(uid, vObj);
|
||||||
|
version->setProvidesRecommendations();
|
||||||
|
return version;
|
||||||
|
});
|
||||||
|
|
||||||
|
VersionListPtr list = std::make_shared<VersionList>(uid);
|
||||||
|
list->setName(ensureString(obj, "name", QString()));
|
||||||
|
list->setParentUid(ensureString(obj, "parentUid", QString()));
|
||||||
|
list->setVersions(versions);
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int formatVersion(const QJsonObject &obj)
|
||||||
|
{
|
||||||
|
if (!obj.contains("formatVersion")) {
|
||||||
|
throw ParseException(QObject::tr("Missing required field: 'formatVersion'"));
|
||||||
|
}
|
||||||
|
if (!obj.value("formatVersion").isDouble()) {
|
||||||
|
throw ParseException(QObject::tr("Required field has invalid type: 'formatVersion'"));
|
||||||
|
}
|
||||||
|
return obj.value("formatVersion").toInt();
|
||||||
|
}
|
||||||
|
|
||||||
|
void parseIndex(const QJsonObject &obj, Index *ptr)
|
||||||
|
{
|
||||||
|
const int version = formatVersion(obj);
|
||||||
|
switch (version) {
|
||||||
|
case 0:
|
||||||
|
ptr->merge(parseIndexInternal(obj));
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw ParseException(QObject::tr("Unknown formatVersion: %1").arg(version));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void parseVersionList(const QJsonObject &obj, VersionList *ptr)
|
||||||
|
{
|
||||||
|
const int version = formatVersion(obj);
|
||||||
|
switch (version) {
|
||||||
|
case 0:
|
||||||
|
ptr->merge(parseVersionListInternal(obj));
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw ParseException(QObject::tr("Unknown formatVersion: %1").arg(version));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void parseVersion(const QJsonObject &obj, Version *ptr)
|
||||||
|
{
|
||||||
|
const int version = formatVersion(obj);
|
||||||
|
switch (version) {
|
||||||
|
case 0:
|
||||||
|
ptr->merge(parseVersionInternal(obj));
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw ParseException(QObject::tr("Unknown formatVersion: %1").arg(version));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -15,17 +15,26 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "multimc_logic_export.h"
|
#include <QJsonObject>
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
class QUrl;
|
#include "Exception.h"
|
||||||
class QString;
|
#include "meta/BaseEntity.h"
|
||||||
class QDir;
|
|
||||||
|
|
||||||
namespace Wonko
|
namespace Meta
|
||||||
{
|
{
|
||||||
MULTIMC_LOGIC_EXPORT QUrl rootUrl();
|
class Index;
|
||||||
MULTIMC_LOGIC_EXPORT QUrl indexUrl();
|
class Version;
|
||||||
MULTIMC_LOGIC_EXPORT QUrl versionListUrl(const QString &uid);
|
class VersionList;
|
||||||
MULTIMC_LOGIC_EXPORT QUrl versionUrl(const QString &uid, const QString &version);
|
|
||||||
MULTIMC_LOGIC_EXPORT QDir localWonkoDir();
|
class ParseException : public Exception
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
using Exception::Exception;
|
||||||
|
};
|
||||||
|
|
||||||
|
void parseIndex(const QJsonObject &obj, Index *ptr);
|
||||||
|
void parseVersion(const QJsonObject &obj, Version *ptr);
|
||||||
|
void parseVersionList(const QJsonObject &obj, VersionList *ptr);
|
||||||
|
|
||||||
}
|
}
|
125
api/logic/meta/Version.cpp
Normal file
125
api/logic/meta/Version.cpp
Normal file
@ -0,0 +1,125 @@
|
|||||||
|
/* Copyright 2015-2017 MultiMC Contributors
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "Version.h"
|
||||||
|
|
||||||
|
#include <QDateTime>
|
||||||
|
|
||||||
|
#include "JsonFormat.h"
|
||||||
|
#include "minecraft/MinecraftProfile.h"
|
||||||
|
|
||||||
|
Meta::Version::Version(const QString &uid, const QString &version)
|
||||||
|
: BaseVersion(), m_uid(uid), m_version(version)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
QString Meta::Version::descriptor()
|
||||||
|
{
|
||||||
|
return m_version;
|
||||||
|
}
|
||||||
|
QString Meta::Version::name()
|
||||||
|
{
|
||||||
|
if(m_data)
|
||||||
|
return m_data->name;
|
||||||
|
return m_uid;
|
||||||
|
}
|
||||||
|
QString Meta::Version::typeString() const
|
||||||
|
{
|
||||||
|
return m_type;
|
||||||
|
}
|
||||||
|
|
||||||
|
QDateTime Meta::Version::time() const
|
||||||
|
{
|
||||||
|
return QDateTime::fromMSecsSinceEpoch(m_time * 1000, Qt::UTC);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Meta::Version::parse(const QJsonObject& obj)
|
||||||
|
{
|
||||||
|
parseVersion(obj, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Meta::Version::merge(const std::shared_ptr<BaseEntity> &other)
|
||||||
|
{
|
||||||
|
VersionPtr version = std::dynamic_pointer_cast<Version>(other);
|
||||||
|
if(version->m_providesRecommendations)
|
||||||
|
{
|
||||||
|
if(m_recommended != version->m_recommended)
|
||||||
|
{
|
||||||
|
setRecommended(version->m_recommended);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (m_type != version->m_type)
|
||||||
|
{
|
||||||
|
setType(version->m_type);
|
||||||
|
}
|
||||||
|
if (m_time != version->m_time)
|
||||||
|
{
|
||||||
|
setTime(version->m_time);
|
||||||
|
}
|
||||||
|
if (m_requires != version->m_requires)
|
||||||
|
{
|
||||||
|
setRequires(version->m_requires);
|
||||||
|
}
|
||||||
|
if (m_parentUid != version->m_parentUid)
|
||||||
|
{
|
||||||
|
setParentUid(version->m_parentUid);
|
||||||
|
}
|
||||||
|
|
||||||
|
setData(version->m_data);
|
||||||
|
}
|
||||||
|
|
||||||
|
QString Meta::Version::localFilename() const
|
||||||
|
{
|
||||||
|
return m_uid + '/' + m_version + ".json";
|
||||||
|
}
|
||||||
|
|
||||||
|
void Meta::Version::setParentUid(const QString& parentUid)
|
||||||
|
{
|
||||||
|
m_parentUid = parentUid;
|
||||||
|
emit requiresChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Meta::Version::setType(const QString &type)
|
||||||
|
{
|
||||||
|
m_type = type;
|
||||||
|
emit typeChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Meta::Version::setTime(const qint64 time)
|
||||||
|
{
|
||||||
|
m_time = time;
|
||||||
|
emit timeChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Meta::Version::setRequires(const QHash<QString, QString> &requires)
|
||||||
|
{
|
||||||
|
m_requires = requires;
|
||||||
|
emit requiresChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Meta::Version::setData(const VersionFilePtr &data)
|
||||||
|
{
|
||||||
|
m_data = data;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Meta::Version::setProvidesRecommendations()
|
||||||
|
{
|
||||||
|
m_providesRecommendations = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Meta::Version::setRecommended(bool recommended)
|
||||||
|
{
|
||||||
|
m_recommended = recommended;
|
||||||
|
}
|
@ -16,54 +16,79 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "BaseVersion.h"
|
#include "BaseVersion.h"
|
||||||
#include "BaseWonkoEntity.h"
|
|
||||||
|
|
||||||
#include <QVector>
|
|
||||||
#include <QStringList>
|
|
||||||
#include <QJsonObject>
|
#include <QJsonObject>
|
||||||
|
#include <QStringList>
|
||||||
|
#include <QVector>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
#include "minecraft/VersionFile.h"
|
#include "minecraft/VersionFile.h"
|
||||||
#include "WonkoReference.h"
|
|
||||||
|
#include "BaseEntity.h"
|
||||||
|
|
||||||
#include "multimc_logic_export.h"
|
#include "multimc_logic_export.h"
|
||||||
|
|
||||||
using WonkoVersionPtr = std::shared_ptr<class WonkoVersion>;
|
namespace Meta
|
||||||
|
{
|
||||||
|
using VersionPtr = std::shared_ptr<class Version>;
|
||||||
|
|
||||||
class MULTIMC_LOGIC_EXPORT WonkoVersion : public QObject, public BaseVersion, public BaseWonkoEntity
|
class MULTIMC_LOGIC_EXPORT Version : public QObject, public BaseVersion, public BaseEntity
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
Q_PROPERTY(QString uid READ uid CONSTANT)
|
|
||||||
Q_PROPERTY(QString version READ version CONSTANT)
|
public: /* con/des */
|
||||||
Q_PROPERTY(QString type READ type NOTIFY typeChanged)
|
explicit Version(const QString &uid, const QString &version);
|
||||||
Q_PROPERTY(QDateTime time READ time NOTIFY timeChanged)
|
|
||||||
Q_PROPERTY(QVector<WonkoReference> requires READ requires NOTIFY requiresChanged)
|
|
||||||
public:
|
|
||||||
explicit WonkoVersion(const QString &uid, const QString &version);
|
|
||||||
|
|
||||||
QString descriptor() override;
|
QString descriptor() override;
|
||||||
QString name() override;
|
QString name() override;
|
||||||
QString typeString() const override;
|
QString typeString() const override;
|
||||||
|
|
||||||
QString uid() const { return m_uid; }
|
QString uid() const
|
||||||
QString version() const { return m_version; }
|
{
|
||||||
QString type() const { return m_type; }
|
return m_uid;
|
||||||
|
}
|
||||||
|
QString parentUid() const
|
||||||
|
{
|
||||||
|
return m_parentUid;
|
||||||
|
}
|
||||||
|
QString version() const
|
||||||
|
{
|
||||||
|
return m_version;
|
||||||
|
}
|
||||||
|
QString type() const
|
||||||
|
{
|
||||||
|
return m_type;
|
||||||
|
}
|
||||||
QDateTime time() const;
|
QDateTime time() const;
|
||||||
qint64 rawTime() const { return m_time; }
|
qint64 rawTime() const
|
||||||
QVector<WonkoReference> requires() const { return m_requires; }
|
{
|
||||||
VersionFilePtr data() const { return m_data; }
|
return m_time;
|
||||||
|
}
|
||||||
|
const QHash<QString, QString> &requires() const
|
||||||
|
{
|
||||||
|
return m_requires;
|
||||||
|
}
|
||||||
|
VersionFilePtr data() const
|
||||||
|
{
|
||||||
|
return m_data;
|
||||||
|
}
|
||||||
|
bool isRecommended() const
|
||||||
|
{
|
||||||
|
return m_recommended;
|
||||||
|
}
|
||||||
|
|
||||||
std::unique_ptr<Task> remoteUpdateTask() override;
|
void merge(const std::shared_ptr<BaseEntity> &other) override;
|
||||||
std::unique_ptr<Task> localUpdateTask() override;
|
void parse(const QJsonObject &obj) override;
|
||||||
void merge(const std::shared_ptr<BaseWonkoEntity> &other) override;
|
|
||||||
|
|
||||||
QString localFilename() const override;
|
QString localFilename() const override;
|
||||||
QJsonObject serialized() const override;
|
|
||||||
|
|
||||||
public: // for usage by format parsers only
|
public: // for usage by format parsers only
|
||||||
|
void setParentUid(const QString &parentUid);
|
||||||
void setType(const QString &type);
|
void setType(const QString &type);
|
||||||
void setTime(const qint64 time);
|
void setTime(const qint64 time);
|
||||||
void setRequires(const QVector<WonkoReference> &requires);
|
void setRequires(const QHash<QString, QString> &requires);
|
||||||
|
void setRecommended(bool recommended);
|
||||||
|
void setProvidesRecommendations();
|
||||||
void setData(const VersionFilePtr &data);
|
void setData(const VersionFilePtr &data);
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
@ -72,12 +97,17 @@ signals:
|
|||||||
void requiresChanged();
|
void requiresChanged();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
bool m_providesRecommendations = false;
|
||||||
|
bool m_recommended = false;
|
||||||
|
QString m_name;
|
||||||
QString m_uid;
|
QString m_uid;
|
||||||
|
QString m_parentUid;
|
||||||
QString m_version;
|
QString m_version;
|
||||||
QString m_type;
|
QString m_type;
|
||||||
qint64 m_time;
|
qint64 m_time;
|
||||||
QVector<WonkoReference> m_requires;
|
QHash<QString, QString> m_requires;
|
||||||
VersionFilePtr m_data;
|
VersionFilePtr m_data;
|
||||||
};
|
};
|
||||||
|
}
|
||||||
|
|
||||||
Q_DECLARE_METATYPE(WonkoVersionPtr)
|
Q_DECLARE_METATYPE(Meta::VersionPtr)
|
235
api/logic/meta/VersionList.cpp
Normal file
235
api/logic/meta/VersionList.cpp
Normal file
@ -0,0 +1,235 @@
|
|||||||
|
/* Copyright 2015-2017 MultiMC Contributors
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "VersionList.h"
|
||||||
|
|
||||||
|
#include <QDateTime>
|
||||||
|
|
||||||
|
#include "Version.h"
|
||||||
|
#include "JsonFormat.h"
|
||||||
|
|
||||||
|
namespace Meta
|
||||||
|
{
|
||||||
|
VersionList::VersionList(const QString &uid, QObject *parent)
|
||||||
|
: BaseVersionList(parent), m_uid(uid)
|
||||||
|
{
|
||||||
|
setObjectName("Version list: " + uid);
|
||||||
|
}
|
||||||
|
|
||||||
|
shared_qobject_ptr<Task> VersionList::getLoadTask()
|
||||||
|
{
|
||||||
|
load();
|
||||||
|
return getCurrentTask();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool VersionList::isLoaded()
|
||||||
|
{
|
||||||
|
return BaseEntity::isLoaded();
|
||||||
|
}
|
||||||
|
|
||||||
|
const BaseVersionPtr VersionList::at(int i) const
|
||||||
|
{
|
||||||
|
return m_versions.at(i);
|
||||||
|
}
|
||||||
|
int VersionList::count() const
|
||||||
|
{
|
||||||
|
return m_versions.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
void VersionList::sortVersions()
|
||||||
|
{
|
||||||
|
beginResetModel();
|
||||||
|
std::sort(m_versions.begin(), m_versions.end(), [](const VersionPtr &a, const VersionPtr &b)
|
||||||
|
{
|
||||||
|
return *a.get() < *b.get();
|
||||||
|
});
|
||||||
|
endResetModel();
|
||||||
|
}
|
||||||
|
|
||||||
|
QVariant VersionList::data(const QModelIndex &index, int role) const
|
||||||
|
{
|
||||||
|
if (!index.isValid() || index.row() < 0 || index.row() >= m_versions.size() || index.parent().isValid())
|
||||||
|
{
|
||||||
|
return QVariant();
|
||||||
|
}
|
||||||
|
|
||||||
|
VersionPtr version = m_versions.at(index.row());
|
||||||
|
|
||||||
|
switch (role)
|
||||||
|
{
|
||||||
|
case VersionPointerRole: return QVariant::fromValue(std::dynamic_pointer_cast<BaseVersion>(version));
|
||||||
|
case VersionRole:
|
||||||
|
case VersionIdRole:
|
||||||
|
return version->version();
|
||||||
|
case ParentVersionRole:
|
||||||
|
{
|
||||||
|
auto parentUid = this->parentUid();
|
||||||
|
if(parentUid.isEmpty())
|
||||||
|
{
|
||||||
|
return QVariant();
|
||||||
|
}
|
||||||
|
auto & reqs = version->requires();
|
||||||
|
auto iter = reqs.find(parentUid);
|
||||||
|
if (iter != reqs.end())
|
||||||
|
{
|
||||||
|
return iter.value();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case TypeRole: return version->type();
|
||||||
|
|
||||||
|
case UidRole: return version->uid();
|
||||||
|
case TimeRole: return version->time();
|
||||||
|
case RequiresRole: return QVariant::fromValue(version->requires());
|
||||||
|
case SortRole: return version->rawTime();
|
||||||
|
case VersionPtrRole: return QVariant::fromValue(version);
|
||||||
|
case RecommendedRole: return version->isRecommended();
|
||||||
|
// FIXME: this should be determined in whatever view/proxy is used...
|
||||||
|
// case LatestRole: return version == getLatestStable();
|
||||||
|
default: return QVariant();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
BaseVersionList::RoleList VersionList::providesRoles() const
|
||||||
|
{
|
||||||
|
return {VersionPointerRole, VersionRole, VersionIdRole, ParentVersionRole,
|
||||||
|
TypeRole, UidRole, TimeRole, RequiresRole, SortRole,
|
||||||
|
RecommendedRole, LatestRole, VersionPtrRole};
|
||||||
|
}
|
||||||
|
|
||||||
|
QHash<int, QByteArray> VersionList::roleNames() const
|
||||||
|
{
|
||||||
|
QHash<int, QByteArray> roles = BaseVersionList::roleNames();
|
||||||
|
roles.insert(UidRole, "uid");
|
||||||
|
roles.insert(TimeRole, "time");
|
||||||
|
roles.insert(SortRole, "sort");
|
||||||
|
roles.insert(RequiresRole, "requires");
|
||||||
|
return roles;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString VersionList::localFilename() const
|
||||||
|
{
|
||||||
|
return m_uid + "/index.json";
|
||||||
|
}
|
||||||
|
|
||||||
|
QString VersionList::humanReadable() const
|
||||||
|
{
|
||||||
|
return m_name.isEmpty() ? m_uid : m_name;
|
||||||
|
}
|
||||||
|
|
||||||
|
VersionPtr VersionList::getVersion(const QString &version)
|
||||||
|
{
|
||||||
|
VersionPtr out = m_lookup.value(version, nullptr);
|
||||||
|
if(!out)
|
||||||
|
{
|
||||||
|
out = std::make_shared<Version>(m_uid, version);
|
||||||
|
m_lookup[version] = out;
|
||||||
|
}
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
void VersionList::setName(const QString &name)
|
||||||
|
{
|
||||||
|
m_name = name;
|
||||||
|
emit nameChanged(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
void VersionList::setVersions(const QVector<VersionPtr> &versions)
|
||||||
|
{
|
||||||
|
beginResetModel();
|
||||||
|
m_versions = versions;
|
||||||
|
std::sort(m_versions.begin(), m_versions.end(), [](const VersionPtr &a, const VersionPtr &b)
|
||||||
|
{
|
||||||
|
return a->rawTime() > b->rawTime();
|
||||||
|
});
|
||||||
|
for (int i = 0; i < m_versions.size(); ++i)
|
||||||
|
{
|
||||||
|
m_lookup.insert(m_versions.at(i)->version(), m_versions.at(i));
|
||||||
|
setupAddedVersion(i, m_versions.at(i));
|
||||||
|
}
|
||||||
|
|
||||||
|
auto recommendedIt = std::find_if(m_versions.constBegin(), m_versions.constEnd(), [](const VersionPtr &ptr) { return ptr->type() == "release"; });
|
||||||
|
m_recommended = recommendedIt == m_versions.constEnd() ? nullptr : *recommendedIt;
|
||||||
|
endResetModel();
|
||||||
|
}
|
||||||
|
|
||||||
|
void VersionList::parse(const QJsonObject& obj)
|
||||||
|
{
|
||||||
|
parseVersionList(obj, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
void VersionList::merge(const BaseEntity::Ptr &other)
|
||||||
|
{
|
||||||
|
const VersionListPtr list = std::dynamic_pointer_cast<VersionList>(other);
|
||||||
|
if (m_name != list->m_name)
|
||||||
|
{
|
||||||
|
setName(list->m_name);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(m_parentUid != list->m_parentUid)
|
||||||
|
{
|
||||||
|
setParentUid(list->m_parentUid);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_versions.isEmpty())
|
||||||
|
{
|
||||||
|
setVersions(list->m_versions);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
for (const VersionPtr &version : list->m_versions)
|
||||||
|
{
|
||||||
|
if (m_lookup.contains(version->version()))
|
||||||
|
{
|
||||||
|
m_lookup.value(version->version())->merge(version);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
beginInsertRows(QModelIndex(), m_versions.size(), m_versions.size());
|
||||||
|
setupAddedVersion(m_versions.size(), version);
|
||||||
|
m_versions.append(version);
|
||||||
|
m_lookup.insert(version->uid(), version);
|
||||||
|
endInsertRows();
|
||||||
|
|
||||||
|
if (!m_recommended || (version->type() == "release" && version->rawTime() > m_recommended->rawTime()))
|
||||||
|
{
|
||||||
|
m_recommended = version;
|
||||||
|
emit dataChanged(index(0), index(m_versions.size() - 1), QVector<int>() << RecommendedRole);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void VersionList::setupAddedVersion(const int row, const VersionPtr &version)
|
||||||
|
{
|
||||||
|
connect(version.get(), &Version::requiresChanged, this, [this, row]() { emit dataChanged(index(row), index(row), QVector<int>() << RequiresRole); });
|
||||||
|
connect(version.get(), &Version::timeChanged, this, [this, row]() { emit dataChanged(index(row), index(row), QVector<int>() << TimeRole << SortRole); });
|
||||||
|
connect(version.get(), &Version::typeChanged, this, [this, row]() { emit dataChanged(index(row), index(row), QVector<int>() << TypeRole); });
|
||||||
|
}
|
||||||
|
|
||||||
|
BaseVersionPtr VersionList::getRecommended() const
|
||||||
|
{
|
||||||
|
return m_recommended;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void Meta::VersionList::setParentUid(const QString& parentUid)
|
||||||
|
{
|
||||||
|
m_parentUid = parentUid;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#include "VersionList.moc"
|
@ -15,78 +15,92 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include "BaseEntity.h"
|
||||||
#include "BaseVersionList.h"
|
#include "BaseVersionList.h"
|
||||||
#include "BaseWonkoEntity.h"
|
#include <QJsonObject>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
using WonkoVersionPtr = std::shared_ptr<class WonkoVersion>;
|
namespace Meta
|
||||||
using WonkoVersionListPtr = std::shared_ptr<class WonkoVersionList>;
|
{
|
||||||
|
using VersionPtr = std::shared_ptr<class Version>;
|
||||||
|
using VersionListPtr = std::shared_ptr<class VersionList>;
|
||||||
|
|
||||||
class MULTIMC_LOGIC_EXPORT WonkoVersionList : public BaseVersionList, public BaseWonkoEntity
|
class MULTIMC_LOGIC_EXPORT VersionList : public BaseVersionList, public BaseEntity
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
Q_PROPERTY(QString uid READ uid CONSTANT)
|
Q_PROPERTY(QString uid READ uid CONSTANT)
|
||||||
Q_PROPERTY(QString name READ name NOTIFY nameChanged)
|
Q_PROPERTY(QString name READ name NOTIFY nameChanged)
|
||||||
public:
|
public:
|
||||||
explicit WonkoVersionList(const QString &uid, QObject *parent = nullptr);
|
explicit VersionList(const QString &uid, QObject *parent = nullptr);
|
||||||
|
|
||||||
enum Roles
|
enum Roles
|
||||||
{
|
{
|
||||||
UidRole = Qt::UserRole + 100,
|
UidRole = Qt::UserRole + 100,
|
||||||
TimeRole,
|
TimeRole,
|
||||||
RequiresRole,
|
RequiresRole,
|
||||||
WonkoVersionPtrRole
|
VersionPtrRole
|
||||||
};
|
};
|
||||||
|
|
||||||
Task *getLoadTask() override;
|
shared_qobject_ptr<Task> getLoadTask() override;
|
||||||
bool isLoaded() override;
|
bool isLoaded() override;
|
||||||
const BaseVersionPtr at(int i) const override;
|
const BaseVersionPtr at(int i) const override;
|
||||||
int count() const override;
|
int count() const override;
|
||||||
void sortVersions() override;
|
void sortVersions() override;
|
||||||
|
|
||||||
BaseVersionPtr getLatestStable() const override;
|
|
||||||
BaseVersionPtr getRecommended() const override;
|
BaseVersionPtr getRecommended() const override;
|
||||||
|
|
||||||
QVariant data(const QModelIndex &index, int role) const override;
|
QVariant data(const QModelIndex &index, int role) const override;
|
||||||
RoleList providesRoles() const override;
|
RoleList providesRoles() const override;
|
||||||
QHash<int, QByteArray> roleNames() const override;
|
QHash<int, QByteArray> roleNames() const override;
|
||||||
|
|
||||||
std::unique_ptr<Task> remoteUpdateTask() override;
|
|
||||||
std::unique_ptr<Task> localUpdateTask() override;
|
|
||||||
|
|
||||||
QString localFilename() const override;
|
QString localFilename() const override;
|
||||||
QJsonObject serialized() const override;
|
|
||||||
|
|
||||||
QString uid() const { return m_uid; }
|
QString parentUid() const
|
||||||
QString name() const { return m_name; }
|
{
|
||||||
|
return m_parentUid;
|
||||||
|
}
|
||||||
|
QString uid() const
|
||||||
|
{
|
||||||
|
return m_uid;
|
||||||
|
}
|
||||||
|
QString name() const
|
||||||
|
{
|
||||||
|
return m_name;
|
||||||
|
}
|
||||||
QString humanReadable() const;
|
QString humanReadable() const;
|
||||||
|
|
||||||
bool hasVersion(const QString &version) const;
|
VersionPtr getVersion(const QString &version);
|
||||||
WonkoVersionPtr getVersion(const QString &version) const;
|
|
||||||
|
|
||||||
QVector<WonkoVersionPtr> versions() const { return m_versions; }
|
QVector<VersionPtr> versions() const
|
||||||
|
{
|
||||||
|
return m_versions;
|
||||||
|
}
|
||||||
|
|
||||||
public: // for usage only by parsers
|
public: // for usage only by parsers
|
||||||
void setName(const QString &name);
|
void setName(const QString &name);
|
||||||
void setVersions(const QVector<WonkoVersionPtr> &versions);
|
void setParentUid(const QString &parentUid);
|
||||||
void merge(const BaseWonkoEntity::Ptr &other);
|
void setVersions(const QVector<VersionPtr> &versions);
|
||||||
|
void merge(const BaseEntity::Ptr &other) override;
|
||||||
|
void parse(const QJsonObject &obj) override;
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void nameChanged(const QString &name);
|
void nameChanged(const QString &name);
|
||||||
|
|
||||||
protected slots:
|
protected slots:
|
||||||
void updateListData(QList<BaseVersionPtr> versions) override {}
|
void updateListData(QList<BaseVersionPtr>) override
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QVector<WonkoVersionPtr> m_versions;
|
QVector<VersionPtr> m_versions;
|
||||||
QHash<QString, WonkoVersionPtr> m_lookup;
|
QHash<QString, VersionPtr> m_lookup;
|
||||||
QString m_uid;
|
QString m_uid;
|
||||||
|
QString m_parentUid;
|
||||||
QString m_name;
|
QString m_name;
|
||||||
|
|
||||||
WonkoVersionPtr m_recommended;
|
VersionPtr m_recommended;
|
||||||
WonkoVersionPtr m_latest;
|
|
||||||
|
|
||||||
void setupAddedVersion(const int row, const WonkoVersionPtr &version);
|
void setupAddedVersion(const int row, const VersionPtr &version);
|
||||||
};
|
};
|
||||||
|
}
|
||||||
Q_DECLARE_METATYPE(WonkoVersionListPtr)
|
Q_DECLARE_METATYPE(Meta::VersionListPtr)
|
@ -29,15 +29,16 @@ void Library::getApplicableFiles(OpSys system, QStringList& jar, QStringList& na
|
|||||||
return out.absoluteFilePath();
|
return out.absoluteFilePath();
|
||||||
};
|
};
|
||||||
if(m_mojangDownloads)
|
if(m_mojangDownloads)
|
||||||
|
{
|
||||||
|
if(!isNative())
|
||||||
{
|
{
|
||||||
if(m_mojangDownloads->artifact)
|
if(m_mojangDownloads->artifact)
|
||||||
{
|
{
|
||||||
auto artifact = m_mojangDownloads->artifact;
|
auto artifact = m_mojangDownloads->artifact;
|
||||||
jar += actualPath(artifact->path);
|
jar += actualPath(artifact->path);
|
||||||
}
|
}
|
||||||
if(!isNative())
|
}
|
||||||
return;
|
else if(m_nativeClassifiers.contains(system))
|
||||||
if(m_nativeClassifiers.contains(system))
|
|
||||||
{
|
{
|
||||||
auto nativeClassifier = m_nativeClassifiers[system];
|
auto nativeClassifier = m_nativeClassifiers[system];
|
||||||
if(nativeClassifier.contains("${arch}"))
|
if(nativeClassifier.contains("${arch}"))
|
||||||
@ -55,7 +56,15 @@ void Library::getApplicableFiles(OpSys system, QStringList& jar, QStringList& na
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
native += actualPath(m_mojangDownloads->getDownloadInfo(nativeClassifier)->path);
|
auto dlinfo = m_mojangDownloads->getDownloadInfo(nativeClassifier);
|
||||||
|
if(!dlinfo)
|
||||||
|
{
|
||||||
|
qWarning() << "Cannot get native for" << nativeClassifier << "while processing" << m_name;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
native += actualPath(dlinfo->path);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -234,7 +234,7 @@ slots:
|
|||||||
auto test = readMojangJson("data/lib-native.json");
|
auto test = readMojangJson("data/lib-native.json");
|
||||||
QStringList jar, native, native32, native64;
|
QStringList jar, native, native32, native64;
|
||||||
test->getApplicableFiles(Os_OSX, jar, native, native32, native64, QString());
|
test->getApplicableFiles(Os_OSX, jar, native, native32, native64, QString());
|
||||||
QCOMPARE(jar, getStorage("org/lwjgl/lwjgl/lwjgl-platform/2.9.4-nightly-20150209/lwjgl-platform-2.9.4-nightly-20150209.jar"));
|
QCOMPARE(jar, QStringList());
|
||||||
QCOMPARE(native, getStorage("org/lwjgl/lwjgl/lwjgl-platform/2.9.4-nightly-20150209/lwjgl-platform-2.9.4-nightly-20150209-natives-osx.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(native32, {});
|
||||||
QCOMPARE(native64, {});
|
QCOMPARE(native64, {});
|
||||||
|
@ -5,7 +5,6 @@
|
|||||||
#include <settings/Setting.h>
|
#include <settings/Setting.h>
|
||||||
#include "settings/SettingsObject.h"
|
#include "settings/SettingsObject.h"
|
||||||
#include "Env.h"
|
#include "Env.h"
|
||||||
#include "minecraft/MinecraftVersionList.h"
|
|
||||||
#include <MMCStrings.h>
|
#include <MMCStrings.h>
|
||||||
#include <pathmatcher/RegexpMatcher.h>
|
#include <pathmatcher/RegexpMatcher.h>
|
||||||
#include <pathmatcher/MultiMatcher.h>
|
#include <pathmatcher/MultiMatcher.h>
|
||||||
@ -21,9 +20,13 @@
|
|||||||
#include "minecraft/launch/ModMinecraftJar.h"
|
#include "minecraft/launch/ModMinecraftJar.h"
|
||||||
#include "minecraft/launch/ClaimAccount.h"
|
#include "minecraft/launch/ClaimAccount.h"
|
||||||
#include "java/launch/CheckJava.h"
|
#include "java/launch/CheckJava.h"
|
||||||
|
#include <meta/Index.h>
|
||||||
|
#include <meta/VersionList.h>
|
||||||
|
|
||||||
#include <icons/IIconList.h>
|
#include <icons/IIconList.h>
|
||||||
|
|
||||||
|
#include <QCoreApplication>
|
||||||
|
|
||||||
#define IBUS "@im=ibus"
|
#define IBUS "@im=ibus"
|
||||||
|
|
||||||
// all of this because keeping things compatible with deprecated old settings
|
// all of this because keeping things compatible with deprecated old settings
|
||||||
@ -104,7 +107,7 @@ QString MinecraftInstance::binRoot() const
|
|||||||
|
|
||||||
std::shared_ptr< BaseVersionList > MinecraftInstance::versionList() const
|
std::shared_ptr< BaseVersionList > MinecraftInstance::versionList() const
|
||||||
{
|
{
|
||||||
return ENV.getVersionList("net.minecraft");
|
return ENV.metadataIndex()->get("net.minecraft");
|
||||||
}
|
}
|
||||||
|
|
||||||
QStringList MinecraftInstance::javaArguments() const
|
QStringList MinecraftInstance::javaArguments() const
|
||||||
|
@ -80,7 +80,7 @@ void MinecraftProfile::clear()
|
|||||||
m_traits.clear();
|
m_traits.clear();
|
||||||
m_jarMods.clear();
|
m_jarMods.clear();
|
||||||
mojangDownloads.clear();
|
mojangDownloads.clear();
|
||||||
m_problemSeverity = ProblemSeverity::PROBLEM_NONE;
|
m_problemSeverity = ProblemSeverity::None;
|
||||||
}
|
}
|
||||||
|
|
||||||
void MinecraftProfile::clearPatches()
|
void MinecraftProfile::clearPatches()
|
||||||
@ -273,9 +273,9 @@ QVariant MinecraftProfile::data(const QModelIndex &index, int role) const
|
|||||||
auto severity = patch->getProblemSeverity();
|
auto severity = patch->getProblemSeverity();
|
||||||
switch (severity)
|
switch (severity)
|
||||||
{
|
{
|
||||||
case PROBLEM_WARNING:
|
case ProblemSeverity::Warning:
|
||||||
return "warning";
|
return "warning";
|
||||||
case PROBLEM_ERROR:
|
case ProblemSeverity::Error:
|
||||||
return "error";
|
return "error";
|
||||||
default:
|
default:
|
||||||
return QVariant();
|
return QVariant();
|
||||||
@ -491,20 +491,29 @@ void MinecraftProfile::applyLibrary(LibraryPtr library)
|
|||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QList<LibraryPtr> * list = &m_libraries;
|
||||||
|
if(library->isNative())
|
||||||
|
{
|
||||||
|
list = &m_nativeLibraries;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto libraryCopy = Library::limitedCopy(library);
|
||||||
|
|
||||||
// find the library by name.
|
// find the library by name.
|
||||||
const int index = findLibraryByName(m_libraries, library->rawName());
|
const int index = findLibraryByName(*list, library->rawName());
|
||||||
// library not found? just add it.
|
// library not found? just add it.
|
||||||
if (index < 0)
|
if (index < 0)
|
||||||
{
|
{
|
||||||
m_libraries.append(Library::limitedCopy(library));
|
list->append(libraryCopy);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
auto existingLibrary = m_libraries.at(index);
|
|
||||||
|
auto existingLibrary = list->at(index);
|
||||||
// if we are higher it means we should update
|
// if we are higher it means we should update
|
||||||
if (Version(library->version()) > Version(existingLibrary->version()))
|
if (Version(library->version()) > Version(existingLibrary->version()))
|
||||||
{
|
{
|
||||||
auto libraryCopy = Library::limitedCopy(library);
|
list->replace(index, libraryCopy);
|
||||||
m_libraries.replace(index, libraryCopy);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -581,6 +590,11 @@ const QList<LibraryPtr> & MinecraftProfile::getLibraries() const
|
|||||||
return m_libraries;
|
return m_libraries;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const QList<LibraryPtr> & MinecraftProfile::getNativeLibraries() const
|
||||||
|
{
|
||||||
|
return m_nativeLibraries;
|
||||||
|
}
|
||||||
|
|
||||||
void MinecraftProfile::getLibraryFiles(const QString& architecture, QStringList& jars, QStringList& nativeJars, const QString& overridePath) const
|
void MinecraftProfile::getLibraryFiles(const QString& architecture, QStringList& jars, QStringList& nativeJars, const QString& overridePath) const
|
||||||
{
|
{
|
||||||
QStringList native32, native64;
|
QStringList native32, native64;
|
||||||
@ -590,6 +604,10 @@ void MinecraftProfile::getLibraryFiles(const QString& architecture, QStringList&
|
|||||||
{
|
{
|
||||||
lib->getApplicableFiles(currentSystem, jars, nativeJars, native32, native64, overridePath);
|
lib->getApplicableFiles(currentSystem, jars, nativeJars, native32, native64, overridePath);
|
||||||
}
|
}
|
||||||
|
for (auto lib : getNativeLibraries())
|
||||||
|
{
|
||||||
|
lib->getApplicableFiles(currentSystem, jars, nativeJars, native32, native64, overridePath);
|
||||||
|
}
|
||||||
if(architecture == "32")
|
if(architecture == "32")
|
||||||
{
|
{
|
||||||
nativeJars.append(native32);
|
nativeJars.append(native32);
|
||||||
@ -621,6 +639,11 @@ void MinecraftProfile::installJarMods(QStringList selectedFiles)
|
|||||||
m_strategy->installJarMods(selectedFiles);
|
m_strategy->installJarMods(selectedFiles);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MinecraftProfile::installVersion(BaseVersionPtr version)
|
||||||
|
{
|
||||||
|
// TODO: implement
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* TODO: get rid of this. Get rid of all order numbers.
|
* TODO: get rid of this. Get rid of all order numbers.
|
||||||
*/
|
*/
|
||||||
|
@ -22,8 +22,9 @@
|
|||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
#include "Library.h"
|
#include "Library.h"
|
||||||
#include "VersionFile.h"
|
#include "ProfilePatch.h"
|
||||||
#include "JarMod.h"
|
#include "JarMod.h"
|
||||||
|
#include "BaseVersion.h"
|
||||||
#include "MojangDownloadInfo.h"
|
#include "MojangDownloadInfo.h"
|
||||||
|
|
||||||
#include "multimc_logic_export.h"
|
#include "multimc_logic_export.h"
|
||||||
@ -58,6 +59,9 @@ public:
|
|||||||
/// install more jar mods
|
/// install more jar mods
|
||||||
void installJarMods(QStringList selectedFiles);
|
void installJarMods(QStringList selectedFiles);
|
||||||
|
|
||||||
|
/// install more jar mods
|
||||||
|
void installVersion(BaseVersionPtr version);
|
||||||
|
|
||||||
/// DEPRECATED, remove ASAP
|
/// DEPRECATED, remove ASAP
|
||||||
int getFreeOrderNumber();
|
int getFreeOrderNumber();
|
||||||
|
|
||||||
@ -111,6 +115,7 @@ public: /* getters for profile variables */
|
|||||||
const QStringList & getTweakers() const;
|
const QStringList & getTweakers() const;
|
||||||
const QList<JarmodPtr> & getJarMods() const;
|
const QList<JarmodPtr> & getJarMods() const;
|
||||||
const QList<LibraryPtr> & getLibraries() const;
|
const QList<LibraryPtr> & getLibraries() const;
|
||||||
|
const QList<LibraryPtr> & getNativeLibraries() const;
|
||||||
void getLibraryFiles(const QString & architecture, QStringList & jars, QStringList & nativeJars, const QString & overridePath) const;
|
void getLibraryFiles(const QString & architecture, QStringList & jars, QStringList & nativeJars, const QString & overridePath) const;
|
||||||
QString getMainJarUrl() const;
|
QString getMainJarUrl() const;
|
||||||
bool hasTrait(const QString & trait) const;
|
bool hasTrait(const QString & trait) const;
|
||||||
@ -165,13 +170,16 @@ private: /* data */
|
|||||||
/// the list of libraries
|
/// the list of libraries
|
||||||
QList<LibraryPtr> m_libraries;
|
QList<LibraryPtr> m_libraries;
|
||||||
|
|
||||||
|
/// the list of libraries
|
||||||
|
QList<LibraryPtr> m_nativeLibraries;
|
||||||
|
|
||||||
/// traits, collected from all the version files (version files can only add)
|
/// traits, collected from all the version files (version files can only add)
|
||||||
QSet<QString> m_traits;
|
QSet<QString> m_traits;
|
||||||
|
|
||||||
/// A list of jar mods. version files can add those.
|
/// A list of jar mods. version files can add those.
|
||||||
QList<JarmodPtr> m_jarMods;
|
QList<JarmodPtr> m_jarMods;
|
||||||
|
|
||||||
ProblemSeverity m_problemSeverity = PROBLEM_NONE;
|
ProblemSeverity m_problemSeverity = ProblemSeverity::None;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
FIXME: add support for those rules here? Looks like a pile of quick hacks to me though.
|
FIXME: add support for those rules here? Looks like a pile of quick hacks to me though.
|
||||||
|
@ -1,230 +0,0 @@
|
|||||||
#include "MinecraftVersion.h"
|
|
||||||
#include "MinecraftProfile.h"
|
|
||||||
#include "VersionBuildError.h"
|
|
||||||
#include "ProfileUtils.h"
|
|
||||||
#include "settings/SettingsObject.h"
|
|
||||||
|
|
||||||
bool MinecraftVersion::usesLegacyLauncher()
|
|
||||||
{
|
|
||||||
return m_traits.contains("legacyLaunch") || m_traits.contains("aplhaLaunch");
|
|
||||||
}
|
|
||||||
|
|
||||||
QString MinecraftVersion::descriptor()
|
|
||||||
{
|
|
||||||
return m_descriptor;
|
|
||||||
}
|
|
||||||
|
|
||||||
QString MinecraftVersion::name()
|
|
||||||
{
|
|
||||||
return m_name;
|
|
||||||
}
|
|
||||||
|
|
||||||
QString MinecraftVersion::typeString() const
|
|
||||||
{
|
|
||||||
if(m_type == "snapshot")
|
|
||||||
{
|
|
||||||
return QObject::tr("Snapshot");
|
|
||||||
}
|
|
||||||
else if (m_type == "release")
|
|
||||||
{
|
|
||||||
return QObject::tr("Regular release");
|
|
||||||
}
|
|
||||||
else if (m_type == "old_alpha")
|
|
||||||
{
|
|
||||||
return QObject::tr("Alpha");
|
|
||||||
}
|
|
||||||
else if (m_type == "old_beta")
|
|
||||||
{
|
|
||||||
return QObject::tr("Beta");
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return QString();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
VersionSource MinecraftVersion::getVersionSource()
|
|
||||||
{
|
|
||||||
return m_versionSource;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool MinecraftVersion::hasJarMods()
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool MinecraftVersion::isMinecraftVersion()
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void MinecraftVersion::applyFileTo(MinecraftProfile *profile)
|
|
||||||
{
|
|
||||||
if(m_versionSource == VersionSource::Local && getVersionFile())
|
|
||||||
{
|
|
||||||
getVersionFile()->applyTo(profile);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
throw VersionIncomplete(QObject::tr("Can't apply incomplete/builtin Minecraft version %1").arg(m_name));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
VersionFilePtr MinecraftVersion::getVersionFile()
|
|
||||||
{
|
|
||||||
QFileInfo versionFile(QString("versions/%1/%1.dat").arg(m_descriptor));
|
|
||||||
m_problems.clear();
|
|
||||||
m_problemSeverity = PROBLEM_NONE;
|
|
||||||
if(!versionFile.exists())
|
|
||||||
{
|
|
||||||
if(m_loadedVersionFile)
|
|
||||||
{
|
|
||||||
m_loadedVersionFile.reset();
|
|
||||||
}
|
|
||||||
addProblem(PROBLEM_WARNING, QObject::tr("The patch file doesn't exist locally. It's possible it just needs to be downloaded."));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
if(versionFile.lastModified() != m_loadedVersionFileTimestamp)
|
|
||||||
{
|
|
||||||
auto loadedVersionFile = ProfileUtils::parseBinaryJsonFile(versionFile);
|
|
||||||
loadedVersionFile->name = "Minecraft";
|
|
||||||
loadedVersionFile->setCustomizable(true);
|
|
||||||
m_loadedVersionFileTimestamp = versionFile.lastModified();
|
|
||||||
m_loadedVersionFile = loadedVersionFile;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch(Exception e)
|
|
||||||
{
|
|
||||||
m_loadedVersionFile.reset();
|
|
||||||
addProblem(PROBLEM_ERROR, QObject::tr("The patch file couldn't be read:\n%1").arg(e.cause()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return m_loadedVersionFile;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool MinecraftVersion::isCustomizable()
|
|
||||||
{
|
|
||||||
switch(m_versionSource)
|
|
||||||
{
|
|
||||||
case VersionSource::Local:
|
|
||||||
case VersionSource::Remote:
|
|
||||||
// locally cached file, or a remote file that we can acquire can be customized
|
|
||||||
return true;
|
|
||||||
case VersionSource::Builtin:
|
|
||||||
// builtins do not follow the normal OneSix format. They are not customizable.
|
|
||||||
default:
|
|
||||||
// Everything else is undefined and therefore not customizable.
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
const QList<PatchProblem> &MinecraftVersion::getProblems()
|
|
||||||
{
|
|
||||||
if(m_versionSource != VersionSource::Builtin && getVersionFile())
|
|
||||||
{
|
|
||||||
return getVersionFile()->getProblems();
|
|
||||||
}
|
|
||||||
return ProfilePatch::getProblems();
|
|
||||||
}
|
|
||||||
|
|
||||||
ProblemSeverity MinecraftVersion::getProblemSeverity()
|
|
||||||
{
|
|
||||||
if(m_versionSource != VersionSource::Builtin && getVersionFile())
|
|
||||||
{
|
|
||||||
return getVersionFile()->getProblemSeverity();
|
|
||||||
}
|
|
||||||
return ProfilePatch::getProblemSeverity();
|
|
||||||
}
|
|
||||||
|
|
||||||
void MinecraftVersion::applyTo(MinecraftProfile *profile)
|
|
||||||
{
|
|
||||||
// do we have this one cached?
|
|
||||||
if (m_versionSource == VersionSource::Local)
|
|
||||||
{
|
|
||||||
applyFileTo(profile);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
// if not builtin, do not proceed any further.
|
|
||||||
if (m_versionSource != VersionSource::Builtin)
|
|
||||||
{
|
|
||||||
throw VersionIncomplete(QObject::tr(
|
|
||||||
"Minecraft version %1 could not be applied: version files are missing.").arg(m_descriptor));
|
|
||||||
}
|
|
||||||
profile->applyMinecraftVersion(m_descriptor);
|
|
||||||
profile->applyMainClass(m_mainClass);
|
|
||||||
profile->applyAppletClass(m_appletClass);
|
|
||||||
profile->applyMinecraftArguments(" ${auth_player_name} ${auth_session}"); // all builtin versions are legacy
|
|
||||||
profile->applyMinecraftVersionType(m_type);
|
|
||||||
profile->applyTraits(m_traits);
|
|
||||||
profile->applyProblemSeverity(m_problemSeverity);
|
|
||||||
}
|
|
||||||
|
|
||||||
int MinecraftVersion::getOrder()
|
|
||||||
{
|
|
||||||
return order;
|
|
||||||
}
|
|
||||||
|
|
||||||
void MinecraftVersion::setOrder(int order)
|
|
||||||
{
|
|
||||||
this->order = order;
|
|
||||||
}
|
|
||||||
|
|
||||||
QList<JarmodPtr> MinecraftVersion::getJarMods()
|
|
||||||
{
|
|
||||||
return QList<JarmodPtr>();
|
|
||||||
}
|
|
||||||
|
|
||||||
QString MinecraftVersion::getName()
|
|
||||||
{
|
|
||||||
return "Minecraft";
|
|
||||||
}
|
|
||||||
QString MinecraftVersion::getVersion()
|
|
||||||
{
|
|
||||||
return m_descriptor;
|
|
||||||
}
|
|
||||||
QString MinecraftVersion::getID()
|
|
||||||
{
|
|
||||||
return "net.minecraft";
|
|
||||||
}
|
|
||||||
QString MinecraftVersion::getFilename()
|
|
||||||
{
|
|
||||||
return QString();
|
|
||||||
}
|
|
||||||
QDateTime MinecraftVersion::getReleaseDateTime()
|
|
||||||
{
|
|
||||||
return m_releaseTime;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
bool MinecraftVersion::needsUpdate()
|
|
||||||
{
|
|
||||||
return m_versionSource == VersionSource::Remote || hasUpdate();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool MinecraftVersion::hasUpdate()
|
|
||||||
{
|
|
||||||
return m_versionSource == VersionSource::Remote || (m_versionSource == VersionSource::Local && upstreamUpdate);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool MinecraftVersion::isCustom()
|
|
||||||
{
|
|
||||||
// if we add any other source types, this will evaluate to false for them.
|
|
||||||
return m_versionSource != VersionSource::Builtin
|
|
||||||
&& m_versionSource != VersionSource::Local
|
|
||||||
&& m_versionSource != VersionSource::Remote;
|
|
||||||
}
|
|
@ -1,132 +0,0 @@
|
|||||||
/* Copyright 2013-2017 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 <QStringList>
|
|
||||||
#include <QSet>
|
|
||||||
#include <QDateTime>
|
|
||||||
|
|
||||||
#include "BaseVersion.h"
|
|
||||||
#include "ProfilePatch.h"
|
|
||||||
#include "VersionFile.h"
|
|
||||||
|
|
||||||
#include "multimc_logic_export.h"
|
|
||||||
|
|
||||||
class MinecraftProfile;
|
|
||||||
class MinecraftVersion;
|
|
||||||
typedef std::shared_ptr<MinecraftVersion> MinecraftVersionPtr;
|
|
||||||
|
|
||||||
class MULTIMC_LOGIC_EXPORT MinecraftVersion : public BaseVersion, public ProfilePatch
|
|
||||||
{
|
|
||||||
friend class MinecraftVersionList;
|
|
||||||
|
|
||||||
public: /* methods */
|
|
||||||
bool usesLegacyLauncher();
|
|
||||||
virtual QString descriptor() override;
|
|
||||||
virtual QString name() override;
|
|
||||||
virtual QString typeString() const override;
|
|
||||||
virtual bool hasJarMods() override;
|
|
||||||
virtual bool isMinecraftVersion() override;
|
|
||||||
virtual void applyTo(MinecraftProfile *profile) override;
|
|
||||||
virtual int getOrder() override;
|
|
||||||
virtual void setOrder(int order) override;
|
|
||||||
virtual QList<JarmodPtr> getJarMods() override;
|
|
||||||
virtual QString getID() override;
|
|
||||||
virtual QString getVersion() override;
|
|
||||||
virtual QString getName() override;
|
|
||||||
virtual QString getFilename() override;
|
|
||||||
QDateTime getReleaseDateTime() override;
|
|
||||||
VersionSource getVersionSource() override;
|
|
||||||
|
|
||||||
bool needsUpdate();
|
|
||||||
bool hasUpdate();
|
|
||||||
virtual bool isCustom() override;
|
|
||||||
virtual bool isMoveable() override
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
virtual bool isCustomizable() override;
|
|
||||||
virtual bool isRemovable() override
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
virtual bool isRevertible() override
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
virtual bool isEditable() override
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
virtual bool isVersionChangeable() override
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual VersionFilePtr getVersionFile() override;
|
|
||||||
|
|
||||||
// virtual QJsonDocument toJson(bool saveOrder) override;
|
|
||||||
|
|
||||||
QString getUrl() const;
|
|
||||||
|
|
||||||
virtual const QList<PatchProblem> &getProblems() override;
|
|
||||||
virtual ProblemSeverity getProblemSeverity() override;
|
|
||||||
|
|
||||||
private: /* methods */
|
|
||||||
void applyFileTo(MinecraftProfile *profile);
|
|
||||||
|
|
||||||
protected: /* data */
|
|
||||||
VersionSource m_versionSource = VersionSource::Builtin;
|
|
||||||
|
|
||||||
/// The URL that this version will be downloaded from.
|
|
||||||
QString m_versionFileURL;
|
|
||||||
|
|
||||||
/// the human readable version name
|
|
||||||
QString m_name;
|
|
||||||
|
|
||||||
/// the version ID.
|
|
||||||
QString m_descriptor;
|
|
||||||
|
|
||||||
/// version traits. added by MultiMC
|
|
||||||
QSet<QString> m_traits;
|
|
||||||
|
|
||||||
/// The main class this version uses (if any, can be empty).
|
|
||||||
QString m_mainClass;
|
|
||||||
|
|
||||||
/// The applet class this version uses (if any, can be empty).
|
|
||||||
QString m_appletClass;
|
|
||||||
|
|
||||||
/// The type of this release
|
|
||||||
QString m_type;
|
|
||||||
|
|
||||||
/// the time this version was actually released by Mojang
|
|
||||||
QDateTime m_releaseTime;
|
|
||||||
|
|
||||||
/// the time this version was last updated by Mojang
|
|
||||||
QDateTime m_updateTime;
|
|
||||||
|
|
||||||
/// MD5 hash of the minecraft jar
|
|
||||||
QString m_jarChecksum;
|
|
||||||
|
|
||||||
/// order of this file... default = -2
|
|
||||||
int order = -2;
|
|
||||||
|
|
||||||
/// an update available from Mojang
|
|
||||||
MinecraftVersionPtr upstreamUpdate;
|
|
||||||
|
|
||||||
QDateTime m_loadedVersionFileTimestamp;
|
|
||||||
mutable VersionFilePtr m_loadedVersionFile;
|
|
||||||
};
|
|
@ -1,677 +0,0 @@
|
|||||||
/* Copyright 2013-2017 MultiMC Contributors
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <QtXml>
|
|
||||||
#include "Json.h"
|
|
||||||
#include <QtAlgorithms>
|
|
||||||
#include <QtNetwork>
|
|
||||||
|
|
||||||
#include "Env.h"
|
|
||||||
#include "Exception.h"
|
|
||||||
|
|
||||||
#include "MinecraftVersionList.h"
|
|
||||||
#include "net/URLConstants.h"
|
|
||||||
|
|
||||||
#include "ParseUtils.h"
|
|
||||||
#include "ProfileUtils.h"
|
|
||||||
#include "VersionFilterData.h"
|
|
||||||
#include "onesix/OneSixVersionFormat.h"
|
|
||||||
#include "MojangVersionFormat.h"
|
|
||||||
#include <FileSystem.h>
|
|
||||||
|
|
||||||
static const char * localVersionCache = "versions/versions.dat";
|
|
||||||
|
|
||||||
class MCVListLoadTask : public Task
|
|
||||||
{
|
|
||||||
Q_OBJECT
|
|
||||||
|
|
||||||
public:
|
|
||||||
explicit MCVListLoadTask(MinecraftVersionList *vlist);
|
|
||||||
virtual ~MCVListLoadTask() override{};
|
|
||||||
|
|
||||||
virtual void executeTask() override;
|
|
||||||
|
|
||||||
protected
|
|
||||||
slots:
|
|
||||||
void list_downloaded();
|
|
||||||
|
|
||||||
protected:
|
|
||||||
QNetworkReply *vlistReply;
|
|
||||||
MinecraftVersionList *m_list;
|
|
||||||
MinecraftVersion *m_currentStable;
|
|
||||||
};
|
|
||||||
|
|
||||||
class MCVListVersionUpdateTask : public Task
|
|
||||||
{
|
|
||||||
Q_OBJECT
|
|
||||||
|
|
||||||
public:
|
|
||||||
explicit MCVListVersionUpdateTask(MinecraftVersionList *vlist, std::shared_ptr<MinecraftVersion> updatedVersion);
|
|
||||||
virtual ~MCVListVersionUpdateTask() override{};
|
|
||||||
virtual void executeTask() override;
|
|
||||||
bool canAbort() const override;
|
|
||||||
|
|
||||||
public slots:
|
|
||||||
bool abort() override;
|
|
||||||
|
|
||||||
protected
|
|
||||||
slots:
|
|
||||||
void json_downloaded();
|
|
||||||
|
|
||||||
protected:
|
|
||||||
NetJobPtr specificVersionDownloadJob;
|
|
||||||
QByteArray versionIndexData;
|
|
||||||
std::shared_ptr<MinecraftVersion> updatedVersion;
|
|
||||||
MinecraftVersionList *m_list;
|
|
||||||
bool m_aborted = false;
|
|
||||||
};
|
|
||||||
|
|
||||||
class ListLoadError : public Exception
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
ListLoadError(QString cause) : Exception(cause) {};
|
|
||||||
virtual ~ListLoadError() noexcept
|
|
||||||
{
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
MinecraftVersionList::MinecraftVersionList(QObject *parent) : BaseVersionList(parent)
|
|
||||||
{
|
|
||||||
loadBuiltinList();
|
|
||||||
loadCachedList();
|
|
||||||
}
|
|
||||||
|
|
||||||
Task *MinecraftVersionList::getLoadTask()
|
|
||||||
{
|
|
||||||
return new MCVListLoadTask(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool MinecraftVersionList::isLoaded()
|
|
||||||
{
|
|
||||||
return m_loaded;
|
|
||||||
}
|
|
||||||
|
|
||||||
const BaseVersionPtr MinecraftVersionList::at(int i) const
|
|
||||||
{
|
|
||||||
return m_vlist.at(i);
|
|
||||||
}
|
|
||||||
|
|
||||||
int MinecraftVersionList::count() const
|
|
||||||
{
|
|
||||||
return m_vlist.count();
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool cmpVersions(BaseVersionPtr first, BaseVersionPtr second)
|
|
||||||
{
|
|
||||||
auto left = std::dynamic_pointer_cast<MinecraftVersion>(first);
|
|
||||||
auto right = std::dynamic_pointer_cast<MinecraftVersion>(second);
|
|
||||||
return left->getReleaseDateTime() > right->getReleaseDateTime();
|
|
||||||
}
|
|
||||||
|
|
||||||
void MinecraftVersionList::sortInternal()
|
|
||||||
{
|
|
||||||
qSort(m_vlist.begin(), m_vlist.end(), cmpVersions);
|
|
||||||
}
|
|
||||||
|
|
||||||
void MinecraftVersionList::loadCachedList()
|
|
||||||
{
|
|
||||||
QFile localIndex(localVersionCache);
|
|
||||||
if (!localIndex.exists())
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (!localIndex.open(QIODevice::ReadOnly))
|
|
||||||
{
|
|
||||||
// FIXME: this is actually a very bad thing! How do we deal with this?
|
|
||||||
qCritical() << "The minecraft version cache can't be read.";
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
auto data = localIndex.readAll();
|
|
||||||
try
|
|
||||||
{
|
|
||||||
localIndex.close();
|
|
||||||
QJsonDocument jsonDoc = QJsonDocument::fromBinaryData(data);
|
|
||||||
if (jsonDoc.isNull())
|
|
||||||
{
|
|
||||||
throw ListLoadError(tr("Error reading the version list."));
|
|
||||||
}
|
|
||||||
loadMojangList(jsonDoc, VersionSource::Local);
|
|
||||||
}
|
|
||||||
catch (Exception &e)
|
|
||||||
{
|
|
||||||
// the cache has gone bad for some reason... flush it.
|
|
||||||
qCritical() << "The minecraft version cache is corrupted. Flushing cache.";
|
|
||||||
localIndex.remove();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
m_hasLocalIndex = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void MinecraftVersionList::loadBuiltinList()
|
|
||||||
{
|
|
||||||
qDebug() << "Loading builtin version list.";
|
|
||||||
// grab the version list data from internal resources.
|
|
||||||
const QJsonDocument doc =
|
|
||||||
Json::requireDocument(QString(":/versions/minecraft.json"), "builtin version list");
|
|
||||||
const QJsonObject root = doc.object();
|
|
||||||
|
|
||||||
// parse all the versions
|
|
||||||
for (const auto version : Json::requireArray(root.value("versions")))
|
|
||||||
{
|
|
||||||
QJsonObject versionObj = version.toObject();
|
|
||||||
QString versionID = versionObj.value("id").toString("");
|
|
||||||
QString versionTypeStr = versionObj.value("type").toString("");
|
|
||||||
if (versionID.isEmpty() || versionTypeStr.isEmpty())
|
|
||||||
{
|
|
||||||
qCritical() << "Parsed version is missing ID or type";
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (g_VersionFilterData.legacyBlacklist.contains(versionID))
|
|
||||||
{
|
|
||||||
qWarning() << "Blacklisted legacy version ignored: " << versionID;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Now, we construct the version object and add it to the list.
|
|
||||||
std::shared_ptr<MinecraftVersion> mcVersion(new MinecraftVersion());
|
|
||||||
mcVersion->m_name = mcVersion->m_descriptor = versionID;
|
|
||||||
|
|
||||||
// Parse the timestamp.
|
|
||||||
mcVersion->m_releaseTime = timeFromS3Time(versionObj.value("releaseTime").toString(""));
|
|
||||||
mcVersion->m_versionFileURL = QString();
|
|
||||||
mcVersion->m_versionSource = VersionSource::Builtin;
|
|
||||||
mcVersion->m_type = versionTypeStr;
|
|
||||||
mcVersion->m_appletClass = versionObj.value("appletClass").toString("");
|
|
||||||
mcVersion->m_mainClass = versionObj.value("mainClass").toString("");
|
|
||||||
mcVersion->m_jarChecksum = versionObj.value("checksum").toString("");
|
|
||||||
if (versionObj.contains("+traits"))
|
|
||||||
{
|
|
||||||
for (auto traitVal : Json::requireArray(versionObj.value("+traits")))
|
|
||||||
{
|
|
||||||
mcVersion->m_traits.insert(Json::requireString(traitVal));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
m_lookup[versionID] = mcVersion;
|
|
||||||
m_vlist.append(mcVersion);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void MinecraftVersionList::loadMojangList(QJsonDocument jsonDoc, VersionSource source)
|
|
||||||
{
|
|
||||||
qDebug() << "Loading" << ((source == VersionSource::Remote) ? "remote" : "local") << "version list.";
|
|
||||||
|
|
||||||
if (!jsonDoc.isObject())
|
|
||||||
{
|
|
||||||
throw ListLoadError(tr("Error parsing version list JSON: jsonDoc is not an object"));
|
|
||||||
}
|
|
||||||
|
|
||||||
QJsonObject root = jsonDoc.object();
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
QJsonObject latest = Json::requireObject(root.value("latest"));
|
|
||||||
m_latestReleaseID = Json::requireString(latest.value("release"));
|
|
||||||
m_latestSnapshotID = Json::requireString(latest.value("snapshot"));
|
|
||||||
}
|
|
||||||
catch (Exception &err)
|
|
||||||
{
|
|
||||||
qCritical()
|
|
||||||
<< tr("Error parsing version list JSON: couldn't determine latest versions");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Now, get the array of versions.
|
|
||||||
if (!root.value("versions").isArray())
|
|
||||||
{
|
|
||||||
throw ListLoadError(tr("Error parsing version list JSON: version list object is "
|
|
||||||
"missing 'versions' array"));
|
|
||||||
}
|
|
||||||
QJsonArray versions = root.value("versions").toArray();
|
|
||||||
|
|
||||||
QList<BaseVersionPtr> tempList;
|
|
||||||
for (auto version : versions)
|
|
||||||
{
|
|
||||||
// Load the version info.
|
|
||||||
if (!version.isObject())
|
|
||||||
{
|
|
||||||
qCritical() << "Error while parsing version list : invalid JSON structure";
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
QJsonObject versionObj = version.toObject();
|
|
||||||
QString versionID = versionObj.value("id").toString("");
|
|
||||||
if (versionID.isEmpty())
|
|
||||||
{
|
|
||||||
qCritical() << "Error while parsing version : version ID is missing";
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (g_VersionFilterData.legacyBlacklist.contains(versionID))
|
|
||||||
{
|
|
||||||
qWarning() << "Blacklisted legacy version ignored: " << versionID;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Now, we construct the version object and add it to the list.
|
|
||||||
std::shared_ptr<MinecraftVersion> mcVersion(new MinecraftVersion());
|
|
||||||
mcVersion->m_name = mcVersion->m_descriptor = versionID;
|
|
||||||
|
|
||||||
mcVersion->m_releaseTime = timeFromS3Time(versionObj.value("releaseTime").toString(""));
|
|
||||||
mcVersion->m_updateTime = timeFromS3Time(versionObj.value("time").toString(""));
|
|
||||||
|
|
||||||
if (mcVersion->m_releaseTime < g_VersionFilterData.legacyCutoffDate)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// depends on where we load the version from -- network request or local file?
|
|
||||||
mcVersion->m_versionSource = source;
|
|
||||||
mcVersion->m_versionFileURL = versionObj.value("url").toString("");
|
|
||||||
QString versionTypeStr = versionObj.value("type").toString("");
|
|
||||||
if (versionTypeStr.isEmpty())
|
|
||||||
{
|
|
||||||
qCritical() << "Ignoring" << versionID
|
|
||||||
<< "because it doesn't have the version type set.";
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
// OneSix or Legacy. use filter to determine type
|
|
||||||
if (versionTypeStr == "release")
|
|
||||||
{
|
|
||||||
}
|
|
||||||
else if (versionTypeStr == "snapshot") // It's a snapshot... yay
|
|
||||||
{
|
|
||||||
}
|
|
||||||
else if (versionTypeStr == "old_alpha")
|
|
||||||
{
|
|
||||||
}
|
|
||||||
else if (versionTypeStr == "old_beta")
|
|
||||||
{
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
qCritical() << "Ignoring" << versionID
|
|
||||||
<< "because it has an invalid version type.";
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
mcVersion->m_type = versionTypeStr;
|
|
||||||
qDebug() << "Loaded version" << versionID << "from"
|
|
||||||
<< ((source == VersionSource::Remote) ? "remote" : "local") << "version list.";
|
|
||||||
tempList.append(mcVersion);
|
|
||||||
}
|
|
||||||
updateListData(tempList);
|
|
||||||
if(source == VersionSource::Remote)
|
|
||||||
{
|
|
||||||
m_loaded = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void MinecraftVersionList::sortVersions()
|
|
||||||
{
|
|
||||||
beginResetModel();
|
|
||||||
sortInternal();
|
|
||||||
endResetModel();
|
|
||||||
}
|
|
||||||
|
|
||||||
QVariant MinecraftVersionList::data(const QModelIndex& index, int role) const
|
|
||||||
{
|
|
||||||
if (!index.isValid())
|
|
||||||
return QVariant();
|
|
||||||
|
|
||||||
if (index.row() > count())
|
|
||||||
return QVariant();
|
|
||||||
|
|
||||||
auto version = std::dynamic_pointer_cast<MinecraftVersion>(m_vlist[index.row()]);
|
|
||||||
switch (role)
|
|
||||||
{
|
|
||||||
case VersionPointerRole:
|
|
||||||
return qVariantFromValue(m_vlist[index.row()]);
|
|
||||||
|
|
||||||
case VersionRole:
|
|
||||||
return version->name();
|
|
||||||
|
|
||||||
case VersionIdRole:
|
|
||||||
return version->descriptor();
|
|
||||||
|
|
||||||
case RecommendedRole:
|
|
||||||
return version->descriptor() == m_latestReleaseID;
|
|
||||||
|
|
||||||
case LatestRole:
|
|
||||||
{
|
|
||||||
if(version->descriptor() != m_latestSnapshotID)
|
|
||||||
return false;
|
|
||||||
MinecraftVersionPtr latestRelease = std::dynamic_pointer_cast<MinecraftVersion>(getLatestStable());
|
|
||||||
/*
|
|
||||||
if(latestRelease && latestRelease->m_releaseTime > version->m_releaseTime)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
case TypeRole:
|
|
||||||
return version->typeString();
|
|
||||||
|
|
||||||
default:
|
|
||||||
return QVariant();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
BaseVersionList::RoleList MinecraftVersionList::providesRoles() const
|
|
||||||
{
|
|
||||||
return {VersionPointerRole, VersionRole, VersionIdRole, RecommendedRole, LatestRole, TypeRole};
|
|
||||||
}
|
|
||||||
|
|
||||||
BaseVersionPtr MinecraftVersionList::getLatestStable() const
|
|
||||||
{
|
|
||||||
if(m_lookup.contains(m_latestReleaseID))
|
|
||||||
return m_lookup[m_latestReleaseID];
|
|
||||||
return BaseVersionPtr();
|
|
||||||
}
|
|
||||||
|
|
||||||
BaseVersionPtr MinecraftVersionList::getRecommended() const
|
|
||||||
{
|
|
||||||
return getLatestStable();
|
|
||||||
}
|
|
||||||
|
|
||||||
void MinecraftVersionList::updateListData(QList<BaseVersionPtr> versions)
|
|
||||||
{
|
|
||||||
beginResetModel();
|
|
||||||
for (auto version : versions)
|
|
||||||
{
|
|
||||||
auto descr = version->descriptor();
|
|
||||||
|
|
||||||
if (!m_lookup.contains(descr))
|
|
||||||
{
|
|
||||||
m_lookup[version->descriptor()] = version;
|
|
||||||
m_vlist.append(version);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
auto orig = std::dynamic_pointer_cast<MinecraftVersion>(m_lookup[descr]);
|
|
||||||
auto added = std::dynamic_pointer_cast<MinecraftVersion>(version);
|
|
||||||
// updateListData is called after Mojang list loads. those can be local or remote
|
|
||||||
// remote comes always after local
|
|
||||||
// any other options are ignored
|
|
||||||
if (orig->m_versionSource != VersionSource::Local || added->m_versionSource != VersionSource::Remote)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
// alright, it's an update. put it inside the original, for further processing.
|
|
||||||
orig->upstreamUpdate = added;
|
|
||||||
}
|
|
||||||
sortInternal();
|
|
||||||
endResetModel();
|
|
||||||
}
|
|
||||||
|
|
||||||
MCVListLoadTask::MCVListLoadTask(MinecraftVersionList *vlist)
|
|
||||||
{
|
|
||||||
m_list = vlist;
|
|
||||||
m_currentStable = NULL;
|
|
||||||
vlistReply = nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
void MCVListLoadTask::executeTask()
|
|
||||||
{
|
|
||||||
setStatus(tr("Loading instance version list..."));
|
|
||||||
vlistReply = ENV.qnam().get(QNetworkRequest(QUrl("https://launchermeta.mojang.com/mc/game/version_manifest.json")));
|
|
||||||
connect(vlistReply, SIGNAL(finished()), this, SLOT(list_downloaded()));
|
|
||||||
}
|
|
||||||
|
|
||||||
void MCVListLoadTask::list_downloaded()
|
|
||||||
{
|
|
||||||
if (vlistReply->error() != QNetworkReply::NoError)
|
|
||||||
{
|
|
||||||
vlistReply->deleteLater();
|
|
||||||
emitFailed("Failed to load Minecraft main version list" + vlistReply->errorString());
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto data = vlistReply->readAll();
|
|
||||||
vlistReply->deleteLater();
|
|
||||||
try
|
|
||||||
{
|
|
||||||
QJsonParseError jsonError;
|
|
||||||
QJsonDocument jsonDoc = QJsonDocument::fromJson(data, &jsonError);
|
|
||||||
if (jsonError.error != QJsonParseError::NoError)
|
|
||||||
{
|
|
||||||
throw ListLoadError(
|
|
||||||
tr("Error parsing version list JSON: %1").arg(jsonError.errorString()));
|
|
||||||
}
|
|
||||||
m_list->loadMojangList(jsonDoc, VersionSource::Remote);
|
|
||||||
}
|
|
||||||
catch (Exception &e)
|
|
||||||
{
|
|
||||||
emitFailed(e.cause());
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
emitSucceeded();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
MCVListVersionUpdateTask::MCVListVersionUpdateTask(MinecraftVersionList *vlist, std::shared_ptr<MinecraftVersion> updatedVersion)
|
|
||||||
: Task()
|
|
||||||
{
|
|
||||||
m_list = vlist;
|
|
||||||
this->updatedVersion = updatedVersion;
|
|
||||||
}
|
|
||||||
|
|
||||||
void MCVListVersionUpdateTask::executeTask()
|
|
||||||
{
|
|
||||||
if(m_aborted)
|
|
||||||
{
|
|
||||||
emitFailed(tr("Task aborted."));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
auto job = new NetJob("Version index");
|
|
||||||
job->addNetAction(Net::Download::makeByteArray(QUrl(updatedVersion->getUrl()), &versionIndexData));
|
|
||||||
specificVersionDownloadJob.reset(job);
|
|
||||||
connect(specificVersionDownloadJob.get(), SIGNAL(succeeded()), SLOT(json_downloaded()));
|
|
||||||
connect(specificVersionDownloadJob.get(), SIGNAL(failed(QString)), SIGNAL(failed(QString)));
|
|
||||||
connect(specificVersionDownloadJob.get(), SIGNAL(progress(qint64, qint64)), SIGNAL(progress(qint64, qint64)));
|
|
||||||
specificVersionDownloadJob->start();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool MCVListVersionUpdateTask::canAbort() const
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool MCVListVersionUpdateTask::abort()
|
|
||||||
{
|
|
||||||
m_aborted = true;
|
|
||||||
if(specificVersionDownloadJob)
|
|
||||||
{
|
|
||||||
return specificVersionDownloadJob->abort();
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void MCVListVersionUpdateTask::json_downloaded()
|
|
||||||
{
|
|
||||||
specificVersionDownloadJob.reset();
|
|
||||||
|
|
||||||
QJsonParseError jsonError;
|
|
||||||
QJsonDocument jsonDoc = QJsonDocument::fromJson(versionIndexData, &jsonError);
|
|
||||||
versionIndexData.clear();
|
|
||||||
|
|
||||||
if (jsonError.error != QJsonParseError::NoError)
|
|
||||||
{
|
|
||||||
emitFailed(tr("The download version file is not valid."));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
VersionFilePtr file;
|
|
||||||
try
|
|
||||||
{
|
|
||||||
file = MojangVersionFormat::versionFileFromJson(jsonDoc, "net.minecraft.json");
|
|
||||||
}
|
|
||||||
catch (Exception &e)
|
|
||||||
{
|
|
||||||
emitFailed(tr("Couldn't process version file: %1").arg(e.cause()));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Strip LWJGL from the version file. We use our own.
|
|
||||||
ProfileUtils::removeLwjglFromPatch(file);
|
|
||||||
|
|
||||||
// TODO: recognize and add LWJGL versions here.
|
|
||||||
|
|
||||||
file->fileId = "net.minecraft";
|
|
||||||
|
|
||||||
// now dump the file to disk
|
|
||||||
auto doc = OneSixVersionFormat::versionFileToJson(file, false);
|
|
||||||
auto newdata = doc.toBinaryData();
|
|
||||||
auto id = updatedVersion->descriptor();
|
|
||||||
QString targetPath = "versions/" + id + "/" + id + ".dat";
|
|
||||||
FS::ensureFilePathExists(targetPath);
|
|
||||||
QSaveFile vfile1(targetPath);
|
|
||||||
if (!vfile1.open(QIODevice::Truncate | QIODevice::WriteOnly))
|
|
||||||
{
|
|
||||||
emitFailed(tr("Can't open %1 for writing.").arg(targetPath));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
qint64 actual = 0;
|
|
||||||
if ((actual = vfile1.write(newdata)) != newdata.size())
|
|
||||||
{
|
|
||||||
emitFailed(tr("Failed to write into %1. Written %2 out of %3.")
|
|
||||||
.arg(targetPath)
|
|
||||||
.arg(actual)
|
|
||||||
.arg(newdata.size()));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (!vfile1.commit())
|
|
||||||
{
|
|
||||||
emitFailed(tr("Can't commit changes to %1").arg(targetPath));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
m_list->finalizeUpdate(id);
|
|
||||||
emitSucceeded();
|
|
||||||
}
|
|
||||||
|
|
||||||
std::shared_ptr<Task> MinecraftVersionList::createUpdateTask(QString version)
|
|
||||||
{
|
|
||||||
auto iter = m_lookup.find(version);
|
|
||||||
if(iter == m_lookup.end())
|
|
||||||
return nullptr;
|
|
||||||
|
|
||||||
auto mcversion = std::dynamic_pointer_cast<MinecraftVersion>(*iter);
|
|
||||||
if(!mcversion)
|
|
||||||
{
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
return std::shared_ptr<Task>(new MCVListVersionUpdateTask(this, mcversion));
|
|
||||||
}
|
|
||||||
|
|
||||||
void MinecraftVersionList::saveCachedList()
|
|
||||||
{
|
|
||||||
// FIXME: throw.
|
|
||||||
if (!FS::ensureFilePathExists(localVersionCache))
|
|
||||||
return;
|
|
||||||
QSaveFile tfile(localVersionCache);
|
|
||||||
if (!tfile.open(QIODevice::WriteOnly | QIODevice::Truncate))
|
|
||||||
return;
|
|
||||||
QJsonObject toplevel;
|
|
||||||
QJsonArray entriesArr;
|
|
||||||
for (auto version : m_vlist)
|
|
||||||
{
|
|
||||||
auto mcversion = std::dynamic_pointer_cast<MinecraftVersion>(version);
|
|
||||||
// do not save the remote versions.
|
|
||||||
if (mcversion->m_versionSource != VersionSource::Local)
|
|
||||||
continue;
|
|
||||||
QJsonObject entryObj;
|
|
||||||
|
|
||||||
entryObj.insert("id", mcversion->descriptor());
|
|
||||||
entryObj.insert("version", mcversion->descriptor());
|
|
||||||
entryObj.insert("time", timeToS3Time(mcversion->m_updateTime));
|
|
||||||
entryObj.insert("releaseTime", timeToS3Time(mcversion->m_releaseTime));
|
|
||||||
entryObj.insert("url", mcversion->m_versionFileURL);
|
|
||||||
entryObj.insert("type", mcversion->m_type);
|
|
||||||
entriesArr.append(entryObj);
|
|
||||||
}
|
|
||||||
toplevel.insert("versions", entriesArr);
|
|
||||||
|
|
||||||
{
|
|
||||||
bool someLatest = false;
|
|
||||||
QJsonObject latestObj;
|
|
||||||
if(!m_latestReleaseID.isNull())
|
|
||||||
{
|
|
||||||
latestObj.insert("release", m_latestReleaseID);
|
|
||||||
someLatest = true;
|
|
||||||
}
|
|
||||||
if(!m_latestSnapshotID.isNull())
|
|
||||||
{
|
|
||||||
latestObj.insert("snapshot", m_latestSnapshotID);
|
|
||||||
someLatest = true;
|
|
||||||
}
|
|
||||||
if(someLatest)
|
|
||||||
{
|
|
||||||
toplevel.insert("latest", latestObj);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
QJsonDocument doc(toplevel);
|
|
||||||
QByteArray jsonData = doc.toBinaryData();
|
|
||||||
qint64 result = tfile.write(jsonData);
|
|
||||||
if (result == -1)
|
|
||||||
return;
|
|
||||||
if (result != jsonData.size())
|
|
||||||
return;
|
|
||||||
tfile.commit();
|
|
||||||
}
|
|
||||||
|
|
||||||
void MinecraftVersionList::finalizeUpdate(QString version)
|
|
||||||
{
|
|
||||||
int idx = -1;
|
|
||||||
for (int i = 0; i < m_vlist.size(); i++)
|
|
||||||
{
|
|
||||||
if (version == m_vlist[i]->descriptor())
|
|
||||||
{
|
|
||||||
idx = i;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (idx == -1)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto updatedVersion = std::dynamic_pointer_cast<MinecraftVersion>(m_vlist[idx]);
|
|
||||||
|
|
||||||
// reject any updates to builtin versions.
|
|
||||||
if (updatedVersion->m_versionSource == VersionSource::Builtin)
|
|
||||||
return;
|
|
||||||
|
|
||||||
// if we have an update for the version, replace it, make the update local
|
|
||||||
if (updatedVersion->upstreamUpdate)
|
|
||||||
{
|
|
||||||
auto updatedWith = updatedVersion->upstreamUpdate;
|
|
||||||
updatedWith->m_versionSource = VersionSource::Local;
|
|
||||||
m_vlist[idx] = updatedWith;
|
|
||||||
m_lookup[version] = updatedWith;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// otherwise, just set the version as local;
|
|
||||||
updatedVersion->m_versionSource = VersionSource::Local;
|
|
||||||
}
|
|
||||||
|
|
||||||
dataChanged(index(idx), index(idx));
|
|
||||||
|
|
||||||
saveCachedList();
|
|
||||||
}
|
|
||||||
|
|
||||||
#include "MinecraftVersionList.moc"
|
|
@ -1,73 +0,0 @@
|
|||||||
/* Copyright 2013-2017 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 <QObject>
|
|
||||||
#include <QList>
|
|
||||||
#include <QSet>
|
|
||||||
|
|
||||||
#include "BaseVersionList.h"
|
|
||||||
#include "tasks/Task.h"
|
|
||||||
#include "minecraft/MinecraftVersion.h"
|
|
||||||
#include <net/NetJob.h>
|
|
||||||
|
|
||||||
#include "multimc_logic_export.h"
|
|
||||||
|
|
||||||
class MCVListLoadTask;
|
|
||||||
class MCVListVersionUpdateTask;
|
|
||||||
|
|
||||||
class MULTIMC_LOGIC_EXPORT MinecraftVersionList : public BaseVersionList
|
|
||||||
{
|
|
||||||
Q_OBJECT
|
|
||||||
private:
|
|
||||||
void sortInternal();
|
|
||||||
void loadBuiltinList();
|
|
||||||
void loadMojangList(QJsonDocument jsonDoc, VersionSource source);
|
|
||||||
void loadCachedList();
|
|
||||||
void saveCachedList();
|
|
||||||
void finalizeUpdate(QString version);
|
|
||||||
public:
|
|
||||||
friend class MCVListLoadTask;
|
|
||||||
friend class MCVListVersionUpdateTask;
|
|
||||||
|
|
||||||
explicit MinecraftVersionList(QObject *parent = 0);
|
|
||||||
|
|
||||||
std::shared_ptr<Task> createUpdateTask(QString version);
|
|
||||||
|
|
||||||
virtual Task *getLoadTask() override;
|
|
||||||
virtual bool isLoaded() override;
|
|
||||||
virtual const BaseVersionPtr at(int i) const override;
|
|
||||||
virtual int count() const override;
|
|
||||||
virtual void sortVersions() override;
|
|
||||||
virtual QVariant data(const QModelIndex & index, int role) const override;
|
|
||||||
virtual RoleList providesRoles() const override;
|
|
||||||
|
|
||||||
virtual BaseVersionPtr getLatestStable() const override;
|
|
||||||
virtual BaseVersionPtr getRecommended() const override;
|
|
||||||
|
|
||||||
protected:
|
|
||||||
QList<BaseVersionPtr> m_vlist;
|
|
||||||
QMap<QString, BaseVersionPtr> m_lookup;
|
|
||||||
|
|
||||||
bool m_loaded = false;
|
|
||||||
bool m_hasLocalIndex = false;
|
|
||||||
QString m_latestReleaseID = "INVALID";
|
|
||||||
QString m_latestSnapshotID = "INVALID";
|
|
||||||
|
|
||||||
protected
|
|
||||||
slots:
|
|
||||||
virtual void updateListData(QList<BaseVersionPtr> versions) override;
|
|
||||||
};
|
|
@ -1,6 +1,5 @@
|
|||||||
#include "MojangVersionFormat.h"
|
#include "MojangVersionFormat.h"
|
||||||
#include "onesix/OneSixVersionFormat.h"
|
#include "onesix/OneSixVersionFormat.h"
|
||||||
#include "MinecraftVersion.h"
|
|
||||||
#include "VersionBuildError.h"
|
#include "VersionBuildError.h"
|
||||||
#include "MojangDownloadInfo.h"
|
#include "MojangDownloadInfo.h"
|
||||||
|
|
||||||
@ -152,7 +151,7 @@ void MojangVersionFormat::readVersionProperties(const QJsonObject &in, VersionFi
|
|||||||
}
|
}
|
||||||
else if (!toCompare.isEmpty())
|
else if (!toCompare.isEmpty())
|
||||||
{
|
{
|
||||||
out->addProblem(PROBLEM_ERROR, QObject::tr("processArguments is set to unknown value '%1'").arg(processArguments));
|
out->addProblem(ProblemSeverity::Error, QObject::tr("processArguments is set to unknown value '%1'").arg(processArguments));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Bits::readString(in, "type", out->type);
|
Bits::readString(in, "type", out->type);
|
||||||
@ -167,8 +166,8 @@ void MojangVersionFormat::readVersionProperties(const QJsonObject &in, VersionFi
|
|||||||
out->mojangAssetIndex = std::make_shared<MojangAssetIndexInfo>(out->assets);
|
out->mojangAssetIndex = std::make_shared<MojangAssetIndexInfo>(out->assets);
|
||||||
}
|
}
|
||||||
|
|
||||||
out->m_releaseTime = timeFromS3Time(in.value("releaseTime").toString(""));
|
out->releaseTime = timeFromS3Time(in.value("releaseTime").toString(""));
|
||||||
out->m_updateTime = timeFromS3Time(in.value("time").toString(""));
|
out->updateTime = timeFromS3Time(in.value("time").toString(""));
|
||||||
|
|
||||||
if (in.contains("minimumLauncherVersion"))
|
if (in.contains("minimumLauncherVersion"))
|
||||||
{
|
{
|
||||||
@ -176,7 +175,7 @@ void MojangVersionFormat::readVersionProperties(const QJsonObject &in, VersionFi
|
|||||||
if (out->minimumLauncherVersion > CURRENT_MINIMUM_LAUNCHER_VERSION)
|
if (out->minimumLauncherVersion > CURRENT_MINIMUM_LAUNCHER_VERSION)
|
||||||
{
|
{
|
||||||
out->addProblem(
|
out->addProblem(
|
||||||
PROBLEM_WARNING,
|
ProblemSeverity::Warning,
|
||||||
QObject::tr("The 'minimumLauncherVersion' value of this version (%1) is higher than supported by MultiMC (%2). It might not work properly!")
|
QObject::tr("The 'minimumLauncherVersion' value of this version (%1) is higher than supported by MultiMC (%2). It might not work properly!")
|
||||||
.arg(out->minimumLauncherVersion)
|
.arg(out->minimumLauncherVersion)
|
||||||
.arg(CURRENT_MINIMUM_LAUNCHER_VERSION));
|
.arg(CURRENT_MINIMUM_LAUNCHER_VERSION));
|
||||||
@ -211,9 +210,9 @@ VersionFilePtr MojangVersionFormat::versionFileFromJson(const QJsonDocument &doc
|
|||||||
readVersionProperties(root, out.get());
|
readVersionProperties(root, out.get());
|
||||||
|
|
||||||
out->name = "Minecraft";
|
out->name = "Minecraft";
|
||||||
out->fileId = "net.minecraft";
|
out->uid = "net.minecraft";
|
||||||
out->version = out->minecraftVersion;
|
out->version = out->minecraftVersion;
|
||||||
out->filename = filename;
|
// out->filename = filename;
|
||||||
|
|
||||||
|
|
||||||
if (root.contains("libraries"))
|
if (root.contains("libraries"))
|
||||||
@ -235,13 +234,13 @@ void MojangVersionFormat::writeVersionProperties(const VersionFile* in, QJsonObj
|
|||||||
writeString(out, "mainClass", in->mainClass);
|
writeString(out, "mainClass", in->mainClass);
|
||||||
writeString(out, "minecraftArguments", in->minecraftArguments);
|
writeString(out, "minecraftArguments", in->minecraftArguments);
|
||||||
writeString(out, "type", in->type);
|
writeString(out, "type", in->type);
|
||||||
if(!in->m_releaseTime.isNull())
|
if(!in->releaseTime.isNull())
|
||||||
{
|
{
|
||||||
writeString(out, "releaseTime", timeToS3Time(in->m_releaseTime));
|
writeString(out, "releaseTime", timeToS3Time(in->releaseTime));
|
||||||
}
|
}
|
||||||
if(!in->m_updateTime.isNull())
|
if(!in->updateTime.isNull())
|
||||||
{
|
{
|
||||||
writeString(out, "time", timeToS3Time(in->m_updateTime));
|
writeString(out, "time", timeToS3Time(in->updateTime));
|
||||||
}
|
}
|
||||||
if(in->minimumLauncherVersion != -1)
|
if(in->minimumLauncherVersion != -1)
|
||||||
{
|
{
|
||||||
|
175
api/logic/minecraft/ProfilePatch.cpp
Normal file
175
api/logic/minecraft/ProfilePatch.cpp
Normal file
@ -0,0 +1,175 @@
|
|||||||
|
#include <meta/VersionList.h>
|
||||||
|
#include <meta/Index.h>
|
||||||
|
#include <Env.h>
|
||||||
|
#include "ProfilePatch.h"
|
||||||
|
|
||||||
|
#include "meta/Version.h"
|
||||||
|
#include "VersionFile.h"
|
||||||
|
|
||||||
|
ProfilePatch::ProfilePatch(std::shared_ptr<Meta::Version> version)
|
||||||
|
:m_metaVersion(version)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
ProfilePatch::ProfilePatch(std::shared_ptr<VersionFile> file, const QString& filename)
|
||||||
|
:m_file(file), m_filename(filename)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void ProfilePatch::applyTo(MinecraftProfile* profile)
|
||||||
|
{
|
||||||
|
auto vfile = getVersionFile();
|
||||||
|
if(vfile)
|
||||||
|
{
|
||||||
|
vfile->applyTo(profile);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::shared_ptr<class VersionFile> ProfilePatch::getVersionFile()
|
||||||
|
{
|
||||||
|
if(m_metaVersion)
|
||||||
|
{
|
||||||
|
if(!m_metaVersion->isLoaded())
|
||||||
|
{
|
||||||
|
m_metaVersion->load();
|
||||||
|
}
|
||||||
|
return m_metaVersion->data();
|
||||||
|
}
|
||||||
|
return m_file;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::shared_ptr<class Meta::VersionList> ProfilePatch::getVersionList()
|
||||||
|
{
|
||||||
|
if(m_metaVersion)
|
||||||
|
{
|
||||||
|
return ENV.metadataIndex()->get(m_metaVersion->uid());
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
int ProfilePatch::getOrder()
|
||||||
|
{
|
||||||
|
if(m_orderOverride)
|
||||||
|
return m_order;
|
||||||
|
|
||||||
|
auto vfile = getVersionFile();
|
||||||
|
if(vfile)
|
||||||
|
{
|
||||||
|
return vfile->order;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
void ProfilePatch::setOrder(int order)
|
||||||
|
{
|
||||||
|
m_orderOverride = true;
|
||||||
|
m_order = order;
|
||||||
|
}
|
||||||
|
QString ProfilePatch::getID()
|
||||||
|
{
|
||||||
|
if(m_metaVersion)
|
||||||
|
return m_metaVersion->uid();
|
||||||
|
return getVersionFile()->uid;
|
||||||
|
}
|
||||||
|
QString ProfilePatch::getName()
|
||||||
|
{
|
||||||
|
if(m_metaVersion)
|
||||||
|
return m_metaVersion->name();
|
||||||
|
return getVersionFile()->name;
|
||||||
|
}
|
||||||
|
QString ProfilePatch::getVersion()
|
||||||
|
{
|
||||||
|
if(m_metaVersion)
|
||||||
|
return m_metaVersion->version();
|
||||||
|
return getVersionFile()->version;
|
||||||
|
}
|
||||||
|
QString ProfilePatch::getFilename()
|
||||||
|
{
|
||||||
|
return m_filename;
|
||||||
|
}
|
||||||
|
QDateTime ProfilePatch::getReleaseDateTime()
|
||||||
|
{
|
||||||
|
if(m_metaVersion)
|
||||||
|
{
|
||||||
|
return m_metaVersion->time();
|
||||||
|
}
|
||||||
|
return getVersionFile()->releaseTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ProfilePatch::isCustom()
|
||||||
|
{
|
||||||
|
return !m_isVanilla;
|
||||||
|
};
|
||||||
|
|
||||||
|
bool ProfilePatch::isCustomizable()
|
||||||
|
{
|
||||||
|
if(m_metaVersion)
|
||||||
|
{
|
||||||
|
if(getVersionFile())
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
bool ProfilePatch::isRemovable()
|
||||||
|
{
|
||||||
|
return m_isRemovable;
|
||||||
|
}
|
||||||
|
bool ProfilePatch::isRevertible()
|
||||||
|
{
|
||||||
|
return m_isRevertible;
|
||||||
|
}
|
||||||
|
bool ProfilePatch::isMoveable()
|
||||||
|
{
|
||||||
|
return m_isMovable;
|
||||||
|
}
|
||||||
|
bool ProfilePatch::isVersionChangeable()
|
||||||
|
{
|
||||||
|
auto list = getVersionList();
|
||||||
|
if(list)
|
||||||
|
{
|
||||||
|
if(!list->isLoaded())
|
||||||
|
{
|
||||||
|
list->load();
|
||||||
|
}
|
||||||
|
return list->count() != 0;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ProfilePatch::setVanilla (bool state)
|
||||||
|
{
|
||||||
|
m_isVanilla = state;
|
||||||
|
}
|
||||||
|
void ProfilePatch::setRemovable (bool state)
|
||||||
|
{
|
||||||
|
m_isRemovable = state;
|
||||||
|
}
|
||||||
|
void ProfilePatch::setRevertible (bool state)
|
||||||
|
{
|
||||||
|
m_isRevertible = state;
|
||||||
|
}
|
||||||
|
void ProfilePatch::setMovable (bool state)
|
||||||
|
{
|
||||||
|
m_isMovable = state;
|
||||||
|
}
|
||||||
|
|
||||||
|
ProblemSeverity ProfilePatch::getProblemSeverity()
|
||||||
|
{
|
||||||
|
auto file = getVersionFile();
|
||||||
|
if(file)
|
||||||
|
{
|
||||||
|
return file->getProblemSeverity();
|
||||||
|
}
|
||||||
|
return ProblemSeverity::Error;
|
||||||
|
}
|
||||||
|
|
||||||
|
const QList<PatchProblem> ProfilePatch::getProblems()
|
||||||
|
{
|
||||||
|
auto file = getVersionFile();
|
||||||
|
if(file)
|
||||||
|
{
|
||||||
|
return file->getProblems();
|
||||||
|
}
|
||||||
|
return {PatchProblem(ProblemSeverity::Error, QObject::tr("Patch is not loaded yet."))};
|
||||||
|
}
|
@ -5,101 +5,67 @@
|
|||||||
#include <QJsonDocument>
|
#include <QJsonDocument>
|
||||||
#include <QDateTime>
|
#include <QDateTime>
|
||||||
#include "JarMod.h"
|
#include "JarMod.h"
|
||||||
|
#include "ProblemProvider.h"
|
||||||
|
|
||||||
class MinecraftProfile;
|
class MinecraftProfile;
|
||||||
|
namespace Meta
|
||||||
enum ProblemSeverity
|
|
||||||
{
|
{
|
||||||
PROBLEM_NONE,
|
class Version;
|
||||||
PROBLEM_WARNING,
|
class VersionList;
|
||||||
PROBLEM_ERROR
|
}
|
||||||
};
|
class VersionFile;
|
||||||
|
|
||||||
/// where is a version from?
|
class ProfilePatch : public ProblemProvider
|
||||||
enum class VersionSource
|
|
||||||
{
|
|
||||||
Builtin, //!< version loaded from the internal resources.
|
|
||||||
Local, //!< version loaded from a file in the cache.
|
|
||||||
Remote, //!< incomplete version on a remote server.
|
|
||||||
};
|
|
||||||
|
|
||||||
class PatchProblem
|
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
PatchProblem(ProblemSeverity severity, const QString & description)
|
ProfilePatch(std::shared_ptr<Meta::Version> version);
|
||||||
{
|
ProfilePatch(std::shared_ptr<VersionFile> file, const QString &filename = QString());
|
||||||
m_severity = severity;
|
|
||||||
m_description = description;
|
|
||||||
}
|
|
||||||
const QString & getDescription() const
|
|
||||||
{
|
|
||||||
return m_description;
|
|
||||||
}
|
|
||||||
const ProblemSeverity getSeverity() const
|
|
||||||
{
|
|
||||||
return m_severity;
|
|
||||||
}
|
|
||||||
private:
|
|
||||||
ProblemSeverity m_severity;
|
|
||||||
QString m_description;
|
|
||||||
};
|
|
||||||
|
|
||||||
class ProfilePatch : public std::enable_shared_from_this<ProfilePatch>
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
virtual ~ProfilePatch(){};
|
virtual ~ProfilePatch(){};
|
||||||
virtual void applyTo(MinecraftProfile *profile) = 0;
|
virtual void applyTo(MinecraftProfile *profile);
|
||||||
|
|
||||||
virtual bool isMinecraftVersion() = 0;
|
virtual bool isMoveable();
|
||||||
virtual bool hasJarMods() = 0;
|
virtual bool isCustomizable();
|
||||||
virtual QList<JarmodPtr> getJarMods() = 0;
|
virtual bool isRevertible();
|
||||||
|
virtual bool isRemovable();
|
||||||
|
virtual bool isCustom();
|
||||||
|
virtual bool isVersionChangeable();
|
||||||
|
|
||||||
virtual bool isMoveable() = 0;
|
virtual void setOrder(int order);
|
||||||
virtual bool isCustomizable() = 0;
|
virtual int getOrder();
|
||||||
virtual bool isRevertible() = 0;
|
|
||||||
virtual bool isRemovable() = 0;
|
|
||||||
virtual bool isCustom() = 0;
|
|
||||||
virtual bool isEditable() = 0;
|
|
||||||
virtual bool isVersionChangeable() = 0;
|
|
||||||
|
|
||||||
virtual void setOrder(int order) = 0;
|
virtual QString getID();
|
||||||
virtual int getOrder() = 0;
|
virtual QString getName();
|
||||||
|
virtual QString getVersion();
|
||||||
|
virtual QDateTime getReleaseDateTime();
|
||||||
|
|
||||||
virtual QString getID() = 0;
|
virtual QString getFilename();
|
||||||
virtual QString getName() = 0;
|
|
||||||
virtual QString getVersion() = 0;
|
|
||||||
virtual QDateTime getReleaseDateTime() = 0;
|
|
||||||
|
|
||||||
virtual QString getFilename() = 0;
|
virtual std::shared_ptr<class VersionFile> getVersionFile();
|
||||||
|
virtual std::shared_ptr<class Meta::VersionList> getVersionList();
|
||||||
|
|
||||||
virtual VersionSource getVersionSource() = 0;
|
void setVanilla (bool state);
|
||||||
|
void setRemovable (bool state);
|
||||||
|
void setRevertible (bool state);
|
||||||
|
void setMovable (bool state);
|
||||||
|
|
||||||
virtual std::shared_ptr<class VersionFile> getVersionFile() = 0;
|
|
||||||
|
|
||||||
virtual const QList<PatchProblem>& getProblems()
|
const QList<PatchProblem> getProblems() override;
|
||||||
{
|
ProblemSeverity getProblemSeverity() override;
|
||||||
return m_problems;
|
|
||||||
}
|
|
||||||
virtual void addProblem(ProblemSeverity severity, const QString &description)
|
|
||||||
{
|
|
||||||
if(severity > m_problemSeverity)
|
|
||||||
{
|
|
||||||
m_problemSeverity = severity;
|
|
||||||
}
|
|
||||||
m_problems.append(PatchProblem(severity, description));
|
|
||||||
}
|
|
||||||
virtual ProblemSeverity getProblemSeverity()
|
|
||||||
{
|
|
||||||
return m_problemSeverity;
|
|
||||||
}
|
|
||||||
virtual bool hasFailed()
|
|
||||||
{
|
|
||||||
return getProblemSeverity() == PROBLEM_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
QList<PatchProblem> m_problems;
|
// Properties for UI and version manipulation from UI in general
|
||||||
ProblemSeverity m_problemSeverity = PROBLEM_NONE;
|
bool m_isMovable = false;
|
||||||
|
bool m_isRevertible = false;
|
||||||
|
bool m_isRemovable = false;
|
||||||
|
bool m_isVanilla = false;
|
||||||
|
|
||||||
|
bool m_orderOverride = false;
|
||||||
|
int m_order = 0;
|
||||||
|
|
||||||
|
std::shared_ptr<Meta::Version> m_metaVersion;
|
||||||
|
std::shared_ptr<VersionFile> m_file;
|
||||||
|
QString m_filename;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef std::shared_ptr<ProfilePatch> ProfilePatchPtr;
|
typedef std::shared_ptr<ProfilePatch> ProfilePatchPtr;
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "ProfileUtils.h"
|
#include "ProfileUtils.h"
|
||||||
|
#include "ProfilePatch.h"
|
||||||
|
|
||||||
class MinecraftProfile;
|
class MinecraftProfile;
|
||||||
|
|
||||||
|
@ -102,9 +102,9 @@ bool readOverrideOrders(QString path, PatchOrder &order)
|
|||||||
static VersionFilePtr createErrorVersionFile(QString fileId, QString filepath, QString error)
|
static VersionFilePtr createErrorVersionFile(QString fileId, QString filepath, QString error)
|
||||||
{
|
{
|
||||||
auto outError = std::make_shared<VersionFile>();
|
auto outError = std::make_shared<VersionFile>();
|
||||||
outError->fileId = outError->name = fileId;
|
outError->uid = outError->name = fileId;
|
||||||
outError->filename = filepath;
|
// outError->filename = filepath;
|
||||||
outError->addProblem(PROBLEM_ERROR, error);
|
outError->addProblem(ProblemSeverity::Error, error);
|
||||||
return outError;
|
return outError;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -26,23 +26,6 @@ public:
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
|
||||||
* some patch was intended for a different version of minecraft
|
|
||||||
*/
|
|
||||||
class MinecraftVersionMismatch : public VersionBuildError
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
MinecraftVersionMismatch(QString fileId, QString mcVersion, QString parentMcVersion)
|
|
||||||
: VersionBuildError(QObject::tr("The patch %1 is for a different version of Minecraft "
|
|
||||||
"(%2) than that of the instance (%3).")
|
|
||||||
.arg(fileId)
|
|
||||||
.arg(mcVersion)
|
|
||||||
.arg(parentMcVersion)) {};
|
|
||||||
virtual ~MinecraftVersionMismatch() noexcept
|
|
||||||
{
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* files required for the version are not (yet?) present
|
* files required for the version are not (yet?) present
|
||||||
*/
|
*/
|
||||||
|
@ -12,37 +12,28 @@
|
|||||||
#include "VersionBuildError.h"
|
#include "VersionBuildError.h"
|
||||||
#include <Version.h>
|
#include <Version.h>
|
||||||
|
|
||||||
bool VersionFile::isMinecraftVersion()
|
static bool isMinecraftVersion(const QString &uid)
|
||||||
{
|
{
|
||||||
return fileId == "net.minecraft";
|
return uid == "net.minecraft";
|
||||||
}
|
|
||||||
|
|
||||||
bool VersionFile::hasJarMods()
|
|
||||||
{
|
|
||||||
return !jarMods.isEmpty();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void VersionFile::applyTo(MinecraftProfile *profile)
|
void VersionFile::applyTo(MinecraftProfile *profile)
|
||||||
{
|
{
|
||||||
auto theirVersion = profile->getMinecraftVersion();
|
// Only real Minecraft can set those. Don't let anything override them.
|
||||||
if (!theirVersion.isNull() && !dependsOnMinecraftVersion.isNull())
|
if (isMinecraftVersion(uid))
|
||||||
{
|
{
|
||||||
if (QRegExp(dependsOnMinecraftVersion, Qt::CaseInsensitive, QRegExp::Wildcard).indexIn(theirVersion) == -1)
|
|
||||||
{
|
|
||||||
throw MinecraftVersionMismatch(fileId, dependsOnMinecraftVersion, theirVersion);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
profile->applyMinecraftVersion(minecraftVersion);
|
profile->applyMinecraftVersion(minecraftVersion);
|
||||||
|
profile->applyMinecraftVersionType(type);
|
||||||
|
// HACK: ignore assets from other version files than Minecraft
|
||||||
|
// workaround for stupid assets issue caused by amazon:
|
||||||
|
// https://www.theregister.co.uk/2017/02/28/aws_is_awol_as_s3_goes_haywire/
|
||||||
|
profile->applyMinecraftAssets(mojangAssetIndex);
|
||||||
|
}
|
||||||
|
|
||||||
profile->applyMainClass(mainClass);
|
profile->applyMainClass(mainClass);
|
||||||
profile->applyAppletClass(appletClass);
|
profile->applyAppletClass(appletClass);
|
||||||
profile->applyMinecraftArguments(minecraftArguments);
|
profile->applyMinecraftArguments(minecraftArguments);
|
||||||
if (isMinecraftVersion())
|
|
||||||
{
|
|
||||||
profile->applyMinecraftVersionType(type);
|
|
||||||
}
|
|
||||||
profile->applyMinecraftAssets(mojangAssetIndex);
|
|
||||||
profile->applyTweakers(addTweakers);
|
profile->applyTweakers(addTweakers);
|
||||||
|
|
||||||
profile->applyJarMods(jarMods);
|
profile->applyJarMods(jarMods);
|
||||||
profile->applyTraits(traits);
|
profile->applyTraits(traits);
|
||||||
|
|
||||||
@ -58,3 +49,14 @@ void VersionFile::applyTo(MinecraftProfile *profile)
|
|||||||
iter++;
|
iter++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
auto theirVersion = profile->getMinecraftVersion();
|
||||||
|
if (!theirVersion.isNull() && !dependsOnMinecraftVersion.isNull())
|
||||||
|
{
|
||||||
|
if (QRegExp(dependsOnMinecraftVersion, Qt::CaseInsensitive, QRegExp::Wildcard).indexIn(theirVersion) == -1)
|
||||||
|
{
|
||||||
|
throw MinecraftVersionMismatch(uid, dependsOnMinecraftVersion, theirVersion);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*/
|
@ -8,7 +8,7 @@
|
|||||||
#include <memory>
|
#include <memory>
|
||||||
#include "minecraft/OpSys.h"
|
#include "minecraft/OpSys.h"
|
||||||
#include "minecraft/Rule.h"
|
#include "minecraft/Rule.h"
|
||||||
#include "ProfilePatch.h"
|
#include "ProblemProvider.h"
|
||||||
#include "Library.h"
|
#include "Library.h"
|
||||||
#include "JarMod.h"
|
#include "JarMod.h"
|
||||||
|
|
||||||
@ -18,126 +18,25 @@ struct MojangDownloadInfo;
|
|||||||
struct MojangAssetIndexInfo;
|
struct MojangAssetIndexInfo;
|
||||||
|
|
||||||
typedef std::shared_ptr<VersionFile> VersionFilePtr;
|
typedef std::shared_ptr<VersionFile> VersionFilePtr;
|
||||||
class VersionFile : public ProfilePatch
|
class VersionFile : public ProblemContainer
|
||||||
{
|
{
|
||||||
friend class MojangVersionFormat;
|
friend class MojangVersionFormat;
|
||||||
friend class OneSixVersionFormat;
|
friend class OneSixVersionFormat;
|
||||||
public: /* methods */
|
public: /* methods */
|
||||||
virtual void applyTo(MinecraftProfile *profile) override;
|
void applyTo(MinecraftProfile *profile);
|
||||||
virtual bool isMinecraftVersion() override;
|
|
||||||
virtual bool hasJarMods() override;
|
|
||||||
virtual int getOrder() override
|
|
||||||
{
|
|
||||||
return order;
|
|
||||||
}
|
|
||||||
virtual void setOrder(int order) override
|
|
||||||
{
|
|
||||||
this->order = order;
|
|
||||||
}
|
|
||||||
virtual QList<JarmodPtr> getJarMods() override
|
|
||||||
{
|
|
||||||
return jarMods;
|
|
||||||
}
|
|
||||||
virtual QString getID() override
|
|
||||||
{
|
|
||||||
return fileId;
|
|
||||||
}
|
|
||||||
virtual QString getName() override
|
|
||||||
{
|
|
||||||
return name;
|
|
||||||
}
|
|
||||||
virtual QString getVersion() override
|
|
||||||
{
|
|
||||||
return version;
|
|
||||||
}
|
|
||||||
virtual QString getFilename() override
|
|
||||||
{
|
|
||||||
return filename;
|
|
||||||
}
|
|
||||||
virtual QDateTime getReleaseDateTime() override
|
|
||||||
{
|
|
||||||
return m_releaseTime;
|
|
||||||
}
|
|
||||||
VersionSource getVersionSource() override
|
|
||||||
{
|
|
||||||
return VersionSource::Local;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::shared_ptr<class VersionFile> getVersionFile() override
|
|
||||||
{
|
|
||||||
return std::dynamic_pointer_cast<VersionFile>(shared_from_this());
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual bool isCustom() override
|
|
||||||
{
|
|
||||||
return !m_isVanilla;
|
|
||||||
};
|
|
||||||
virtual bool isCustomizable() override
|
|
||||||
{
|
|
||||||
return m_isCustomizable;
|
|
||||||
}
|
|
||||||
virtual bool isRemovable() override
|
|
||||||
{
|
|
||||||
return m_isRemovable;
|
|
||||||
}
|
|
||||||
virtual bool isRevertible() override
|
|
||||||
{
|
|
||||||
return m_isRevertible;
|
|
||||||
}
|
|
||||||
virtual bool isMoveable() override
|
|
||||||
{
|
|
||||||
return m_isMovable;
|
|
||||||
}
|
|
||||||
virtual bool isEditable() override
|
|
||||||
{
|
|
||||||
return isCustom();
|
|
||||||
}
|
|
||||||
virtual bool isVersionChangeable() override
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
void setVanilla (bool state)
|
|
||||||
{
|
|
||||||
m_isVanilla = state;
|
|
||||||
}
|
|
||||||
void setRemovable (bool state)
|
|
||||||
{
|
|
||||||
m_isRemovable = state;
|
|
||||||
}
|
|
||||||
void setRevertible (bool state)
|
|
||||||
{
|
|
||||||
m_isRevertible = state;
|
|
||||||
}
|
|
||||||
void setCustomizable (bool state)
|
|
||||||
{
|
|
||||||
m_isCustomizable = state;
|
|
||||||
}
|
|
||||||
void setMovable (bool state)
|
|
||||||
{
|
|
||||||
m_isMovable = state;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public: /* data */
|
public: /* data */
|
||||||
/// MultiMC: order hint for this version file if no explicit order is set
|
/// MultiMC: order hint for this version file if no explicit order is set
|
||||||
int order = 0;
|
int order = 0;
|
||||||
|
|
||||||
// Flags for UI and version file manipulation in general
|
|
||||||
bool m_isVanilla = false;
|
|
||||||
bool m_isRemovable = false;
|
|
||||||
bool m_isRevertible = false;
|
|
||||||
bool m_isCustomizable = false;
|
|
||||||
bool m_isMovable = false;
|
|
||||||
|
|
||||||
/// MultiMC: filename of the file this was loaded from
|
/// MultiMC: filename of the file this was loaded from
|
||||||
QString filename;
|
// QString filename;
|
||||||
|
|
||||||
/// MultiMC: human readable name of this package
|
/// MultiMC: human readable name of this package
|
||||||
QString name;
|
QString name;
|
||||||
|
|
||||||
/// MultiMC: package ID of this package
|
/// MultiMC: package ID of this package
|
||||||
QString fileId;
|
QString uid;
|
||||||
|
|
||||||
/// MultiMC: version of this package
|
/// MultiMC: version of this package
|
||||||
QString version;
|
QString version;
|
||||||
@ -148,13 +47,13 @@ public: /* data */
|
|||||||
/// Mojang: used to version the Mojang version format
|
/// Mojang: used to version the Mojang version format
|
||||||
int minimumLauncherVersion = -1;
|
int minimumLauncherVersion = -1;
|
||||||
|
|
||||||
/// Mojang: version of Minecraft this is
|
/// Mojang: DEPRECATED version of Minecraft this is
|
||||||
QString minecraftVersion;
|
QString minecraftVersion;
|
||||||
|
|
||||||
/// Mojang: class to launch Minecraft with
|
/// Mojang: class to launch Minecraft with
|
||||||
QString mainClass;
|
QString mainClass;
|
||||||
|
|
||||||
/// MultiMC: DEPRECATED class to launch legacy Minecraft with (ambed in a custom window)
|
/// MultiMC: class to launch legacy Minecraft with (embed in a custom window)
|
||||||
QString appletClass;
|
QString appletClass;
|
||||||
|
|
||||||
/// Mojang: Minecraft launch arguments (may contain placeholders for variable substitution)
|
/// Mojang: Minecraft launch arguments (may contain placeholders for variable substitution)
|
||||||
@ -164,10 +63,10 @@ public: /* data */
|
|||||||
QString type;
|
QString type;
|
||||||
|
|
||||||
/// Mojang: the time this version was actually released by Mojang
|
/// Mojang: the time this version was actually released by Mojang
|
||||||
QDateTime m_releaseTime;
|
QDateTime releaseTime;
|
||||||
|
|
||||||
/// Mojang: the time this version was last updated by Mojang
|
/// Mojang: the time this version was last updated by Mojang
|
||||||
QDateTime m_updateTime;
|
QDateTime updateTime;
|
||||||
|
|
||||||
/// Mojang: DEPRECATED asset group to be used with Minecraft
|
/// Mojang: DEPRECATED asset group to be used with Minecraft
|
||||||
QString assets;
|
QString assets;
|
||||||
@ -191,5 +90,3 @@ public:
|
|||||||
// Mojang: extended asset index download information
|
// Mojang: extended asset index download information
|
||||||
std::shared_ptr<MojangAssetIndexInfo> mojangAssetIndex;
|
std::shared_ptr<MojangAssetIndexInfo> mojangAssetIndex;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -58,18 +58,11 @@ VersionFilterData::VersionFilterData()
|
|||||||
|
|
||||||
// don't use installers for those.
|
// don't use installers for those.
|
||||||
forgeInstallerBlacklist = QSet<QString>({"1.5.2"});
|
forgeInstallerBlacklist = QSet<QString>({"1.5.2"});
|
||||||
// these won't show up in version lists because they are extremely bad and dangerous
|
|
||||||
legacyBlacklist = QSet<QString>({"rd-160052"});
|
// FIXME: remove, used for deciding when core mods should display
|
||||||
/*
|
|
||||||
* nothing older than this will be accepted from Mojang servers
|
|
||||||
* (these versions need to be tested by us first)
|
|
||||||
*/
|
|
||||||
legacyCutoffDate = timeFromS3Time("2013-06-25T15:08:56+02:00");
|
legacyCutoffDate = timeFromS3Time("2013-06-25T15:08:56+02:00");
|
||||||
lwjglWhitelist =
|
lwjglWhitelist =
|
||||||
QSet<QString>{"net.java.jinput:jinput", "net.java.jinput:jinput-platform",
|
QSet<QString>{"net.java.jinput:jinput", "net.java.jinput:jinput-platform",
|
||||||
"net.java.jutils:jutils", "org.lwjgl.lwjgl:lwjgl",
|
"net.java.jutils:jutils", "org.lwjgl.lwjgl:lwjgl",
|
||||||
"org.lwjgl.lwjgl:lwjgl_util", "org.lwjgl.lwjgl:lwjgl-platform"};
|
"org.lwjgl.lwjgl:lwjgl_util", "org.lwjgl.lwjgl:lwjgl-platform"};
|
||||||
|
|
||||||
// Version list magic
|
|
||||||
recommendedMinecraftVersion = "1.7.10";
|
|
||||||
}
|
}
|
||||||
|
@ -20,13 +20,9 @@ struct VersionFilterData
|
|||||||
QMap<QString, QList<FMLlib>> fmlLibsMapping;
|
QMap<QString, QList<FMLlib>> fmlLibsMapping;
|
||||||
// set of minecraft versions for which using forge installers is blacklisted
|
// set of minecraft versions for which using forge installers is blacklisted
|
||||||
QSet<QString> forgeInstallerBlacklist;
|
QSet<QString> forgeInstallerBlacklist;
|
||||||
// set of 'legacy' versions that will not show up in the version lists.
|
|
||||||
QSet<QString> legacyBlacklist;
|
|
||||||
// no new versions below this date will be accepted from Mojang servers
|
// no new versions below this date will be accepted from Mojang servers
|
||||||
QDateTime legacyCutoffDate;
|
QDateTime legacyCutoffDate;
|
||||||
// Libraries that belong to LWJGL
|
// Libraries that belong to LWJGL
|
||||||
QSet<QString> lwjglWhitelist;
|
QSet<QString> lwjglWhitelist;
|
||||||
// Currently recommended minecraft version
|
|
||||||
QString recommendedMinecraftVersion;
|
|
||||||
};
|
};
|
||||||
extern VersionFilterData MULTIMC_LOGIC_EXPORT g_VersionFilterData;
|
extern VersionFilterData MULTIMC_LOGIC_EXPORT g_VersionFilterData;
|
||||||
|
@ -1,458 +0,0 @@
|
|||||||
/* Copyright 2013-2017 MultiMC Contributors
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "ForgeInstaller.h"
|
|
||||||
#include "ForgeVersionList.h"
|
|
||||||
|
|
||||||
#include "minecraft/MinecraftProfile.h"
|
|
||||||
#include "minecraft/GradleSpecifier.h"
|
|
||||||
#include "net/HttpMetaCache.h"
|
|
||||||
#include "tasks/Task.h"
|
|
||||||
#include "minecraft/onesix/OneSixInstance.h"
|
|
||||||
#include <minecraft/onesix/OneSixVersionFormat.h>
|
|
||||||
#include "minecraft/VersionFilterData.h"
|
|
||||||
#include "minecraft/MinecraftVersion.h"
|
|
||||||
#include "Env.h"
|
|
||||||
#include "Exception.h"
|
|
||||||
#include <FileSystem.h>
|
|
||||||
|
|
||||||
#include <quazip.h>
|
|
||||||
#include <quazipfile.h>
|
|
||||||
#include <QStringList>
|
|
||||||
#include <QRegularExpression>
|
|
||||||
#include <QRegularExpressionMatch>
|
|
||||||
|
|
||||||
#include <QJsonDocument>
|
|
||||||
#include <QJsonArray>
|
|
||||||
#include <QSaveFile>
|
|
||||||
#include <QCryptographicHash>
|
|
||||||
|
|
||||||
ForgeInstaller::ForgeInstaller() : BaseInstaller()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void ForgeInstaller::prepare(const QString &filename, const QString &universalUrl)
|
|
||||||
{
|
|
||||||
VersionFilePtr newVersion;
|
|
||||||
m_universal_url = universalUrl;
|
|
||||||
|
|
||||||
QuaZip zip(filename);
|
|
||||||
if (!zip.open(QuaZip::mdUnzip))
|
|
||||||
return;
|
|
||||||
|
|
||||||
QuaZipFile file(&zip);
|
|
||||||
|
|
||||||
// read the install profile
|
|
||||||
if (!zip.setCurrentFile("install_profile.json"))
|
|
||||||
return;
|
|
||||||
|
|
||||||
QJsonParseError jsonError;
|
|
||||||
if (!file.open(QIODevice::ReadOnly))
|
|
||||||
return;
|
|
||||||
QJsonDocument jsonDoc = QJsonDocument::fromJson(file.readAll(), &jsonError);
|
|
||||||
file.close();
|
|
||||||
if (jsonError.error != QJsonParseError::NoError)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (!jsonDoc.isObject())
|
|
||||||
return;
|
|
||||||
|
|
||||||
QJsonObject root = jsonDoc.object();
|
|
||||||
|
|
||||||
auto installVal = root.value("install");
|
|
||||||
auto versionInfoVal = root.value("versionInfo");
|
|
||||||
if (!installVal.isObject() || !versionInfoVal.isObject())
|
|
||||||
return;
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
newVersion = OneSixVersionFormat::versionFileFromJson(QJsonDocument(versionInfoVal.toObject()), QString(), false);
|
|
||||||
}
|
|
||||||
catch(Exception &err)
|
|
||||||
{
|
|
||||||
qWarning() << "Forge: Fatal error while parsing version file:" << err.what();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
for(auto problem: newVersion->getProblems())
|
|
||||||
{
|
|
||||||
qWarning() << "Forge: Problem found: " << problem.getDescription();
|
|
||||||
}
|
|
||||||
if(newVersion->getProblemSeverity() == ProblemSeverity::PROBLEM_ERROR)
|
|
||||||
{
|
|
||||||
qWarning() << "Forge: Errors found while parsing version file";
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
QJsonObject installObj = installVal.toObject();
|
|
||||||
QString libraryName = installObj.value("path").toString();
|
|
||||||
internalPath = installObj.value("filePath").toString();
|
|
||||||
m_forgeVersionString = installObj.value("version").toString().remove("Forge", Qt::CaseInsensitive).trimmed();
|
|
||||||
|
|
||||||
// where do we put the library? decode the mojang path
|
|
||||||
GradleSpecifier lib(libraryName);
|
|
||||||
|
|
||||||
auto cacheentry = ENV.metacache()->resolveEntry("libraries", lib.toPath());
|
|
||||||
finalPath = "libraries/" + lib.toPath();
|
|
||||||
if (!FS::ensureFilePathExists(finalPath))
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (!zip.setCurrentFile(internalPath))
|
|
||||||
return;
|
|
||||||
if (!file.open(QIODevice::ReadOnly))
|
|
||||||
return;
|
|
||||||
{
|
|
||||||
QByteArray data = file.readAll();
|
|
||||||
// extract file
|
|
||||||
QSaveFile extraction(finalPath);
|
|
||||||
if (!extraction.open(QIODevice::WriteOnly))
|
|
||||||
return;
|
|
||||||
if (extraction.write(data) != data.size())
|
|
||||||
return;
|
|
||||||
if (!extraction.commit())
|
|
||||||
return;
|
|
||||||
QCryptographicHash md5sum(QCryptographicHash::Md5);
|
|
||||||
md5sum.addData(data);
|
|
||||||
|
|
||||||
cacheentry->setStale(false);
|
|
||||||
cacheentry->setMD5Sum(md5sum.result().toHex().constData());
|
|
||||||
ENV.metacache()->updateEntry(cacheentry);
|
|
||||||
}
|
|
||||||
file.close();
|
|
||||||
|
|
||||||
m_forge_json = newVersion;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ForgeInstaller::add(OneSixInstance *to)
|
|
||||||
{
|
|
||||||
if (!BaseInstaller::add(to))
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!m_forge_json)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// A blacklist
|
|
||||||
QSet<QString> blacklist{"authlib", "realms"};
|
|
||||||
QList<QString> xzlist{"org.scala-lang", "com.typesafe"};
|
|
||||||
|
|
||||||
// get the minecraft version from the instance
|
|
||||||
VersionFilePtr minecraft;
|
|
||||||
auto minecraftPatch = to->getMinecraftProfile()->versionPatch("net.minecraft");
|
|
||||||
if(minecraftPatch)
|
|
||||||
{
|
|
||||||
minecraft = std::dynamic_pointer_cast<VersionFile>(minecraftPatch);
|
|
||||||
if(!minecraft)
|
|
||||||
{
|
|
||||||
auto mcWrap = std::dynamic_pointer_cast<MinecraftVersion>(minecraftPatch);
|
|
||||||
if(mcWrap)
|
|
||||||
{
|
|
||||||
minecraft = mcWrap->getVersionFile();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// for each library in the version we are adding (except for the blacklisted)
|
|
||||||
QMutableListIterator<LibraryPtr> iter(m_forge_json->libraries);
|
|
||||||
while (iter.hasNext())
|
|
||||||
{
|
|
||||||
auto library = iter.next();
|
|
||||||
QString libName = library->artifactId();
|
|
||||||
QString libVersion = library->version();
|
|
||||||
QString rawName = library->rawName();
|
|
||||||
|
|
||||||
// ignore lwjgl libraries.
|
|
||||||
if (g_VersionFilterData.lwjglWhitelist.contains(library->artifactPrefix()))
|
|
||||||
{
|
|
||||||
iter.remove();
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
// ignore other blacklisted (realms, authlib)
|
|
||||||
if (blacklist.contains(libName))
|
|
||||||
{
|
|
||||||
iter.remove();
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
// if minecraft version was found, ignore everything that is already in the minecraft version
|
|
||||||
if(minecraft)
|
|
||||||
{
|
|
||||||
bool found = false;
|
|
||||||
for (auto & lib: minecraft->libraries)
|
|
||||||
{
|
|
||||||
if(library->artifactPrefix() == lib->artifactPrefix() && library->version() == lib->version())
|
|
||||||
{
|
|
||||||
found = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (found)
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// if this is the actual forge lib, set an absolute url for the download
|
|
||||||
if (m_forge_version->type == ForgeVersion::Gradle)
|
|
||||||
{
|
|
||||||
if (libName == "forge")
|
|
||||||
{
|
|
||||||
library->setClassifier("universal");
|
|
||||||
}
|
|
||||||
else if (libName == "minecraftforge")
|
|
||||||
{
|
|
||||||
QString forgeCoord("net.minecraftforge:forge:%1:universal");
|
|
||||||
// using insane form of the MC version...
|
|
||||||
QString longVersion = m_forge_version->mcver + "-" + m_forge_version->jobbuildver;
|
|
||||||
GradleSpecifier spec(forgeCoord.arg(longVersion));
|
|
||||||
library->setRawName(spec);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (libName.contains("minecraftforge"))
|
|
||||||
{
|
|
||||||
library->setAbsoluteUrl(m_universal_url);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// mark bad libraries based on the xzlist above
|
|
||||||
for (auto entry : xzlist)
|
|
||||||
{
|
|
||||||
qDebug() << "Testing " << rawName << " : " << entry;
|
|
||||||
if (rawName.startsWith(entry))
|
|
||||||
{
|
|
||||||
library->setHint("forge-pack-xz");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
QString &args = m_forge_json->minecraftArguments;
|
|
||||||
QStringList tweakers;
|
|
||||||
{
|
|
||||||
QRegularExpression expression("--tweakClass ([a-zA-Z0-9\\.]*)");
|
|
||||||
QRegularExpressionMatch match = expression.match(args);
|
|
||||||
while (match.hasMatch())
|
|
||||||
{
|
|
||||||
tweakers.append(match.captured(1));
|
|
||||||
args.remove(match.capturedStart(), match.capturedLength());
|
|
||||||
match = expression.match(args);
|
|
||||||
}
|
|
||||||
if(tweakers.size())
|
|
||||||
{
|
|
||||||
args.operator=(args.trimmed());
|
|
||||||
m_forge_json->addTweakers = tweakers;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if(minecraft && args == minecraft->minecraftArguments)
|
|
||||||
{
|
|
||||||
args.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
m_forge_json->name = "Forge";
|
|
||||||
m_forge_json->fileId = id();
|
|
||||||
m_forge_json->version = m_forgeVersionString;
|
|
||||||
m_forge_json->dependsOnMinecraftVersion = to->intendedVersionId();
|
|
||||||
m_forge_json->order = 5;
|
|
||||||
|
|
||||||
// reset some things we do not want to be passed along.
|
|
||||||
m_forge_json->m_releaseTime = QDateTime();
|
|
||||||
m_forge_json->m_updateTime = QDateTime();
|
|
||||||
m_forge_json->minimumLauncherVersion = -1;
|
|
||||||
m_forge_json->type.clear();
|
|
||||||
m_forge_json->minecraftArguments.clear();
|
|
||||||
m_forge_json->minecraftVersion.clear();
|
|
||||||
|
|
||||||
QSaveFile file(filename(to->instanceRoot()));
|
|
||||||
if (!file.open(QFile::WriteOnly))
|
|
||||||
{
|
|
||||||
qCritical() << "Error opening" << file.fileName()
|
|
||||||
<< "for reading:" << file.errorString();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
file.write(OneSixVersionFormat::versionFileToJson(m_forge_json, true).toJson());
|
|
||||||
file.commit();
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ForgeInstaller::addLegacy(OneSixInstance *to)
|
|
||||||
{
|
|
||||||
if (!BaseInstaller::add(to))
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
auto entry = ENV.metacache()->resolveEntry("minecraftforge", m_forge_version->filename());
|
|
||||||
finalPath = FS::PathCombine(to->jarModsDir(), m_forge_version->filename());
|
|
||||||
if (!FS::ensureFilePathExists(finalPath))
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (!QFile::copy(entry->getFullPath(), finalPath))
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
QJsonObject obj;
|
|
||||||
obj.insert("order", 5);
|
|
||||||
{
|
|
||||||
QJsonArray jarmodsPlus;
|
|
||||||
{
|
|
||||||
QJsonObject libObj;
|
|
||||||
libObj.insert("name", m_forge_version->universal_filename);
|
|
||||||
jarmodsPlus.append(libObj);
|
|
||||||
}
|
|
||||||
obj.insert("+jarMods", jarmodsPlus);
|
|
||||||
}
|
|
||||||
|
|
||||||
obj.insert("name", QString("Forge"));
|
|
||||||
obj.insert("fileId", id());
|
|
||||||
obj.insert("version", m_forge_version->jobbuildver);
|
|
||||||
obj.insert("mcVersion", to->intendedVersionId());
|
|
||||||
if (g_VersionFilterData.fmlLibsMapping.contains(m_forge_version->mcver))
|
|
||||||
{
|
|
||||||
QJsonArray traitsPlus;
|
|
||||||
traitsPlus.append(QString("legacyFML"));
|
|
||||||
obj.insert("+traits", traitsPlus);
|
|
||||||
}
|
|
||||||
auto fullversion = to->getMinecraftProfile();
|
|
||||||
fullversion->remove("net.minecraftforge");
|
|
||||||
|
|
||||||
QFile file(filename(to->instanceRoot()));
|
|
||||||
if (!file.open(QFile::WriteOnly))
|
|
||||||
{
|
|
||||||
qCritical() << "Error opening" << file.fileName()
|
|
||||||
<< "for reading:" << file.errorString();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
file.write(QJsonDocument(obj).toJson());
|
|
||||||
file.close();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
class ForgeInstallTask : public Task
|
|
||||||
{
|
|
||||||
Q_OBJECT
|
|
||||||
public:
|
|
||||||
ForgeInstallTask(ForgeInstaller *installer, OneSixInstance *instance,
|
|
||||||
BaseVersionPtr version, QObject *parent = 0)
|
|
||||||
: Task(parent), m_installer(installer), m_instance(instance), m_version(version)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
protected:
|
|
||||||
void executeTask() override
|
|
||||||
{
|
|
||||||
setStatus(tr("Installing Forge..."));
|
|
||||||
ForgeVersionPtr forgeVersion = std::dynamic_pointer_cast<ForgeVersion>(m_version);
|
|
||||||
if (!forgeVersion)
|
|
||||||
{
|
|
||||||
emitFailed(tr("Unknown error occured"));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
prepare(forgeVersion);
|
|
||||||
}
|
|
||||||
void prepare(ForgeVersionPtr forgeVersion)
|
|
||||||
{
|
|
||||||
auto entry = ENV.metacache()->resolveEntry("minecraftforge", forgeVersion->filename());
|
|
||||||
auto installFunction = [this, entry, forgeVersion]()
|
|
||||||
{
|
|
||||||
if (!install(entry, forgeVersion))
|
|
||||||
{
|
|
||||||
qCritical() << "Failure installing Forge";
|
|
||||||
emitFailed(tr("Failure to install Forge"));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
reload();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/*
|
|
||||||
* HACK IF the local non-stale file is too small, mark is as stale
|
|
||||||
*
|
|
||||||
* This fixes some problems with bad files acquired because of unhandled HTTP redirects
|
|
||||||
* in old versions of MultiMC.
|
|
||||||
*/
|
|
||||||
if (!entry->isStale())
|
|
||||||
{
|
|
||||||
QFileInfo localFile(entry->getFullPath());
|
|
||||||
if (localFile.size() <= 0x4000)
|
|
||||||
{
|
|
||||||
entry->setStale(true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (entry->isStale())
|
|
||||||
{
|
|
||||||
NetJob *fjob = new NetJob("Forge download");
|
|
||||||
fjob->addNetAction(Net::Download::makeCached(forgeVersion->url(), entry));
|
|
||||||
connect(fjob, &NetJob::progress, this, &Task::setProgress);
|
|
||||||
connect(fjob, &NetJob::status, this, &Task::setStatus);
|
|
||||||
connect(fjob, &NetJob::failed, [this](QString reason)
|
|
||||||
{ emitFailed(tr("Failure to download Forge:\n%1").arg(reason)); });
|
|
||||||
connect(fjob, &NetJob::succeeded, installFunction);
|
|
||||||
fjob->start();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
installFunction();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
bool install(const std::shared_ptr<MetaEntry> &entry, const ForgeVersionPtr &forgeVersion)
|
|
||||||
{
|
|
||||||
if (forgeVersion->usesInstaller())
|
|
||||||
{
|
|
||||||
QString forgePath = entry->getFullPath();
|
|
||||||
m_installer->prepare(forgePath, forgeVersion->universal_url);
|
|
||||||
return m_installer->add(m_instance);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
return m_installer->addLegacy(m_instance);
|
|
||||||
}
|
|
||||||
void reload()
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
m_instance->reloadProfile();
|
|
||||||
emitSucceeded();
|
|
||||||
}
|
|
||||||
catch (Exception &e)
|
|
||||||
{
|
|
||||||
emitFailed(e.cause());
|
|
||||||
}
|
|
||||||
catch (...)
|
|
||||||
{
|
|
||||||
emitFailed(tr("Failed to load the version description file for reasons unknown."));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
ForgeInstaller *m_installer;
|
|
||||||
OneSixInstance *m_instance;
|
|
||||||
BaseVersionPtr m_version;
|
|
||||||
};
|
|
||||||
|
|
||||||
Task *ForgeInstaller::createInstallTask(OneSixInstance *instance,
|
|
||||||
BaseVersionPtr version, QObject *parent)
|
|
||||||
{
|
|
||||||
if (!version)
|
|
||||||
{
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
m_forge_version = std::dynamic_pointer_cast<ForgeVersion>(version);
|
|
||||||
return new ForgeInstallTask(this, instance, version, parent);
|
|
||||||
}
|
|
||||||
|
|
||||||
#include "ForgeInstaller.moc"
|
|
@ -1,52 +0,0 @@
|
|||||||
/* Copyright 2013-2017 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 "BaseInstaller.h"
|
|
||||||
|
|
||||||
#include <QString>
|
|
||||||
#include <memory>
|
|
||||||
|
|
||||||
#include "multimc_logic_export.h"
|
|
||||||
|
|
||||||
class VersionFile;
|
|
||||||
class ForgeInstallTask;
|
|
||||||
struct ForgeVersion;
|
|
||||||
|
|
||||||
class MULTIMC_LOGIC_EXPORT ForgeInstaller : public BaseInstaller
|
|
||||||
{
|
|
||||||
friend class ForgeInstallTask;
|
|
||||||
public:
|
|
||||||
ForgeInstaller();
|
|
||||||
virtual ~ForgeInstaller(){}
|
|
||||||
virtual Task *createInstallTask(OneSixInstance *instance, BaseVersionPtr version, QObject *parent) override;
|
|
||||||
virtual QString id() const override { return "net.minecraftforge"; }
|
|
||||||
|
|
||||||
protected:
|
|
||||||
void prepare(const QString &filename, const QString &universalUrl);
|
|
||||||
bool add(OneSixInstance *to) override;
|
|
||||||
bool addLegacy(OneSixInstance *to);
|
|
||||||
|
|
||||||
private:
|
|
||||||
// the parsed version json, read from the installer
|
|
||||||
std::shared_ptr<VersionFile> m_forge_json;
|
|
||||||
// the actual forge version
|
|
||||||
std::shared_ptr<ForgeVersion> m_forge_version;
|
|
||||||
QString internalPath;
|
|
||||||
QString finalPath;
|
|
||||||
QString m_forgeVersionString;
|
|
||||||
QString m_universal_url;
|
|
||||||
};
|
|
@ -1,55 +0,0 @@
|
|||||||
#include "ForgeVersion.h"
|
|
||||||
#include "minecraft/VersionFilterData.h"
|
|
||||||
#include <QObject>
|
|
||||||
|
|
||||||
QString ForgeVersion::name()
|
|
||||||
{
|
|
||||||
return "Forge " + jobbuildver;
|
|
||||||
}
|
|
||||||
|
|
||||||
QString ForgeVersion::descriptor()
|
|
||||||
{
|
|
||||||
return universal_filename;
|
|
||||||
}
|
|
||||||
|
|
||||||
QString ForgeVersion::typeString() const
|
|
||||||
{
|
|
||||||
if (is_recommended)
|
|
||||||
return QObject::tr("Recommended");
|
|
||||||
return QString();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ForgeVersion::operator<(BaseVersion &a)
|
|
||||||
{
|
|
||||||
ForgeVersion *pa = dynamic_cast<ForgeVersion *>(&a);
|
|
||||||
if (!pa)
|
|
||||||
return true;
|
|
||||||
return m_buildnr < pa->m_buildnr;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ForgeVersion::operator>(BaseVersion &a)
|
|
||||||
{
|
|
||||||
ForgeVersion *pa = dynamic_cast<ForgeVersion *>(&a);
|
|
||||||
if (!pa)
|
|
||||||
return false;
|
|
||||||
return m_buildnr > pa->m_buildnr;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ForgeVersion::usesInstaller()
|
|
||||||
{
|
|
||||||
if(installer_url.isEmpty())
|
|
||||||
return false;
|
|
||||||
if(g_VersionFilterData.forgeInstallerBlacklist.contains(mcver))
|
|
||||||
return false;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
QString ForgeVersion::filename()
|
|
||||||
{
|
|
||||||
return usesInstaller() ? installer_filename : universal_filename;
|
|
||||||
}
|
|
||||||
|
|
||||||
QString ForgeVersion::url()
|
|
||||||
{
|
|
||||||
return usesInstaller() ? installer_url : universal_url;
|
|
||||||
}
|
|
@ -1,42 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
#include <QString>
|
|
||||||
#include <memory>
|
|
||||||
#include "BaseVersion.h"
|
|
||||||
|
|
||||||
struct ForgeVersion;
|
|
||||||
typedef std::shared_ptr<ForgeVersion> ForgeVersionPtr;
|
|
||||||
|
|
||||||
struct ForgeVersion : public BaseVersion
|
|
||||||
{
|
|
||||||
virtual QString descriptor() override;
|
|
||||||
virtual QString name() override;
|
|
||||||
virtual QString typeString() const override;
|
|
||||||
virtual bool operator<(BaseVersion &a) override;
|
|
||||||
virtual bool operator>(BaseVersion &a) override;
|
|
||||||
|
|
||||||
QString filename();
|
|
||||||
QString url();
|
|
||||||
|
|
||||||
enum
|
|
||||||
{
|
|
||||||
Invalid,
|
|
||||||
Legacy,
|
|
||||||
Gradle
|
|
||||||
} type = Invalid;
|
|
||||||
|
|
||||||
bool usesInstaller();
|
|
||||||
|
|
||||||
int m_buildnr = 0;
|
|
||||||
QString branch;
|
|
||||||
QString universal_url;
|
|
||||||
QString changelog_url;
|
|
||||||
QString installer_url;
|
|
||||||
QString jobbuildver;
|
|
||||||
QString mcver;
|
|
||||||
QString mcver_sane;
|
|
||||||
QString universal_filename;
|
|
||||||
QString installer_filename;
|
|
||||||
bool is_recommended = false;
|
|
||||||
};
|
|
||||||
|
|
||||||
Q_DECLARE_METATYPE(ForgeVersionPtr)
|
|
@ -1,333 +0,0 @@
|
|||||||
/* Copyright 2013-2017 MultiMC Contributors
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "ForgeVersionList.h"
|
|
||||||
#include "ForgeVersion.h"
|
|
||||||
|
|
||||||
#include "net/NetJob.h"
|
|
||||||
#include "net/URLConstants.h"
|
|
||||||
#include "Env.h"
|
|
||||||
|
|
||||||
#include <QtNetwork>
|
|
||||||
#include <QtXml>
|
|
||||||
#include <QRegExp>
|
|
||||||
|
|
||||||
#include <QDebug>
|
|
||||||
|
|
||||||
ForgeVersionList::ForgeVersionList(QObject *parent) : BaseVersionList(parent)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
Task *ForgeVersionList::getLoadTask()
|
|
||||||
{
|
|
||||||
return new ForgeListLoadTask(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ForgeVersionList::isLoaded()
|
|
||||||
{
|
|
||||||
return m_loaded;
|
|
||||||
}
|
|
||||||
|
|
||||||
const BaseVersionPtr ForgeVersionList::at(int i) const
|
|
||||||
{
|
|
||||||
return m_vlist.at(i);
|
|
||||||
}
|
|
||||||
|
|
||||||
int ForgeVersionList::count() const
|
|
||||||
{
|
|
||||||
return m_vlist.count();
|
|
||||||
}
|
|
||||||
|
|
||||||
int ForgeVersionList::columnCount(const QModelIndex &parent) const
|
|
||||||
{
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
QVariant ForgeVersionList::data(const QModelIndex &index, int role) const
|
|
||||||
{
|
|
||||||
if (!index.isValid())
|
|
||||||
return QVariant();
|
|
||||||
|
|
||||||
if (index.row() > count())
|
|
||||||
return QVariant();
|
|
||||||
|
|
||||||
auto version = std::dynamic_pointer_cast<ForgeVersion>(m_vlist[index.row()]);
|
|
||||||
switch (role)
|
|
||||||
{
|
|
||||||
case VersionPointerRole:
|
|
||||||
return qVariantFromValue(m_vlist[index.row()]);
|
|
||||||
|
|
||||||
case VersionRole:
|
|
||||||
return version->name();
|
|
||||||
|
|
||||||
case VersionIdRole:
|
|
||||||
return version->descriptor();
|
|
||||||
|
|
||||||
case ParentGameVersionRole:
|
|
||||||
return version->mcver_sane;
|
|
||||||
|
|
||||||
case RecommendedRole:
|
|
||||||
return version->is_recommended;
|
|
||||||
|
|
||||||
case BranchRole:
|
|
||||||
return version->branch;
|
|
||||||
|
|
||||||
default:
|
|
||||||
return QVariant();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
BaseVersionList::RoleList ForgeVersionList::providesRoles() const
|
|
||||||
{
|
|
||||||
return {VersionPointerRole, VersionRole, VersionIdRole, ParentGameVersionRole, RecommendedRole, BranchRole};
|
|
||||||
}
|
|
||||||
|
|
||||||
BaseVersionPtr ForgeVersionList::getLatestStable() const
|
|
||||||
{
|
|
||||||
return BaseVersionPtr();
|
|
||||||
}
|
|
||||||
|
|
||||||
void ForgeVersionList::updateListData(QList<BaseVersionPtr> versions)
|
|
||||||
{
|
|
||||||
beginResetModel();
|
|
||||||
m_vlist = versions;
|
|
||||||
m_loaded = true;
|
|
||||||
endResetModel();
|
|
||||||
// NOW SORT!!
|
|
||||||
// sort();
|
|
||||||
}
|
|
||||||
|
|
||||||
void ForgeVersionList::sortVersions()
|
|
||||||
{
|
|
||||||
// NO-OP for now
|
|
||||||
}
|
|
||||||
|
|
||||||
ForgeListLoadTask::ForgeListLoadTask(ForgeVersionList *vlist) : Task()
|
|
||||||
{
|
|
||||||
m_list = vlist;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ForgeListLoadTask::executeTask()
|
|
||||||
{
|
|
||||||
setStatus(tr("Fetching Forge version lists..."));
|
|
||||||
auto job = new NetJob("Version index");
|
|
||||||
// we do not care if the version is stale or not.
|
|
||||||
auto forgeListEntry = ENV.metacache()->resolveEntry("minecraftforge", "list.json");
|
|
||||||
auto gradleForgeListEntry = ENV.metacache()->resolveEntry("minecraftforge", "json");
|
|
||||||
|
|
||||||
// verify by poking the server.
|
|
||||||
forgeListEntry->setStale(true);
|
|
||||||
gradleForgeListEntry->setStale(true);
|
|
||||||
|
|
||||||
job->addNetAction(listDownload = Net::Download::makeCached(QUrl(URLConstants::FORGE_LEGACY_URL),forgeListEntry));
|
|
||||||
job->addNetAction(gradleListDownload = Net::Download::makeCached(QUrl(URLConstants::FORGE_GRADLE_URL), gradleForgeListEntry));
|
|
||||||
|
|
||||||
connect(listDownload.get(), SIGNAL(failed(int)), SLOT(listFailed()));
|
|
||||||
connect(gradleListDownload.get(), SIGNAL(failed(int)), SLOT(gradleListFailed()));
|
|
||||||
|
|
||||||
listJob.reset(job);
|
|
||||||
connect(listJob.get(), SIGNAL(succeeded()), SLOT(listDownloaded()));
|
|
||||||
connect(listJob.get(), SIGNAL(progress(qint64, qint64)), SIGNAL(progress(qint64, qint64)));
|
|
||||||
listJob->start();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ForgeListLoadTask::abort()
|
|
||||||
{
|
|
||||||
return listJob->abort();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ForgeListLoadTask::parseForgeGradleList(QList<BaseVersionPtr> &out)
|
|
||||||
{
|
|
||||||
QMap<int, std::shared_ptr<ForgeVersion>> lookup;
|
|
||||||
QByteArray data;
|
|
||||||
{
|
|
||||||
auto filename = gradleListDownload->getTargetFilepath();
|
|
||||||
QFile listFile(filename);
|
|
||||||
if (!listFile.open(QIODevice::ReadOnly))
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
data = listFile.readAll();
|
|
||||||
gradleListDownload.reset();
|
|
||||||
}
|
|
||||||
|
|
||||||
QJsonParseError jsonError;
|
|
||||||
QJsonDocument jsonDoc = QJsonDocument::fromJson(data, &jsonError);
|
|
||||||
|
|
||||||
if (jsonError.error != QJsonParseError::NoError)
|
|
||||||
{
|
|
||||||
emitFailed("Error parsing gradle version list JSON:" + jsonError.errorString());
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!jsonDoc.isObject())
|
|
||||||
{
|
|
||||||
emitFailed("Error parsing gradle version list JSON: JSON root is not an object");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
QJsonObject root = jsonDoc.object();
|
|
||||||
|
|
||||||
// we probably could hard code these, but it might still be worth doing it this way
|
|
||||||
const QString webpath = root.value("webpath").toString();
|
|
||||||
const QString artifact = root.value("artifact").toString();
|
|
||||||
|
|
||||||
QJsonObject numbers = root.value("number").toObject();
|
|
||||||
for (auto it = numbers.begin(); it != numbers.end(); ++it)
|
|
||||||
{
|
|
||||||
QJsonObject number = it.value().toObject();
|
|
||||||
std::shared_ptr<ForgeVersion> fVersion(new ForgeVersion());
|
|
||||||
fVersion->m_buildnr = number.value("build").toDouble();
|
|
||||||
if(fVersion->m_buildnr >= 953 && fVersion->m_buildnr <= 965)
|
|
||||||
{
|
|
||||||
qDebug() << fVersion->m_buildnr;
|
|
||||||
}
|
|
||||||
fVersion->jobbuildver = number.value("version").toString();
|
|
||||||
fVersion->branch = number.value("branch").toString("");
|
|
||||||
fVersion->mcver = number.value("mcversion").toString();
|
|
||||||
fVersion->universal_filename = "";
|
|
||||||
fVersion->installer_filename = "";
|
|
||||||
// HACK: here, we fix the minecraft version used by forge.
|
|
||||||
// HACK: this will inevitably break (later)
|
|
||||||
// FIXME: replace with a dictionary
|
|
||||||
fVersion->mcver_sane = fVersion->mcver;
|
|
||||||
fVersion->mcver_sane.replace("_pre", "-pre");
|
|
||||||
|
|
||||||
QString universal_filename, installer_filename;
|
|
||||||
QJsonArray files = number.value("files").toArray();
|
|
||||||
for (auto fIt = files.begin(); fIt != files.end(); ++fIt)
|
|
||||||
{
|
|
||||||
// TODO with gradle we also get checksums, use them
|
|
||||||
QJsonArray file = (*fIt).toArray();
|
|
||||||
if (file.size() < 3)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
QString extension = file.at(0).toString();
|
|
||||||
QString part = file.at(1).toString();
|
|
||||||
QString checksum = file.at(2).toString();
|
|
||||||
|
|
||||||
// insane form of mcver is used here
|
|
||||||
QString longVersion = fVersion->mcver + "-" + fVersion->jobbuildver;
|
|
||||||
if (!fVersion->branch.isEmpty())
|
|
||||||
{
|
|
||||||
longVersion = longVersion + "-" + fVersion->branch;
|
|
||||||
}
|
|
||||||
QString filename = artifact + "-" + longVersion + "-" + part + "." + extension;
|
|
||||||
|
|
||||||
QString url = QString("%1/%2/%3")
|
|
||||||
.arg(webpath)
|
|
||||||
.arg(longVersion)
|
|
||||||
.arg(filename);
|
|
||||||
|
|
||||||
if (part == "installer")
|
|
||||||
{
|
|
||||||
fVersion->installer_url = url;
|
|
||||||
installer_filename = filename;
|
|
||||||
}
|
|
||||||
else if (part == "universal" || part == "client")
|
|
||||||
{
|
|
||||||
fVersion->universal_url = url;
|
|
||||||
universal_filename = filename;
|
|
||||||
}
|
|
||||||
else if (part == "changelog")
|
|
||||||
{
|
|
||||||
fVersion->changelog_url = url;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (fVersion->installer_url.isEmpty() && fVersion->universal_url.isEmpty())
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
fVersion->universal_filename = universal_filename;
|
|
||||||
fVersion->installer_filename = installer_filename;
|
|
||||||
fVersion->type = ForgeVersion::Gradle;
|
|
||||||
out.append(fVersion);
|
|
||||||
lookup[fVersion->m_buildnr] = fVersion;
|
|
||||||
}
|
|
||||||
QJsonObject promos = root.value("promos").toObject();
|
|
||||||
for (auto it = promos.begin(); it != promos.end(); ++it)
|
|
||||||
{
|
|
||||||
QString key = it.key();
|
|
||||||
int build = it.value().toInt();
|
|
||||||
QRegularExpression regexp("^(?<mcversion>[0-9]+(.[0-9]+)*)-(?<label>[a-z]+)$");
|
|
||||||
auto match = regexp.match(key);
|
|
||||||
if(!match.hasMatch())
|
|
||||||
{
|
|
||||||
qDebug() << key << "doesn't match." << "build" << build;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
QString label = match.captured("label");
|
|
||||||
if(label != "recommended")
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
QString mcversion = match.captured("mcversion");
|
|
||||||
qDebug() << "Forge build" << build << "is the" << label << "for Minecraft" << mcversion << QString("<%1>").arg(key);
|
|
||||||
lookup[build]->is_recommended = true;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ForgeListLoadTask::listDownloaded()
|
|
||||||
{
|
|
||||||
QList<BaseVersionPtr> list;
|
|
||||||
bool ret = true;
|
|
||||||
|
|
||||||
if (!parseForgeGradleList(list))
|
|
||||||
{
|
|
||||||
ret = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!ret)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
std::sort(list.begin(), list.end(), [](const BaseVersionPtr & l, const BaseVersionPtr & r)
|
|
||||||
{ return (*l > *r); });
|
|
||||||
|
|
||||||
m_list->updateListData(list);
|
|
||||||
|
|
||||||
emitSucceeded();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ForgeListLoadTask::listFailed()
|
|
||||||
{
|
|
||||||
auto &reply = listDownload->m_reply;
|
|
||||||
if (reply)
|
|
||||||
{
|
|
||||||
qCritical() << "Getting forge version list failed: " << reply->errorString();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
qCritical() << "Getting forge version list failed for reasons unknown.";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void ForgeListLoadTask::gradleListFailed()
|
|
||||||
{
|
|
||||||
auto &reply = gradleListDownload->m_reply;
|
|
||||||
if (reply)
|
|
||||||
{
|
|
||||||
qCritical() << "Getting forge version list failed: " << reply->errorString();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
qCritical() << "Getting forge version list failed for reasons unknown.";
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,90 +0,0 @@
|
|||||||
/* Copyright 2013-2017 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 "ForgeVersion.h"
|
|
||||||
|
|
||||||
#include <QObject>
|
|
||||||
#include <QAbstractListModel>
|
|
||||||
#include <QUrl>
|
|
||||||
#include <QNetworkReply>
|
|
||||||
|
|
||||||
#include "BaseVersionList.h"
|
|
||||||
#include "tasks/Task.h"
|
|
||||||
#include "net/NetJob.h"
|
|
||||||
|
|
||||||
#include "multimc_logic_export.h"
|
|
||||||
|
|
||||||
class MULTIMC_LOGIC_EXPORT ForgeVersionList : public BaseVersionList
|
|
||||||
{
|
|
||||||
Q_OBJECT
|
|
||||||
public:
|
|
||||||
friend class ForgeListLoadTask;
|
|
||||||
|
|
||||||
explicit ForgeVersionList(QObject *parent = 0);
|
|
||||||
|
|
||||||
virtual Task *getLoadTask() override;
|
|
||||||
virtual bool isLoaded() override;
|
|
||||||
virtual const BaseVersionPtr at(int i) const override;
|
|
||||||
virtual int count() const override;
|
|
||||||
virtual void sortVersions() override;
|
|
||||||
|
|
||||||
virtual BaseVersionPtr getLatestStable() const override;
|
|
||||||
|
|
||||||
ForgeVersionPtr findVersionByVersionNr(QString version);
|
|
||||||
|
|
||||||
virtual QVariant data(const QModelIndex &index, int role) const override;
|
|
||||||
virtual RoleList providesRoles() const override;
|
|
||||||
|
|
||||||
virtual int columnCount(const QModelIndex &parent) const override;
|
|
||||||
|
|
||||||
protected:
|
|
||||||
QList<BaseVersionPtr> m_vlist;
|
|
||||||
|
|
||||||
bool m_loaded = false;
|
|
||||||
|
|
||||||
protected
|
|
||||||
slots:
|
|
||||||
virtual void updateListData(QList<BaseVersionPtr> versions) override;
|
|
||||||
};
|
|
||||||
|
|
||||||
class ForgeListLoadTask : public Task
|
|
||||||
{
|
|
||||||
Q_OBJECT
|
|
||||||
|
|
||||||
public:
|
|
||||||
explicit ForgeListLoadTask(ForgeVersionList *vlist);
|
|
||||||
|
|
||||||
virtual void executeTask();
|
|
||||||
virtual bool abort();
|
|
||||||
|
|
||||||
protected
|
|
||||||
slots:
|
|
||||||
void listDownloaded();
|
|
||||||
void listFailed();
|
|
||||||
void gradleListFailed();
|
|
||||||
|
|
||||||
protected:
|
|
||||||
NetJobPtr listJob;
|
|
||||||
ForgeVersionList *m_list;
|
|
||||||
|
|
||||||
Net::Download::Ptr listDownload;
|
|
||||||
Net::Download::Ptr gradleListDownload;
|
|
||||||
|
|
||||||
private:
|
|
||||||
bool parseForgeList(QList<BaseVersionPtr> &out);
|
|
||||||
bool parseForgeGradleList(QList<BaseVersionPtr> &out);
|
|
||||||
};
|
|
@ -1,56 +0,0 @@
|
|||||||
/* Copyright 2013-2017 MultiMC Contributors
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "LegacyForge.h"
|
|
||||||
|
|
||||||
MinecraftForge::MinecraftForge(const QString &file) : Mod(file)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
bool MinecraftForge::FixVersionIfNeeded(QString newVersion)
|
|
||||||
{/*
|
|
||||||
wxString reportedVersion = GetModVersion();
|
|
||||||
if(reportedVersion == "..." || reportedVersion.empty())
|
|
||||||
{
|
|
||||||
std::auto_ptr<wxFFileInputStream> in(new wxFFileInputStream("forge.zip"));
|
|
||||||
wxTempFileOutputStream out("forge.zip");
|
|
||||||
wxTextOutputStream textout(out);
|
|
||||||
wxZipInputStream inzip(*in);
|
|
||||||
wxZipOutputStream outzip(out);
|
|
||||||
std::auto_ptr<wxZipEntry> entry;
|
|
||||||
// preserve metadata
|
|
||||||
outzip.CopyArchiveMetaData(inzip);
|
|
||||||
// copy all entries
|
|
||||||
while (entry.reset(inzip.GetNextEntry()), entry.get() != NULL)
|
|
||||||
if (!outzip.CopyEntry(entry.release(), inzip))
|
|
||||||
return false;
|
|
||||||
// release last entry
|
|
||||||
in.reset();
|
|
||||||
outzip.PutNextEntry("forgeversion.properties");
|
|
||||||
|
|
||||||
wxStringTokenizer tokenizer(newVersion,".");
|
|
||||||
wxString verFile;
|
|
||||||
verFile << wxString("forge.major.number=") << tokenizer.GetNextToken() << "\n";
|
|
||||||
verFile << wxString("forge.minor.number=") << tokenizer.GetNextToken() << "\n";
|
|
||||||
verFile << wxString("forge.revision.number=") << tokenizer.GetNextToken() << "\n";
|
|
||||||
verFile << wxString("forge.build.number=") << tokenizer.GetNextToken() << "\n";
|
|
||||||
auto buf = verFile.ToUTF8();
|
|
||||||
outzip.Write(buf.data(), buf.length());
|
|
||||||
// check if we succeeded
|
|
||||||
return inzip.Eof() && outzip.Close() && out.Commit();
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
return true;
|
|
||||||
}
|
|
@ -1,25 +0,0 @@
|
|||||||
/* Copyright 2013-2017 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 "minecraft/Mod.h"
|
|
||||||
|
|
||||||
class MinecraftForge : public Mod
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
MinecraftForge(const QString &file);
|
|
||||||
bool FixVersionIfNeeded(QString newVersion);
|
|
||||||
};
|
|
@ -9,7 +9,6 @@
|
|||||||
#include <FileSystem.h>
|
#include <FileSystem.h>
|
||||||
|
|
||||||
#include "Env.h"
|
#include "Env.h"
|
||||||
#include "minecraft/MinecraftVersion.h"
|
|
||||||
|
|
||||||
#include "LegacyFTBInstance.h"
|
#include "LegacyFTBInstance.h"
|
||||||
#include "OneSixFTBInstance.h"
|
#include "OneSixFTBInstance.h"
|
||||||
@ -246,17 +245,8 @@ InstancePtr FTBInstanceProvider::createInstance(const FTBRecord & record) const
|
|||||||
m_settings->registerSetting("InstanceType", "Legacy");
|
m_settings->registerSetting("InstanceType", "Legacy");
|
||||||
|
|
||||||
// all legacy versions are built in. therefore we can do this even if we don't have ALL the versions Mojang has on their servers.
|
// all legacy versions are built in. therefore we can do this even if we don't have ALL the versions Mojang has on their servers.
|
||||||
auto mcVersion = std::dynamic_pointer_cast<MinecraftVersion>(ENV.getVersion("net.minecraft", record.mcVersion));
|
|
||||||
if (mcVersion && mcVersion->usesLegacyLauncher())
|
|
||||||
{
|
|
||||||
m_settings->set("InstanceType", "LegacyFTB");
|
|
||||||
inst.reset(new LegacyFTBInstance(m_globalSettings, m_settings, record.instanceDir));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
m_settings->set("InstanceType", "OneSixFTB");
|
m_settings->set("InstanceType", "OneSixFTB");
|
||||||
inst.reset(new OneSixFTBInstance(m_globalSettings, m_settings, record.instanceDir));
|
inst.reset(new OneSixFTBInstance(m_globalSettings, m_settings, record.instanceDir));
|
||||||
}
|
|
||||||
|
|
||||||
// initialize
|
// initialize
|
||||||
{
|
{
|
||||||
|
@ -1,11 +1,9 @@
|
|||||||
#include "FTBPlugin.h"
|
#include "FTBPlugin.h"
|
||||||
#include <Env.h>
|
#include <Env.h>
|
||||||
#include "FTBVersion.h"
|
|
||||||
#include "LegacyFTBInstance.h"
|
#include "LegacyFTBInstance.h"
|
||||||
#include "OneSixFTBInstance.h"
|
#include "OneSixFTBInstance.h"
|
||||||
#include <BaseInstance.h>
|
#include <BaseInstance.h>
|
||||||
#include <InstanceList.h>
|
#include <InstanceList.h>
|
||||||
#include <minecraft/MinecraftVersionList.h>
|
|
||||||
#include <settings/INISettingsObject.h>
|
#include <settings/INISettingsObject.h>
|
||||||
#include <FileSystem.h>
|
#include <FileSystem.h>
|
||||||
|
|
||||||
|
@ -2,7 +2,6 @@
|
|||||||
#include "OneSixFTBInstance.h"
|
#include "OneSixFTBInstance.h"
|
||||||
|
|
||||||
#include "minecraft/VersionBuildError.h"
|
#include "minecraft/VersionBuildError.h"
|
||||||
#include "minecraft/MinecraftVersionList.h"
|
|
||||||
#include <FileSystem.h>
|
#include <FileSystem.h>
|
||||||
|
|
||||||
#include <QDir>
|
#include <QDir>
|
||||||
@ -28,9 +27,8 @@ void FTBProfileStrategy::loadDefaultBuiltinPatches()
|
|||||||
if(QFile::exists(mcJson))
|
if(QFile::exists(mcJson))
|
||||||
{
|
{
|
||||||
auto file = ProfileUtils::parseJsonFile(QFileInfo(mcJson), false);
|
auto file = ProfileUtils::parseJsonFile(QFileInfo(mcJson), false);
|
||||||
file->fileId = "net.minecraft";
|
file->uid = "net.minecraft";
|
||||||
file->name = QObject::tr("Minecraft (tracked)");
|
file->name = QObject::tr("Minecraft (tracked)");
|
||||||
file->setVanilla(true);
|
|
||||||
if(file->version.isEmpty())
|
if(file->version.isEmpty())
|
||||||
{
|
{
|
||||||
file->version = mcVersion;
|
file->version = mcVersion;
|
||||||
@ -40,7 +38,8 @@ void FTBProfileStrategy::loadDefaultBuiltinPatches()
|
|||||||
addLib->setHint("local");
|
addLib->setHint("local");
|
||||||
addLib->setStoragePrefix(nativeInstance->librariesPath().absolutePath());
|
addLib->setStoragePrefix(nativeInstance->librariesPath().absolutePath());
|
||||||
}
|
}
|
||||||
minecraftPatch = std::dynamic_pointer_cast<ProfilePatch>(file);
|
minecraftPatch = std::make_shared<ProfilePatch>(file);
|
||||||
|
minecraftPatch->setVanilla(true);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -65,8 +64,7 @@ void FTBProfileStrategy::loadDefaultBuiltinPatches()
|
|||||||
addLib->setHint("local");
|
addLib->setHint("local");
|
||||||
addLib->setStoragePrefix(nativeInstance->librariesPath().absolutePath());
|
addLib->setStoragePrefix(nativeInstance->librariesPath().absolutePath());
|
||||||
}
|
}
|
||||||
file->fileId = "org.multimc.ftb.pack";
|
file->uid = "org.multimc.ftb.pack";
|
||||||
file->setVanilla(true);
|
|
||||||
file->name = QObject::tr("%1 (FTB pack)").arg(m_instance->name());
|
file->name = QObject::tr("%1 (FTB pack)").arg(m_instance->name());
|
||||||
if(file->version.isEmpty())
|
if(file->version.isEmpty())
|
||||||
{
|
{
|
||||||
@ -82,7 +80,8 @@ void FTBProfileStrategy::loadDefaultBuiltinPatches()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
packPatch = std::dynamic_pointer_cast<ProfilePatch>(file);
|
packPatch = std::make_shared<ProfilePatch>(file);
|
||||||
|
packPatch->setVanilla(true);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -1,32 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
#include <minecraft/MinecraftVersion.h>
|
|
||||||
|
|
||||||
class FTBVersion : public BaseVersion
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
FTBVersion(MinecraftVersionPtr parent) : m_version(parent){};
|
|
||||||
|
|
||||||
public:
|
|
||||||
virtual QString descriptor() override
|
|
||||||
{
|
|
||||||
return m_version->descriptor();
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual QString name() override
|
|
||||||
{
|
|
||||||
return m_version->name();
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual QString typeString() const override
|
|
||||||
{
|
|
||||||
return m_version->typeString();
|
|
||||||
}
|
|
||||||
|
|
||||||
MinecraftVersionPtr getMinecraftVersion()
|
|
||||||
{
|
|
||||||
return m_version;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
MinecraftVersionPtr m_version;
|
|
||||||
};
|
|
@ -27,7 +27,6 @@
|
|||||||
#include "LegacyModList.h"
|
#include "LegacyModList.h"
|
||||||
|
|
||||||
#include "LwjglVersionList.h"
|
#include "LwjglVersionList.h"
|
||||||
#include "minecraft/MinecraftVersionList.h"
|
|
||||||
#include "LegacyInstance.h"
|
#include "LegacyInstance.h"
|
||||||
#include <FileSystem.h>
|
#include <FileSystem.h>
|
||||||
|
|
||||||
|
@ -99,6 +99,7 @@ inline QDomElement getDomElementByTagName(QDomElement parent, QString tagname)
|
|||||||
|
|
||||||
void LWJGLVersionList::rssFailed(const QString& reason)
|
void LWJGLVersionList::rssFailed(const QString& reason)
|
||||||
{
|
{
|
||||||
|
m_rssDLJob.reset();
|
||||||
m_loading = false;
|
m_loading = false;
|
||||||
qWarning() << "Failed to load LWJGL list. Network error: " + reason;
|
qWarning() << "Failed to load LWJGL list. Network error: " + reason;
|
||||||
}
|
}
|
||||||
@ -116,8 +117,9 @@ void LWJGLVersionList::rssSucceeded()
|
|||||||
if (!doc.setContent(m_rssData, false, &xmlErrorMsg, &errorLine))
|
if (!doc.setContent(m_rssData, false, &xmlErrorMsg, &errorLine))
|
||||||
{
|
{
|
||||||
qWarning() << "Failed to load LWJGL list. XML error: " + xmlErrorMsg + " at line " + QString::number(errorLine);
|
qWarning() << "Failed to load LWJGL list. XML error: " + xmlErrorMsg + " at line " + QString::number(errorLine);
|
||||||
m_loading = false;
|
m_rssDLJob.reset();
|
||||||
m_rssData.clear();
|
m_rssData.clear();
|
||||||
|
m_loading = false;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
m_rssData.clear();
|
m_rssData.clear();
|
||||||
@ -162,5 +164,6 @@ void LWJGLVersionList::rssSucceeded()
|
|||||||
endResetModel();
|
endResetModel();
|
||||||
|
|
||||||
qDebug() << "Loaded LWJGL list.";
|
qDebug() << "Loaded LWJGL list.";
|
||||||
|
m_rssDLJob.reset();
|
||||||
m_loading = false;
|
m_loading = false;
|
||||||
}
|
}
|
||||||
|
@ -78,9 +78,9 @@ public:
|
|||||||
return m_vlist[i];
|
return m_vlist[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual Task* getLoadTask() override
|
virtual shared_qobject_ptr<Task> getLoadTask() override
|
||||||
{
|
{
|
||||||
return nullptr;
|
return m_rssDLJob;
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void sortVersions() override {};
|
virtual void sortVersions() override {};
|
||||||
|
@ -1,106 +0,0 @@
|
|||||||
/* Copyright 2013-2017 MultiMC Contributors
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "LiteLoaderInstaller.h"
|
|
||||||
|
|
||||||
#include <QJsonArray>
|
|
||||||
#include <QJsonDocument>
|
|
||||||
|
|
||||||
#include <QDebug>
|
|
||||||
|
|
||||||
#include "minecraft/MinecraftProfile.h"
|
|
||||||
#include "minecraft/Library.h"
|
|
||||||
#include "minecraft/onesix/OneSixInstance.h"
|
|
||||||
#include <minecraft/onesix/OneSixVersionFormat.h>
|
|
||||||
#include "minecraft/liteloader/LiteLoaderVersionList.h"
|
|
||||||
#include "Exception.h"
|
|
||||||
|
|
||||||
LiteLoaderInstaller::LiteLoaderInstaller() : BaseInstaller()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void LiteLoaderInstaller::prepare(LiteLoaderVersionPtr version)
|
|
||||||
{
|
|
||||||
m_version = version;
|
|
||||||
}
|
|
||||||
bool LiteLoaderInstaller::add(OneSixInstance *to)
|
|
||||||
{
|
|
||||||
if (!BaseInstaller::add(to))
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
QFile file(filename(to->instanceRoot()));
|
|
||||||
if (!file.open(QFile::WriteOnly))
|
|
||||||
{
|
|
||||||
qCritical() << "Error opening" << file.fileName()
|
|
||||||
<< "for reading:" << file.errorString();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
file.write(OneSixVersionFormat::versionFileToJson(m_version->getVersionFile(), true).toJson());
|
|
||||||
file.close();
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
class LiteLoaderInstallTask : public Task
|
|
||||||
{
|
|
||||||
Q_OBJECT
|
|
||||||
public:
|
|
||||||
LiteLoaderInstallTask(LiteLoaderInstaller *installer, OneSixInstance *instance, BaseVersionPtr version, QObject *parent)
|
|
||||||
: Task(parent), m_installer(installer), m_instance(instance), m_version(version)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
protected:
|
|
||||||
void executeTask() override
|
|
||||||
{
|
|
||||||
LiteLoaderVersionPtr liteloaderVersion = std::dynamic_pointer_cast<LiteLoaderVersion>(m_version);
|
|
||||||
if (!liteloaderVersion)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
m_installer->prepare(liteloaderVersion);
|
|
||||||
if (!m_installer->add(m_instance))
|
|
||||||
{
|
|
||||||
emitFailed(tr("For reasons unknown, the LiteLoader installation failed. Check your MultiMC log files for details."));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
try
|
|
||||||
{
|
|
||||||
m_instance->reloadProfile();
|
|
||||||
emitSucceeded();
|
|
||||||
}
|
|
||||||
catch (Exception &e)
|
|
||||||
{
|
|
||||||
emitFailed(e.cause());
|
|
||||||
}
|
|
||||||
catch (...)
|
|
||||||
{
|
|
||||||
emitFailed(tr("Failed to load the version description file for reasons unknown."));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
LiteLoaderInstaller *m_installer;
|
|
||||||
OneSixInstance *m_instance;
|
|
||||||
BaseVersionPtr m_version;
|
|
||||||
};
|
|
||||||
|
|
||||||
Task *LiteLoaderInstaller::createInstallTask(OneSixInstance *instance, BaseVersionPtr version, QObject *parent)
|
|
||||||
{
|
|
||||||
return new LiteLoaderInstallTask(this, instance, version, parent);
|
|
||||||
}
|
|
||||||
|
|
||||||
#include "LiteLoaderInstaller.moc"
|
|
@ -1,39 +0,0 @@
|
|||||||
/* Copyright 2013-2017 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 <QString>
|
|
||||||
#include <QMap>
|
|
||||||
|
|
||||||
#include "BaseInstaller.h"
|
|
||||||
#include "LiteLoaderVersionList.h"
|
|
||||||
|
|
||||||
#include "multimc_logic_export.h"
|
|
||||||
|
|
||||||
class MULTIMC_LOGIC_EXPORT LiteLoaderInstaller : public BaseInstaller
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
LiteLoaderInstaller();
|
|
||||||
|
|
||||||
void prepare(LiteLoaderVersionPtr version);
|
|
||||||
bool add(OneSixInstance *to) override;
|
|
||||||
virtual QString id() const override { return "com.mumfrey.liteloader"; }
|
|
||||||
|
|
||||||
Task *createInstallTask(OneSixInstance *instance, BaseVersionPtr version, QObject *parent) override;
|
|
||||||
|
|
||||||
private:
|
|
||||||
LiteLoaderVersionPtr m_version;
|
|
||||||
};
|
|
@ -1,332 +0,0 @@
|
|||||||
/* Copyright 2013-2017 MultiMC Contributors
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "LiteLoaderVersionList.h"
|
|
||||||
#include <minecraft/onesix/OneSixVersionFormat.h>
|
|
||||||
#include "Env.h"
|
|
||||||
#include "net/URLConstants.h"
|
|
||||||
#include "Exception.h"
|
|
||||||
|
|
||||||
#include <QtXml>
|
|
||||||
|
|
||||||
#include <QJsonDocument>
|
|
||||||
#include <QJsonObject>
|
|
||||||
#include <QJsonArray>
|
|
||||||
#include <QJsonValue>
|
|
||||||
#include <QJsonParseError>
|
|
||||||
|
|
||||||
#include <QtAlgorithms>
|
|
||||||
|
|
||||||
#include <QtNetwork>
|
|
||||||
|
|
||||||
LiteLoaderVersionList::LiteLoaderVersionList(QObject *parent) : BaseVersionList(parent)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
Task *LiteLoaderVersionList::getLoadTask()
|
|
||||||
{
|
|
||||||
return new LLListLoadTask(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool LiteLoaderVersionList::isLoaded()
|
|
||||||
{
|
|
||||||
return m_loaded;
|
|
||||||
}
|
|
||||||
|
|
||||||
const BaseVersionPtr LiteLoaderVersionList::at(int i) const
|
|
||||||
{
|
|
||||||
return m_vlist.at(i);
|
|
||||||
}
|
|
||||||
|
|
||||||
int LiteLoaderVersionList::count() const
|
|
||||||
{
|
|
||||||
return m_vlist.count();
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool cmpVersions(BaseVersionPtr first, BaseVersionPtr second)
|
|
||||||
{
|
|
||||||
auto left = std::dynamic_pointer_cast<LiteLoaderVersion>(first);
|
|
||||||
auto right = std::dynamic_pointer_cast<LiteLoaderVersion>(second);
|
|
||||||
return left->timestamp > right->timestamp;
|
|
||||||
}
|
|
||||||
|
|
||||||
VersionFilePtr LiteLoaderVersion::getVersionFile()
|
|
||||||
{
|
|
||||||
auto f = std::make_shared<VersionFile>();
|
|
||||||
f->mainClass = "net.minecraft.launchwrapper.Launch";
|
|
||||||
f->addTweakers += tweakClass;
|
|
||||||
f->order = 10;
|
|
||||||
f->libraries = libraries;
|
|
||||||
f->name = "LiteLoader";
|
|
||||||
f->fileId = "com.mumfrey.liteloader";
|
|
||||||
f->version = version;
|
|
||||||
f->minecraftVersion = mcVersion;
|
|
||||||
return f;
|
|
||||||
}
|
|
||||||
|
|
||||||
void LiteLoaderVersionList::sortVersions()
|
|
||||||
{
|
|
||||||
beginResetModel();
|
|
||||||
std::sort(m_vlist.begin(), m_vlist.end(), cmpVersions);
|
|
||||||
endResetModel();
|
|
||||||
}
|
|
||||||
|
|
||||||
QVariant LiteLoaderVersionList::data(const QModelIndex &index, int role) const
|
|
||||||
{
|
|
||||||
if (!index.isValid())
|
|
||||||
return QVariant();
|
|
||||||
|
|
||||||
if (index.row() > count())
|
|
||||||
return QVariant();
|
|
||||||
|
|
||||||
auto version = std::dynamic_pointer_cast<LiteLoaderVersion>(m_vlist[index.row()]);
|
|
||||||
switch (role)
|
|
||||||
{
|
|
||||||
case VersionPointerRole:
|
|
||||||
return qVariantFromValue(m_vlist[index.row()]);
|
|
||||||
|
|
||||||
case VersionRole:
|
|
||||||
return version->name();
|
|
||||||
|
|
||||||
case VersionIdRole:
|
|
||||||
return version->descriptor();
|
|
||||||
|
|
||||||
case ParentGameVersionRole:
|
|
||||||
return version->mcVersion;
|
|
||||||
|
|
||||||
case LatestRole:
|
|
||||||
return version->isLatest;
|
|
||||||
|
|
||||||
case RecommendedRole:
|
|
||||||
return version->isRecommended;
|
|
||||||
|
|
||||||
case TypeRole:
|
|
||||||
return version->isSnapshot ? tr("Snapshot") : tr("Release");
|
|
||||||
|
|
||||||
default:
|
|
||||||
return QVariant();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
BaseVersionList::RoleList LiteLoaderVersionList::providesRoles() const
|
|
||||||
{
|
|
||||||
return {VersionPointerRole, VersionRole, VersionIdRole, ParentGameVersionRole, RecommendedRole, LatestRole, TypeRole};
|
|
||||||
}
|
|
||||||
|
|
||||||
BaseVersionPtr LiteLoaderVersionList::getLatestStable() const
|
|
||||||
{
|
|
||||||
for (int i = 0; i < m_vlist.length(); i++)
|
|
||||||
{
|
|
||||||
auto ver = std::dynamic_pointer_cast<LiteLoaderVersion>(m_vlist.at(i));
|
|
||||||
if (ver->isRecommended)
|
|
||||||
{
|
|
||||||
return m_vlist.at(i);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return BaseVersionPtr();
|
|
||||||
}
|
|
||||||
|
|
||||||
void LiteLoaderVersionList::updateListData(QList<BaseVersionPtr> versions)
|
|
||||||
{
|
|
||||||
beginResetModel();
|
|
||||||
m_vlist = versions;
|
|
||||||
m_loaded = true;
|
|
||||||
std::sort(m_vlist.begin(), m_vlist.end(), cmpVersions);
|
|
||||||
endResetModel();
|
|
||||||
}
|
|
||||||
|
|
||||||
LLListLoadTask::LLListLoadTask(LiteLoaderVersionList *vlist)
|
|
||||||
{
|
|
||||||
m_list = vlist;
|
|
||||||
}
|
|
||||||
|
|
||||||
LLListLoadTask::~LLListLoadTask()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void LLListLoadTask::executeTask()
|
|
||||||
{
|
|
||||||
setStatus(tr("Loading LiteLoader version list..."));
|
|
||||||
auto job = new NetJob("Version index");
|
|
||||||
// we do not care if the version is stale or not.
|
|
||||||
auto liteloaderEntry = ENV.metacache()->resolveEntry("liteloader", "versions.json");
|
|
||||||
|
|
||||||
// verify by poking the server.
|
|
||||||
liteloaderEntry->setStale(true);
|
|
||||||
|
|
||||||
job->addNetAction(listDownload = Net::Download::makeCached(QUrl(URLConstants::LITELOADER_URL), liteloaderEntry));
|
|
||||||
|
|
||||||
connect(listDownload.get(), SIGNAL(failed(int)), SLOT(listFailed()));
|
|
||||||
|
|
||||||
listJob.reset(job);
|
|
||||||
connect(listJob.get(), SIGNAL(succeeded()), SLOT(listDownloaded()));
|
|
||||||
connect(listJob.get(), SIGNAL(progress(qint64, qint64)), SIGNAL(progress(qint64, qint64)));
|
|
||||||
listJob->start();
|
|
||||||
}
|
|
||||||
|
|
||||||
void LLListLoadTask::listFailed()
|
|
||||||
{
|
|
||||||
emitFailed("Failed to load LiteLoader version list.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
void LLListLoadTask::listDownloaded()
|
|
||||||
{
|
|
||||||
QByteArray data;
|
|
||||||
{
|
|
||||||
auto filename = listDownload->getTargetFilepath();
|
|
||||||
QFile listFile(filename);
|
|
||||||
if (!listFile.open(QIODevice::ReadOnly))
|
|
||||||
{
|
|
||||||
emitFailed("Failed to open the LiteLoader version list.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
data = listFile.readAll();
|
|
||||||
listFile.close();
|
|
||||||
listDownload.reset();
|
|
||||||
}
|
|
||||||
|
|
||||||
QJsonParseError jsonError;
|
|
||||||
QJsonDocument jsonDoc = QJsonDocument::fromJson(data, &jsonError);
|
|
||||||
|
|
||||||
if (jsonError.error != QJsonParseError::NoError)
|
|
||||||
{
|
|
||||||
emitFailed("Error parsing version list JSON:" + jsonError.errorString());
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!jsonDoc.isObject())
|
|
||||||
{
|
|
||||||
emitFailed("Error parsing version list JSON: jsonDoc is not an object");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const QJsonObject root = jsonDoc.object();
|
|
||||||
|
|
||||||
// Now, get the array of versions.
|
|
||||||
if (!root.value("versions").isObject())
|
|
||||||
{
|
|
||||||
emitFailed("Error parsing version list JSON: missing 'versions' object");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto meta = root.value("meta").toObject();
|
|
||||||
QString description = meta.value("description").toString(tr("This is a lightweight loader for mods that don't change game mechanics."));
|
|
||||||
QString defaultUrl = meta.value("url").toString("http://dl.liteloader.com");
|
|
||||||
QString authors = meta.value("authors").toString("Mumfrey");
|
|
||||||
auto versions = root.value("versions").toObject();
|
|
||||||
|
|
||||||
QList<BaseVersionPtr> tempList;
|
|
||||||
for (auto vIt = versions.begin(); vIt != versions.end(); ++vIt)
|
|
||||||
{
|
|
||||||
const QString mcVersion = vIt.key();
|
|
||||||
const QJsonObject versionObject = vIt.value().toObject();
|
|
||||||
|
|
||||||
auto processArtefacts = [&](QJsonObject artefacts, bool notSnapshots, std::shared_ptr<LiteLoaderVersion> &latest)
|
|
||||||
{
|
|
||||||
QString latestVersion;
|
|
||||||
QList<BaseVersionPtr> perMcVersionList;
|
|
||||||
for (auto aIt = artefacts.begin(); aIt != artefacts.end(); ++aIt)
|
|
||||||
{
|
|
||||||
const QString identifier = aIt.key();
|
|
||||||
const QJsonObject artefact = aIt.value().toObject();
|
|
||||||
if (identifier == "latest")
|
|
||||||
{
|
|
||||||
latestVersion = artefact.value("version").toString();
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
LiteLoaderVersionPtr version(new LiteLoaderVersion());
|
|
||||||
version->version = artefact.value("version").toString();
|
|
||||||
version->mcVersion = mcVersion;
|
|
||||||
version->md5 = artefact.value("md5").toString();
|
|
||||||
version->timestamp = artefact.value("timestamp").toString().toLong();
|
|
||||||
version->tweakClass = artefact.value("tweakClass").toString();
|
|
||||||
version->authors = authors;
|
|
||||||
version->description = description;
|
|
||||||
version->defaultUrl = defaultUrl;
|
|
||||||
version->isSnapshot = !notSnapshots;
|
|
||||||
const QJsonArray libs = artefact.value("libraries").toArray();
|
|
||||||
for (auto lIt = libs.begin(); lIt != libs.end(); ++lIt)
|
|
||||||
{
|
|
||||||
auto libobject = (*lIt).toObject();
|
|
||||||
try
|
|
||||||
{
|
|
||||||
auto lib = OneSixVersionFormat::libraryFromJson(libobject, "versions.json");
|
|
||||||
// hack to make liteloader 1.7.10_00 work
|
|
||||||
if(lib->rawName() == GradleSpecifier("org.ow2.asm:asm-all:5.0.3"))
|
|
||||||
{
|
|
||||||
lib->setRepositoryURL("http://repo.maven.apache.org/maven2/");
|
|
||||||
}
|
|
||||||
version->libraries.append(lib);
|
|
||||||
}
|
|
||||||
catch (Exception &e)
|
|
||||||
{
|
|
||||||
qCritical() << "Couldn't read JSON object:";
|
|
||||||
continue; // FIXME: ignores bad libraries and continues loading
|
|
||||||
}
|
|
||||||
}
|
|
||||||
auto liteloaderLib = std::make_shared<Library>("com.mumfrey:liteloader:" + version->version);
|
|
||||||
liteloaderLib->setRepositoryURL("http://dl.liteloader.com/versions/");
|
|
||||||
if(!notSnapshots)
|
|
||||||
{
|
|
||||||
liteloaderLib->setHint("always-stale");
|
|
||||||
}
|
|
||||||
version->libraries.append(liteloaderLib);
|
|
||||||
perMcVersionList.append(version);
|
|
||||||
}
|
|
||||||
if(notSnapshots)
|
|
||||||
{
|
|
||||||
for (auto version : perMcVersionList)
|
|
||||||
{
|
|
||||||
auto v = std::dynamic_pointer_cast<LiteLoaderVersion>(version);
|
|
||||||
if(v->version == latestVersion)
|
|
||||||
{
|
|
||||||
latest = v;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
tempList.append(perMcVersionList);
|
|
||||||
};
|
|
||||||
|
|
||||||
std::shared_ptr<LiteLoaderVersion> latestSnapshot;
|
|
||||||
std::shared_ptr<LiteLoaderVersion> latestRelease;
|
|
||||||
// are there actually released versions for this mc version?
|
|
||||||
if(versionObject.contains("artefacts"))
|
|
||||||
{
|
|
||||||
const QJsonObject artefacts = versionObject.value("artefacts").toObject().value("com.mumfrey:liteloader").toObject();
|
|
||||||
processArtefacts(artefacts, true, latestRelease);
|
|
||||||
}
|
|
||||||
if(versionObject.contains("snapshots"))
|
|
||||||
{
|
|
||||||
QJsonObject artefacts = versionObject.value("snapshots").toObject().value("com.mumfrey:liteloader").toObject();
|
|
||||||
processArtefacts(artefacts, false, latestSnapshot);
|
|
||||||
}
|
|
||||||
if(latestSnapshot)
|
|
||||||
{
|
|
||||||
latestSnapshot->isLatest = true;
|
|
||||||
}
|
|
||||||
else if(latestRelease)
|
|
||||||
{
|
|
||||||
latestRelease->isLatest = true;
|
|
||||||
}
|
|
||||||
if(latestRelease)
|
|
||||||
{
|
|
||||||
latestRelease->isRecommended = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
m_list->updateListData(tempList);
|
|
||||||
|
|
||||||
emitSucceeded();
|
|
||||||
}
|
|
@ -1,123 +0,0 @@
|
|||||||
/* Copyright 2013-2017 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 <QObject>
|
|
||||||
|
|
||||||
#include <QString>
|
|
||||||
#include <QStringList>
|
|
||||||
#include "BaseVersion.h"
|
|
||||||
#include "BaseVersionList.h"
|
|
||||||
#include "tasks/Task.h"
|
|
||||||
#include "net/NetJob.h"
|
|
||||||
#include <minecraft/Library.h>
|
|
||||||
#include <minecraft/VersionFile.h>
|
|
||||||
|
|
||||||
#include "multimc_logic_export.h"
|
|
||||||
|
|
||||||
class LLListLoadTask;
|
|
||||||
class QNetworkReply;
|
|
||||||
|
|
||||||
class LiteLoaderVersion : public BaseVersion
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
QString descriptor() override
|
|
||||||
{
|
|
||||||
if (isLatest)
|
|
||||||
{
|
|
||||||
return QObject::tr("Latest");
|
|
||||||
}
|
|
||||||
return QString();
|
|
||||||
}
|
|
||||||
QString typeString() const override
|
|
||||||
{
|
|
||||||
return mcVersion;
|
|
||||||
}
|
|
||||||
QString name() override
|
|
||||||
{
|
|
||||||
return version;
|
|
||||||
}
|
|
||||||
VersionFilePtr getVersionFile();
|
|
||||||
|
|
||||||
// important info
|
|
||||||
QString version;
|
|
||||||
QString mcVersion;
|
|
||||||
QString md5;
|
|
||||||
long timestamp = 0;
|
|
||||||
bool isLatest = false;
|
|
||||||
bool isRecommended = false;
|
|
||||||
bool isSnapshot = false;
|
|
||||||
|
|
||||||
QString tweakClass;
|
|
||||||
QList<LibraryPtr> libraries;
|
|
||||||
|
|
||||||
// meta
|
|
||||||
QString defaultUrl;
|
|
||||||
QString description;
|
|
||||||
QString authors;
|
|
||||||
};
|
|
||||||
typedef std::shared_ptr<LiteLoaderVersion> LiteLoaderVersionPtr;
|
|
||||||
|
|
||||||
class MULTIMC_LOGIC_EXPORT LiteLoaderVersionList : public BaseVersionList
|
|
||||||
{
|
|
||||||
Q_OBJECT
|
|
||||||
public:
|
|
||||||
friend class LLListLoadTask;
|
|
||||||
|
|
||||||
explicit LiteLoaderVersionList(QObject *parent = 0);
|
|
||||||
|
|
||||||
Task *getLoadTask() override;
|
|
||||||
bool isLoaded() override;
|
|
||||||
const BaseVersionPtr at(int i) const override;
|
|
||||||
int count() const override;
|
|
||||||
void sortVersions() override;
|
|
||||||
QVariant data ( const QModelIndex & index, int role = Qt::DisplayRole ) const override;
|
|
||||||
RoleList providesRoles() const override;
|
|
||||||
|
|
||||||
virtual BaseVersionPtr getLatestStable() const override;
|
|
||||||
|
|
||||||
protected:
|
|
||||||
QList<BaseVersionPtr> m_vlist;
|
|
||||||
|
|
||||||
bool m_loaded = false;
|
|
||||||
|
|
||||||
protected
|
|
||||||
slots:
|
|
||||||
void updateListData(QList<BaseVersionPtr> versions) override;
|
|
||||||
};
|
|
||||||
|
|
||||||
class LLListLoadTask : public Task
|
|
||||||
{
|
|
||||||
Q_OBJECT
|
|
||||||
|
|
||||||
public:
|
|
||||||
explicit LLListLoadTask(LiteLoaderVersionList *vlist);
|
|
||||||
~LLListLoadTask();
|
|
||||||
|
|
||||||
virtual void executeTask();
|
|
||||||
|
|
||||||
protected
|
|
||||||
slots:
|
|
||||||
void listDownloaded();
|
|
||||||
void listFailed();
|
|
||||||
|
|
||||||
protected:
|
|
||||||
NetJobPtr listJob;
|
|
||||||
Net::Download::Ptr listDownload;
|
|
||||||
LiteLoaderVersionList *m_list;
|
|
||||||
};
|
|
||||||
|
|
||||||
Q_DECLARE_METATYPE(LiteLoaderVersionPtr)
|
|
@ -34,7 +34,15 @@
|
|||||||
OneSixInstance::OneSixInstance(SettingsObjectPtr globalSettings, SettingsObjectPtr settings, const QString &rootDir)
|
OneSixInstance::OneSixInstance(SettingsObjectPtr globalSettings, SettingsObjectPtr settings, const QString &rootDir)
|
||||||
: MinecraftInstance(globalSettings, settings, rootDir)
|
: MinecraftInstance(globalSettings, settings, rootDir)
|
||||||
{
|
{
|
||||||
|
// set explicitly during instance creation
|
||||||
m_settings->registerSetting({"IntendedVersion", "MinecraftVersion"}, "");
|
m_settings->registerSetting({"IntendedVersion", "MinecraftVersion"}, "");
|
||||||
|
|
||||||
|
// defaults to the version we've been using for years (2.9.1)
|
||||||
|
m_settings->registerSetting("LWJGLVersion", "2.9.1");
|
||||||
|
|
||||||
|
// optionals
|
||||||
|
m_settings->registerSetting("ForgeVersion", "");
|
||||||
|
m_settings->registerSetting("LiteloaderVersion", "");
|
||||||
}
|
}
|
||||||
|
|
||||||
void OneSixInstance::init()
|
void OneSixInstance::init()
|
||||||
@ -275,6 +283,8 @@ QStringList OneSixInstance::verboseDescription(AuthSessionPtr session)
|
|||||||
printLibFile(file);
|
printLibFile(file);
|
||||||
}
|
}
|
||||||
printLibFile(mainJarPath());
|
printLibFile(mainJarPath());
|
||||||
|
out << "";
|
||||||
|
out << "Native libraries:";
|
||||||
for(auto file: nativeJars)
|
for(auto file: nativeJars)
|
||||||
{
|
{
|
||||||
printLibFile(file);
|
printLibFile(file);
|
||||||
@ -480,7 +490,32 @@ std::shared_ptr<WorldList> OneSixInstance::worldList() const
|
|||||||
|
|
||||||
bool OneSixInstance::setIntendedVersionId(QString version)
|
bool OneSixInstance::setIntendedVersionId(QString version)
|
||||||
{
|
{
|
||||||
|
return setComponentVersion("net.minecraft", version);
|
||||||
|
}
|
||||||
|
|
||||||
|
QString OneSixInstance::intendedVersionId() const
|
||||||
|
{
|
||||||
|
return getComponentVersion("net.minecraft");
|
||||||
|
}
|
||||||
|
|
||||||
|
bool OneSixInstance::setComponentVersion(const QString& uid, const QString& version)
|
||||||
|
{
|
||||||
|
if(uid == "net.minecraft")
|
||||||
|
{
|
||||||
settings()->set("IntendedVersion", version);
|
settings()->set("IntendedVersion", version);
|
||||||
|
}
|
||||||
|
else if (uid == "org.lwjgl")
|
||||||
|
{
|
||||||
|
settings()->set("LWJGLVersion", version);
|
||||||
|
}
|
||||||
|
else if (uid == "net.minecraftforge")
|
||||||
|
{
|
||||||
|
settings()->set("ForgeVersion", version);
|
||||||
|
}
|
||||||
|
else if (uid == "com.mumfrey.liteloader")
|
||||||
|
{
|
||||||
|
settings()->set("LiteloaderVersion", version);
|
||||||
|
}
|
||||||
if(getMinecraftProfile())
|
if(getMinecraftProfile())
|
||||||
{
|
{
|
||||||
clearProfile();
|
clearProfile();
|
||||||
@ -489,6 +524,27 @@ bool OneSixInstance::setIntendedVersionId(QString version)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QString OneSixInstance::getComponentVersion(const QString& uid) const
|
||||||
|
{
|
||||||
|
if(uid == "net.minecraft")
|
||||||
|
{
|
||||||
|
return settings()->get("IntendedVersion").toString();
|
||||||
|
}
|
||||||
|
else if(uid == "org.lwjgl")
|
||||||
|
{
|
||||||
|
return settings()->get("LWJGLVersion").toString();
|
||||||
|
}
|
||||||
|
else if(uid == "net.minecraftforge")
|
||||||
|
{
|
||||||
|
return settings()->get("ForgeVersion").toString();
|
||||||
|
}
|
||||||
|
else if(uid == "com.mumfrey.liteloader")
|
||||||
|
{
|
||||||
|
return settings()->get("LiteloaderVersion").toString();
|
||||||
|
}
|
||||||
|
return QString();
|
||||||
|
}
|
||||||
|
|
||||||
QList< Mod > OneSixInstance::getJarMods() const
|
QList< Mod > OneSixInstance::getJarMods() const
|
||||||
{
|
{
|
||||||
QList<Mod> mods;
|
QList<Mod> mods;
|
||||||
@ -500,12 +556,6 @@ QList< Mod > OneSixInstance::getJarMods() const
|
|||||||
return mods;
|
return mods;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
QString OneSixInstance::intendedVersionId() const
|
|
||||||
{
|
|
||||||
return settings()->get("IntendedVersion").toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
void OneSixInstance::setShouldUpdate(bool)
|
void OneSixInstance::setShouldUpdate(bool)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
@ -523,7 +573,7 @@ QString OneSixInstance::currentVersionId() const
|
|||||||
void OneSixInstance::reloadProfile()
|
void OneSixInstance::reloadProfile()
|
||||||
{
|
{
|
||||||
m_profile->reload();
|
m_profile->reload();
|
||||||
setVersionBroken(m_profile->getProblemSeverity() == ProblemSeverity::PROBLEM_ERROR);
|
setVersionBroken(m_profile->getProblemSeverity() == ProblemSeverity::Error);
|
||||||
emit versionReloaded();
|
emit versionReloaded();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -59,9 +59,11 @@ public:
|
|||||||
|
|
||||||
virtual QString intendedVersionId() const override;
|
virtual QString intendedVersionId() const override;
|
||||||
virtual bool setIntendedVersionId(QString version) override;
|
virtual bool setIntendedVersionId(QString version) override;
|
||||||
|
|
||||||
virtual QString currentVersionId() const override;
|
virtual QString currentVersionId() const override;
|
||||||
|
|
||||||
|
QString getComponentVersion(const QString &uid) const;
|
||||||
|
bool setComponentVersion(const QString &uid, const QString &version);
|
||||||
|
|
||||||
virtual bool shouldUpdate() const override;
|
virtual bool shouldUpdate() const override;
|
||||||
virtual void setShouldUpdate(bool val) override;
|
virtual void setShouldUpdate(bool val) override;
|
||||||
|
|
||||||
|
@ -3,7 +3,6 @@
|
|||||||
#include "OneSixVersionFormat.h"
|
#include "OneSixVersionFormat.h"
|
||||||
|
|
||||||
#include "minecraft/VersionBuildError.h"
|
#include "minecraft/VersionBuildError.h"
|
||||||
#include "minecraft/MinecraftVersionList.h"
|
|
||||||
#include "Env.h"
|
#include "Env.h"
|
||||||
#include <FileSystem.h>
|
#include <FileSystem.h>
|
||||||
|
|
||||||
@ -11,6 +10,12 @@
|
|||||||
#include <QUuid>
|
#include <QUuid>
|
||||||
#include <QJsonDocument>
|
#include <QJsonDocument>
|
||||||
#include <QJsonArray>
|
#include <QJsonArray>
|
||||||
|
#include <QSaveFile>
|
||||||
|
#include <QResource>
|
||||||
|
#include <meta/Index.h>
|
||||||
|
#include <meta/Version.h>
|
||||||
|
|
||||||
|
#include <tuple>
|
||||||
|
|
||||||
OneSixProfileStrategy::OneSixProfileStrategy(OneSixInstance* instance)
|
OneSixProfileStrategy::OneSixProfileStrategy(OneSixInstance* instance)
|
||||||
{
|
{
|
||||||
@ -53,7 +58,7 @@ void OneSixProfileStrategy::upgradeDeprecatedFiles()
|
|||||||
}
|
}
|
||||||
auto file = ProfileUtils::parseJsonFile(QFileInfo(sourceFile), false);
|
auto file = ProfileUtils::parseJsonFile(QFileInfo(sourceFile), false);
|
||||||
ProfileUtils::removeLwjglFromPatch(file);
|
ProfileUtils::removeLwjglFromPatch(file);
|
||||||
file->fileId = "net.minecraft";
|
file->uid = "net.minecraft";
|
||||||
file->version = file->minecraftVersion;
|
file->version = file->minecraftVersion;
|
||||||
file->name = "Minecraft";
|
file->name = "Minecraft";
|
||||||
auto data = OneSixVersionFormat::versionFileToJson(file, false).toJson();
|
auto data = OneSixVersionFormat::versionFileToJson(file, false).toJson();
|
||||||
@ -80,156 +85,128 @@ void OneSixProfileStrategy::upgradeDeprecatedFiles()
|
|||||||
|
|
||||||
void OneSixProfileStrategy::loadDefaultBuiltinPatches()
|
void OneSixProfileStrategy::loadDefaultBuiltinPatches()
|
||||||
{
|
{
|
||||||
|
auto addBuiltinPatch = [&](const QString &uid, const QString intendedVersion, int order)
|
||||||
{
|
{
|
||||||
auto mcJson = FS::PathCombine(m_instance->instanceRoot(), "patches" , "net.minecraft.json");
|
auto jsonFilePath = FS::PathCombine(m_instance->instanceRoot(), "patches" , uid + ".json");
|
||||||
// load up the base minecraft patch
|
// load up the base minecraft patch
|
||||||
ProfilePatchPtr minecraftPatch;
|
ProfilePatchPtr profilePatch;
|
||||||
if(QFile::exists(mcJson))
|
if(QFile::exists(jsonFilePath))
|
||||||
{
|
{
|
||||||
auto file = ProfileUtils::parseJsonFile(QFileInfo(mcJson), false);
|
auto file = ProfileUtils::parseJsonFile(QFileInfo(jsonFilePath), false);
|
||||||
if(file->version.isEmpty())
|
if(file->version.isEmpty())
|
||||||
{
|
{
|
||||||
file->version = m_instance->intendedVersionId();
|
file->version = intendedVersion;
|
||||||
}
|
}
|
||||||
file->setVanilla(false);
|
profilePatch = std::make_shared<ProfilePatch>(file, jsonFilePath);
|
||||||
file->setRevertible(true);
|
profilePatch->setVanilla(false);
|
||||||
minecraftPatch = std::dynamic_pointer_cast<ProfilePatch>(file);
|
profilePatch->setRevertible(true);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
auto mcversion = ENV.getVersion("net.minecraft", m_instance->intendedVersionId());
|
auto metaVersion = ENV.metadataIndex()->get(uid, intendedVersion);
|
||||||
minecraftPatch = std::dynamic_pointer_cast<ProfilePatch>(mcversion);
|
profilePatch = std::make_shared<ProfilePatch>(metaVersion);
|
||||||
|
profilePatch->setVanilla(true);
|
||||||
}
|
}
|
||||||
if (!minecraftPatch)
|
if (!profilePatch)
|
||||||
{
|
{
|
||||||
throw VersionIncomplete("net.minecraft");
|
throw VersionIncomplete(uid);
|
||||||
}
|
|
||||||
minecraftPatch->setOrder(-2);
|
|
||||||
profile->appendPatch(minecraftPatch);
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
auto lwjglJson = FS::PathCombine(m_instance->instanceRoot(), "patches" , "org.lwjgl.json");
|
|
||||||
ProfilePatchPtr lwjglPatch;
|
|
||||||
if(QFile::exists(lwjglJson))
|
|
||||||
{
|
|
||||||
auto file = ProfileUtils::parseJsonFile(QFileInfo(lwjglJson), false);
|
|
||||||
file->setVanilla(false);
|
|
||||||
file->setRevertible(true);
|
|
||||||
lwjglPatch = std::dynamic_pointer_cast<ProfilePatch>(file);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// NOTE: this is obviously fake, is fixed in unstable.
|
|
||||||
QResource LWJGL(":/versions/LWJGL/2.9.1.json");
|
|
||||||
auto lwjgl = ProfileUtils::parseJsonFile(LWJGL.absoluteFilePath(), false);
|
|
||||||
lwjgl->setVanilla(true);
|
|
||||||
lwjgl->setCustomizable(true);
|
|
||||||
lwjglPatch = std::dynamic_pointer_cast<ProfilePatch>(lwjgl);
|
|
||||||
}
|
|
||||||
if (!lwjglPatch)
|
|
||||||
{
|
|
||||||
throw VersionIncomplete("org.lwjgl");
|
|
||||||
}
|
|
||||||
lwjglPatch->setOrder(-1);
|
|
||||||
profile->appendPatch(lwjglPatch);
|
|
||||||
}
|
}
|
||||||
|
profilePatch->setOrder(order);
|
||||||
|
profile->appendPatch(profilePatch);
|
||||||
|
};
|
||||||
|
addBuiltinPatch("net.minecraft", m_instance->getComponentVersion("net.minecraft"), -2);
|
||||||
|
addBuiltinPatch("org.lwjgl", m_instance->getComponentVersion("org.lwjgl"), -1);
|
||||||
}
|
}
|
||||||
|
|
||||||
void OneSixProfileStrategy::loadUserPatches()
|
void OneSixProfileStrategy::loadUserPatches()
|
||||||
{
|
{
|
||||||
// load all patches, put into map for ordering, apply in the right order
|
// first, collect all patches (that are not builtins of OneSix) and load them
|
||||||
ProfileUtils::PatchOrder userOrder;
|
QMap<QString, ProfilePatchPtr> loadedPatches;
|
||||||
ProfileUtils::readOverrideOrders(FS::PathCombine(m_instance->instanceRoot(), "order.json"), userOrder);
|
QDir patchesDir(FS::PathCombine(m_instance->instanceRoot(),"patches"));
|
||||||
QDir patches(FS::PathCombine(m_instance->instanceRoot(),"patches"));
|
for (auto info : patchesDir.entryInfoList(QStringList() << "*.json", QDir::Files))
|
||||||
QSet<QString> seen_extra;
|
|
||||||
|
|
||||||
// first, load things by sort order.
|
|
||||||
for (auto id : userOrder)
|
|
||||||
{
|
|
||||||
// ignore builtins
|
|
||||||
if (id == "net.minecraft")
|
|
||||||
continue;
|
|
||||||
if (id == "org.lwjgl")
|
|
||||||
continue;
|
|
||||||
// parse the file
|
|
||||||
QString filename = patches.absoluteFilePath(id + ".json");
|
|
||||||
QFileInfo finfo(filename);
|
|
||||||
if(!finfo.exists())
|
|
||||||
{
|
|
||||||
qDebug() << "Patch file " << filename << " was deleted by external means...";
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
qDebug() << "Reading" << filename << "by user order";
|
|
||||||
VersionFilePtr file = ProfileUtils::parseJsonFile(finfo, false);
|
|
||||||
// sanity check. prevent tampering with files.
|
|
||||||
if (file->fileId != id)
|
|
||||||
{
|
|
||||||
file->addProblem(PROBLEM_WARNING, QObject::tr("load id %1 does not match internal id %2").arg(id, file->fileId));
|
|
||||||
seen_extra.insert(file->fileId);
|
|
||||||
}
|
|
||||||
file->setRemovable(true);
|
|
||||||
file->setMovable(true);
|
|
||||||
// HACK: ignore assets from other version files than Minecraft
|
|
||||||
// workaround for stupid assets issue caused by amazon:
|
|
||||||
// https://www.theregister.co.uk/2017/02/28/aws_is_awol_as_s3_goes_haywire/
|
|
||||||
file->assets = QString();
|
|
||||||
file->mojangAssetIndex.reset();
|
|
||||||
// HACK
|
|
||||||
profile->appendPatch(file);
|
|
||||||
}
|
|
||||||
// now load the rest by internal preference.
|
|
||||||
QMultiMap<int, VersionFilePtr> files;
|
|
||||||
for (auto info : patches.entryInfoList(QStringList() << "*.json", QDir::Files))
|
|
||||||
{
|
{
|
||||||
// parse the file
|
// parse the file
|
||||||
qDebug() << "Reading" << info.fileName();
|
qDebug() << "Reading" << info.fileName();
|
||||||
auto file = ProfileUtils::parseJsonFile(info, true);
|
auto file = ProfileUtils::parseJsonFile(info, true);
|
||||||
// ignore builtins
|
// ignore builtins
|
||||||
if (file->fileId == "net.minecraft")
|
if (file->uid == "net.minecraft")
|
||||||
continue;
|
continue;
|
||||||
if (file->fileId == "org.lwjgl")
|
if (file->uid == "org.lwjgl")
|
||||||
continue;
|
continue;
|
||||||
// do not load versions with broken IDs twice
|
auto patch = std::make_shared<ProfilePatch>(file, info.filePath());
|
||||||
if(seen_extra.contains(file->fileId))
|
patch->setRemovable(true);
|
||||||
continue;
|
patch->setMovable(true);
|
||||||
// do not load what we already loaded in the first pass
|
if(ENV.metadataIndex()->hasUid(file->uid))
|
||||||
if (userOrder.contains(file->fileId))
|
{
|
||||||
continue;
|
// FIXME: requesting a uid/list creates it in the index... this allows reverting to possibly invalid versions...
|
||||||
file->setRemovable(true);
|
patch->setRevertible(true);
|
||||||
file->setMovable(true);
|
|
||||||
// HACK: ignore assets from other version files than Minecraft
|
|
||||||
// workaround for stupid assets issue caused by amazon:
|
|
||||||
// https://www.theregister.co.uk/2017/02/28/aws_is_awol_as_s3_goes_haywire/
|
|
||||||
file->assets = QString();
|
|
||||||
file->mojangAssetIndex.reset();
|
|
||||||
// HACK
|
|
||||||
files.insert(file->order, file);
|
|
||||||
}
|
}
|
||||||
QSet<int> seen;
|
loadedPatches[file->uid] = patch;
|
||||||
|
}
|
||||||
|
// these are 'special'... if not already loaded from instance files, grab them from the metadata repo.
|
||||||
|
auto loadSpecial = [&](const QString & uid, int order)
|
||||||
|
{
|
||||||
|
auto patchVersion = m_instance->getComponentVersion(uid);
|
||||||
|
if(!patchVersion.isEmpty() && !loadedPatches.contains(uid))
|
||||||
|
{
|
||||||
|
auto patch = std::make_shared<ProfilePatch>(ENV.metadataIndex()->get(uid, patchVersion));
|
||||||
|
patch->setOrder(order);
|
||||||
|
patch->setVanilla(true);
|
||||||
|
patch->setRemovable(true);
|
||||||
|
patch->setMovable(true);
|
||||||
|
loadedPatches[uid] = patch;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
loadSpecial("net.minecraftforge", 5);
|
||||||
|
loadSpecial("com.mumfrey.liteloader", 10);
|
||||||
|
|
||||||
|
// now add all the patches by user sort order
|
||||||
|
ProfileUtils::PatchOrder userOrder;
|
||||||
|
ProfileUtils::readOverrideOrders(FS::PathCombine(m_instance->instanceRoot(), "order.json"), userOrder);
|
||||||
|
bool orderIsDirty = false;
|
||||||
|
for (auto uid : userOrder)
|
||||||
|
{
|
||||||
|
// ignore builtins
|
||||||
|
if (uid == "net.minecraft")
|
||||||
|
continue;
|
||||||
|
if (uid == "org.lwjgl")
|
||||||
|
continue;
|
||||||
|
// ordering has a patch that is gone?
|
||||||
|
if(!loadedPatches.contains(uid))
|
||||||
|
{
|
||||||
|
orderIsDirty = true;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
profile->appendPatch(loadedPatches.take(uid));
|
||||||
|
}
|
||||||
|
|
||||||
|
// is there anything left to sort?
|
||||||
|
if(loadedPatches.isEmpty())
|
||||||
|
{
|
||||||
|
// TODO: save the order here?
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// inserting into multimap by order number as key sorts the patches and detects duplicates
|
||||||
|
QMultiMap<int, ProfilePatchPtr> files;
|
||||||
|
auto iter = loadedPatches.begin();
|
||||||
|
while(iter != loadedPatches.end())
|
||||||
|
{
|
||||||
|
files.insert((*iter)->getOrder(), *iter);
|
||||||
|
iter++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// then just extract the patches and put them in the list
|
||||||
for (auto order : files.keys())
|
for (auto order : files.keys())
|
||||||
{
|
{
|
||||||
if(seen.contains(order))
|
|
||||||
continue;
|
|
||||||
seen.insert(order);
|
|
||||||
const auto &values = files.values(order);
|
const auto &values = files.values(order);
|
||||||
if(values.size() == 1)
|
for(auto &value: values)
|
||||||
{
|
{
|
||||||
profile->appendPatch(values[0]);
|
// TODO: put back the insertion of problem messages here, so the user knows about the id duplication
|
||||||
continue;
|
profile->appendPatch(value);
|
||||||
}
|
|
||||||
for(auto &file: values)
|
|
||||||
{
|
|
||||||
QStringList list;
|
|
||||||
for(auto &file2: values)
|
|
||||||
{
|
|
||||||
if(file != file2)
|
|
||||||
list.append(file2->name);
|
|
||||||
}
|
|
||||||
file->addProblem(PROBLEM_WARNING, QObject::tr("%1 has the same order as the following components:\n%2").arg(file->name, list.join(", ")));
|
|
||||||
profile->appendPatch(file);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// TODO: save the order here?
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -266,7 +243,10 @@ bool OneSixProfileStrategy::removePatch(ProfilePatchPtr patch)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if(!m_instance->getComponentVersion(patch->getID()).isEmpty())
|
||||||
|
{
|
||||||
|
m_instance->setComponentVersion(patch->getID(), QString());
|
||||||
|
}
|
||||||
|
|
||||||
auto preRemoveJarMod = [&](JarmodPtr jarMod) -> bool
|
auto preRemoveJarMod = [&](JarmodPtr jarMod) -> bool
|
||||||
{
|
{
|
||||||
@ -285,7 +265,8 @@ bool OneSixProfileStrategy::removePatch(ProfilePatchPtr patch)
|
|||||||
return true;
|
return true;
|
||||||
};
|
};
|
||||||
|
|
||||||
for(auto &jarmod: patch->getJarMods())
|
auto &jarMods = patch->getVersionFile()->jarMods;
|
||||||
|
for(auto &jarmod: jarMods)
|
||||||
{
|
{
|
||||||
ok &= preRemoveJarMod(jarmod);
|
ok &= preRemoveJarMod(jarmod);
|
||||||
}
|
}
|
||||||
@ -405,12 +386,9 @@ bool OneSixProfileStrategy::installJarMods(QStringList filepaths)
|
|||||||
jarMod->originalName = sourceInfo.completeBaseName();
|
jarMod->originalName = sourceInfo.completeBaseName();
|
||||||
f->jarMods.append(jarMod);
|
f->jarMods.append(jarMod);
|
||||||
f->name = target_name;
|
f->name = target_name;
|
||||||
f->fileId = target_id;
|
f->uid = target_id;
|
||||||
f->order = profile->getFreeOrderNumber();
|
f->order = profile->getFreeOrderNumber();
|
||||||
QString patchFileName = FS::PathCombine(patchDir, target_id + ".json");
|
QString patchFileName = FS::PathCombine(patchDir, target_id + ".json");
|
||||||
f->filename = patchFileName;
|
|
||||||
f->setMovable(true);
|
|
||||||
f->setRemovable(true);
|
|
||||||
|
|
||||||
QFile file(patchFileName);
|
QFile file(patchFileName);
|
||||||
if (!file.open(QFile::WriteOnly))
|
if (!file.open(QFile::WriteOnly))
|
||||||
@ -421,7 +399,11 @@ bool OneSixProfileStrategy::installJarMods(QStringList filepaths)
|
|||||||
}
|
}
|
||||||
file.write(OneSixVersionFormat::versionFileToJson(f, true).toJson());
|
file.write(OneSixVersionFormat::versionFileToJson(f, true).toJson());
|
||||||
file.close();
|
file.close();
|
||||||
profile->appendPatch(f);
|
|
||||||
|
auto patch = std::make_shared<ProfilePatch>(f, patchFileName);
|
||||||
|
patch->setMovable(true);
|
||||||
|
patch->setRemovable(true);
|
||||||
|
profile->appendPatch(patch);
|
||||||
}
|
}
|
||||||
profile->saveCurrentOrder();
|
profile->saveCurrentOrder();
|
||||||
profile->reapplyPatches();
|
profile->reapplyPatches();
|
||||||
|
@ -24,7 +24,6 @@
|
|||||||
#include <QDataStream>
|
#include <QDataStream>
|
||||||
|
|
||||||
#include "BaseInstance.h"
|
#include "BaseInstance.h"
|
||||||
#include "minecraft/MinecraftVersionList.h"
|
|
||||||
#include "minecraft/MinecraftProfile.h"
|
#include "minecraft/MinecraftProfile.h"
|
||||||
#include "minecraft/Library.h"
|
#include "minecraft/Library.h"
|
||||||
#include "net/URLConstants.h"
|
#include "net/URLConstants.h"
|
||||||
@ -35,6 +34,9 @@
|
|||||||
#include "update/FMLLibrariesTask.h"
|
#include "update/FMLLibrariesTask.h"
|
||||||
#include "update/AssetUpdateTask.h"
|
#include "update/AssetUpdateTask.h"
|
||||||
|
|
||||||
|
#include <meta/Index.h>
|
||||||
|
#include <meta/Version.h>
|
||||||
|
|
||||||
OneSixUpdate::OneSixUpdate(OneSixInstance *inst, QObject *parent) : Task(parent), m_inst(inst)
|
OneSixUpdate::OneSixUpdate(OneSixInstance *inst, QObject *parent) : Task(parent), m_inst(inst)
|
||||||
{
|
{
|
||||||
// create folders
|
// create folders
|
||||||
@ -44,29 +46,23 @@ OneSixUpdate::OneSixUpdate(OneSixInstance *inst, QObject *parent) : Task(parent)
|
|||||||
|
|
||||||
// add a version update task, if necessary
|
// add a version update task, if necessary
|
||||||
{
|
{
|
||||||
auto list = std::dynamic_pointer_cast<MinecraftVersionList>(ENV.getVersionList("net.minecraft"));
|
/*
|
||||||
auto version = std::dynamic_pointer_cast<MinecraftVersion>(list->findVersion(m_inst->intendedVersionId()));
|
* FIXME: there are some corner cases here that remain unhandled:
|
||||||
if (version == nullptr)
|
* what if local load succeeds but remote fails? The version is still usable...
|
||||||
|
*/
|
||||||
|
// FIXME: derive this from the actual list of version patches...
|
||||||
|
auto loadVersion = [&](const QString & uid, const QString & version)
|
||||||
{
|
{
|
||||||
// don't do anything if it was invalid
|
auto obj = ENV.metadataIndex()->get(uid, version);
|
||||||
m_preFailure = tr("The specified Minecraft version is invalid. Choose a different one.");
|
obj->load();
|
||||||
}
|
auto task = obj->getCurrentTask();
|
||||||
else if (m_inst->providesVersionFile() || !version->needsUpdate())
|
if(task)
|
||||||
{
|
{
|
||||||
qDebug() << "Instance either provides a version file or doesn't need an update.";
|
m_tasks.append(task.unwrap());
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
auto versionUpdateTask = list->createUpdateTask(m_inst->intendedVersionId());
|
|
||||||
if (!versionUpdateTask)
|
|
||||||
{
|
|
||||||
qDebug() << "Didn't spawn an update task.";
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
m_tasks.append(versionUpdateTask);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
loadVersion("org.lwjgl", m_inst->getComponentVersion("org.lwjgl"));
|
||||||
|
loadVersion("net.minecraft", m_inst->getComponentVersion("net.minecraft"));
|
||||||
}
|
}
|
||||||
|
|
||||||
// libraries download
|
// libraries download
|
||||||
@ -117,11 +113,20 @@ void OneSixUpdate::next()
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
auto task = m_tasks[m_currentTask];
|
auto task = m_tasks[m_currentTask];
|
||||||
|
// if the task is already finished by the time we look at it, skip it
|
||||||
|
if(task->isFinished())
|
||||||
|
{
|
||||||
|
next();
|
||||||
|
}
|
||||||
connect(task.get(), &Task::succeeded, this, &OneSixUpdate::subtaskSucceeded);
|
connect(task.get(), &Task::succeeded, this, &OneSixUpdate::subtaskSucceeded);
|
||||||
connect(task.get(), &Task::failed, this, &OneSixUpdate::subtaskFailed);
|
connect(task.get(), &Task::failed, this, &OneSixUpdate::subtaskFailed);
|
||||||
connect(task.get(), &Task::progress, this, &OneSixUpdate::progress);
|
connect(task.get(), &Task::progress, this, &OneSixUpdate::progress);
|
||||||
connect(task.get(), &Task::status, this, &OneSixUpdate::setStatus);
|
connect(task.get(), &Task::status, this, &OneSixUpdate::setStatus);
|
||||||
|
// if the task is already running, do not start it again
|
||||||
|
if(!task->isRunning())
|
||||||
|
{
|
||||||
task->start();
|
task->start();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void OneSixUpdate::subtaskSucceeded()
|
void OneSixUpdate::subtaskSucceeded()
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
#include "OneSixVersionFormat.h"
|
#include "OneSixVersionFormat.h"
|
||||||
#include <Json.h>
|
#include <Json.h>
|
||||||
#include "minecraft/ParseUtils.h"
|
#include "minecraft/ParseUtils.h"
|
||||||
#include <minecraft/MinecraftVersion.h>
|
|
||||||
#include <minecraft/VersionBuildError.h>
|
#include <minecraft/VersionBuildError.h>
|
||||||
#include <minecraft/MojangVersionFormat.h>
|
#include <minecraft/MojangVersionFormat.h>
|
||||||
|
|
||||||
@ -62,10 +61,19 @@ VersionFilePtr OneSixVersionFormat::versionFileFromJson(const QJsonDocument &doc
|
|||||||
}
|
}
|
||||||
|
|
||||||
out->name = root.value("name").toString();
|
out->name = root.value("name").toString();
|
||||||
out->fileId = root.value("fileId").toString();
|
|
||||||
|
if(root.contains("uid"))
|
||||||
|
{
|
||||||
|
out->uid = root.value("uid").toString();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
out->uid = root.value("fileId").toString();
|
||||||
|
}
|
||||||
|
|
||||||
out->version = root.value("version").toString();
|
out->version = root.value("version").toString();
|
||||||
out->dependsOnMinecraftVersion = root.value("mcVersion").toString();
|
out->dependsOnMinecraftVersion = root.value("mcVersion").toString();
|
||||||
out->filename = filename;
|
// out->filename = filename;
|
||||||
|
|
||||||
MojangVersionFormat::readVersionProperties(root, out.get());
|
MojangVersionFormat::readVersionProperties(root, out.get());
|
||||||
|
|
||||||
@ -120,7 +128,8 @@ VersionFilePtr OneSixVersionFormat::versionFileFromJson(const QJsonDocument &doc
|
|||||||
bool hasLibs = root.contains("libraries");
|
bool hasLibs = root.contains("libraries");
|
||||||
if (hasPlusLibs && hasLibs)
|
if (hasPlusLibs && hasLibs)
|
||||||
{
|
{
|
||||||
out->addProblem(PROBLEM_WARNING, QObject::tr("Version file has both '+libraries' and 'libraries'. This is no longer supported."));
|
out->addProblem(ProblemSeverity::Warning,
|
||||||
|
QObject::tr("Version file has both '+libraries' and 'libraries'. This is no longer supported."));
|
||||||
readLibs("libraries");
|
readLibs("libraries");
|
||||||
readLibs("+libraries");
|
readLibs("+libraries");
|
||||||
}
|
}
|
||||||
@ -136,23 +145,23 @@ VersionFilePtr OneSixVersionFormat::versionFileFromJson(const QJsonDocument &doc
|
|||||||
/* removed features that shouldn't be used */
|
/* removed features that shouldn't be used */
|
||||||
if (root.contains("tweakers"))
|
if (root.contains("tweakers"))
|
||||||
{
|
{
|
||||||
out->addProblem(PROBLEM_ERROR, QObject::tr("Version file contains unsupported element 'tweakers'"));
|
out->addProblem(ProblemSeverity::Error, QObject::tr("Version file contains unsupported element 'tweakers'"));
|
||||||
}
|
}
|
||||||
if (root.contains("-libraries"))
|
if (root.contains("-libraries"))
|
||||||
{
|
{
|
||||||
out->addProblem(PROBLEM_ERROR, QObject::tr("Version file contains unsupported element '-libraries'"));
|
out->addProblem(ProblemSeverity::Error, QObject::tr("Version file contains unsupported element '-libraries'"));
|
||||||
}
|
}
|
||||||
if (root.contains("-tweakers"))
|
if (root.contains("-tweakers"))
|
||||||
{
|
{
|
||||||
out->addProblem(PROBLEM_ERROR, QObject::tr("Version file contains unsupported element '-tweakers'"));
|
out->addProblem(ProblemSeverity::Error, QObject::tr("Version file contains unsupported element '-tweakers'"));
|
||||||
}
|
}
|
||||||
if (root.contains("-minecraftArguments"))
|
if (root.contains("-minecraftArguments"))
|
||||||
{
|
{
|
||||||
out->addProblem(PROBLEM_ERROR, QObject::tr("Version file contains unsupported element '-minecraftArguments'"));
|
out->addProblem(ProblemSeverity::Error, QObject::tr("Version file contains unsupported element '-minecraftArguments'"));
|
||||||
}
|
}
|
||||||
if (root.contains("+minecraftArguments"))
|
if (root.contains("+minecraftArguments"))
|
||||||
{
|
{
|
||||||
out->addProblem(PROBLEM_ERROR, QObject::tr("Version file contains unsupported element '+minecraftArguments'"));
|
out->addProblem(ProblemSeverity::Error, QObject::tr("Version file contains unsupported element '+minecraftArguments'"));
|
||||||
}
|
}
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
@ -165,7 +174,10 @@ QJsonDocument OneSixVersionFormat::versionFileToJson(const VersionFilePtr &patch
|
|||||||
root.insert("order", patch->order);
|
root.insert("order", patch->order);
|
||||||
}
|
}
|
||||||
writeString(root, "name", patch->name);
|
writeString(root, "name", patch->name);
|
||||||
writeString(root, "fileId", patch->fileId);
|
|
||||||
|
writeString(root, "uid", patch->uid);
|
||||||
|
writeString(root, "fileId", patch->uid);
|
||||||
|
|
||||||
writeString(root, "version", patch->version);
|
writeString(root, "version", patch->version);
|
||||||
writeString(root, "mcVersion", patch->dependsOnMinecraftVersion);
|
writeString(root, "mcVersion", patch->dependsOnMinecraftVersion);
|
||||||
|
|
||||||
|
@ -35,11 +35,11 @@ void LibrariesTask::executeTask()
|
|||||||
downloadJob.reset(job);
|
downloadJob.reset(job);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto libs = profile->getLibraries();
|
|
||||||
|
|
||||||
auto metacache = ENV.metacache();
|
auto metacache = ENV.metacache();
|
||||||
QList<LibraryPtr> brokenLocalLibs;
|
QList<LibraryPtr> brokenLocalLibs;
|
||||||
QStringList failedFiles;
|
QStringList failedFiles;
|
||||||
|
auto createJobs = [&](const QList<LibraryPtr> & libs)
|
||||||
|
{
|
||||||
for (auto lib : libs)
|
for (auto lib : libs)
|
||||||
{
|
{
|
||||||
auto dls = lib->getDownloads(currentSystem, metacache.get(), failedFiles, inst->getLocalLibraryPath());
|
auto dls = lib->getDownloads(currentSystem, metacache.get(), failedFiles, inst->getLocalLibraryPath());
|
||||||
@ -48,6 +48,10 @@ void LibrariesTask::executeTask()
|
|||||||
downloadJob->addNetAction(dl);
|
downloadJob->addNetAction(dl);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
createJobs(profile->getLibraries());
|
||||||
|
createJobs(profile->getNativeLibraries());
|
||||||
|
|
||||||
// FIXME: this is never filled!!!!
|
// FIXME: this is never filled!!!!
|
||||||
if (!brokenLocalLibs.empty())
|
if (!brokenLocalLibs.empty())
|
||||||
{
|
{
|
||||||
|
@ -1,39 +0,0 @@
|
|||||||
/* Copyright 2015-2017 MultiMC Contributors
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "BaseWonkoEntity.h"
|
|
||||||
|
|
||||||
#include "Json.h"
|
|
||||||
#include "WonkoUtil.h"
|
|
||||||
|
|
||||||
BaseWonkoEntity::~BaseWonkoEntity()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void BaseWonkoEntity::store() const
|
|
||||||
{
|
|
||||||
Json::write(serialized(), Wonko::localWonkoDir().absoluteFilePath(localFilename()));
|
|
||||||
}
|
|
||||||
|
|
||||||
void BaseWonkoEntity::notifyLocalLoadComplete()
|
|
||||||
{
|
|
||||||
m_localLoaded = true;
|
|
||||||
store();
|
|
||||||
}
|
|
||||||
void BaseWonkoEntity::notifyRemoteLoadComplete()
|
|
||||||
{
|
|
||||||
m_remoteLoaded = true;
|
|
||||||
store();
|
|
||||||
}
|
|
@ -1,51 +0,0 @@
|
|||||||
/* Copyright 2015-2017 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 <QObject>
|
|
||||||
#include <memory>
|
|
||||||
|
|
||||||
#include "multimc_logic_export.h"
|
|
||||||
|
|
||||||
class Task;
|
|
||||||
|
|
||||||
class MULTIMC_LOGIC_EXPORT BaseWonkoEntity
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
virtual ~BaseWonkoEntity();
|
|
||||||
|
|
||||||
using Ptr = std::shared_ptr<BaseWonkoEntity>;
|
|
||||||
|
|
||||||
virtual std::unique_ptr<Task> remoteUpdateTask() = 0;
|
|
||||||
virtual std::unique_ptr<Task> localUpdateTask() = 0;
|
|
||||||
virtual void merge(const std::shared_ptr<BaseWonkoEntity> &other) = 0;
|
|
||||||
|
|
||||||
void store() const;
|
|
||||||
virtual QString localFilename() const = 0;
|
|
||||||
virtual QJsonObject serialized() const = 0;
|
|
||||||
|
|
||||||
bool isComplete() const { return m_localLoaded || m_remoteLoaded; }
|
|
||||||
|
|
||||||
bool isLocalLoaded() const { return m_localLoaded; }
|
|
||||||
bool isRemoteLoaded() const { return m_remoteLoaded; }
|
|
||||||
|
|
||||||
void notifyLocalLoadComplete();
|
|
||||||
void notifyRemoteLoadComplete();
|
|
||||||
|
|
||||||
private:
|
|
||||||
bool m_localLoaded = false;
|
|
||||||
bool m_remoteLoaded = false;
|
|
||||||
};
|
|
@ -1,50 +0,0 @@
|
|||||||
#include <QTest>
|
|
||||||
#include "TestUtil.h"
|
|
||||||
|
|
||||||
#include "wonko/WonkoIndex.h"
|
|
||||||
#include "wonko/WonkoVersionList.h"
|
|
||||||
#include "Env.h"
|
|
||||||
|
|
||||||
class WonkoIndexTest : public QObject
|
|
||||||
{
|
|
||||||
Q_OBJECT
|
|
||||||
private
|
|
||||||
slots:
|
|
||||||
void test_isProvidedByEnv()
|
|
||||||
{
|
|
||||||
QVERIFY(ENV.wonkoIndex());
|
|
||||||
QCOMPARE(ENV.wonkoIndex(), ENV.wonkoIndex());
|
|
||||||
}
|
|
||||||
|
|
||||||
void test_providesTasks()
|
|
||||||
{
|
|
||||||
QVERIFY(ENV.wonkoIndex()->localUpdateTask() != nullptr);
|
|
||||||
QVERIFY(ENV.wonkoIndex()->remoteUpdateTask() != nullptr);
|
|
||||||
}
|
|
||||||
|
|
||||||
void test_hasUid_and_getList()
|
|
||||||
{
|
|
||||||
WonkoIndex windex({std::make_shared<WonkoVersionList>("list1"), std::make_shared<WonkoVersionList>("list2"), std::make_shared<WonkoVersionList>("list3")});
|
|
||||||
QVERIFY(windex.hasUid("list1"));
|
|
||||||
QVERIFY(!windex.hasUid("asdf"));
|
|
||||||
QVERIFY(windex.getList("list2") != nullptr);
|
|
||||||
QCOMPARE(windex.getList("list2")->uid(), QString("list2"));
|
|
||||||
QVERIFY(windex.getList("adsf") == nullptr);
|
|
||||||
}
|
|
||||||
|
|
||||||
void test_merge()
|
|
||||||
{
|
|
||||||
WonkoIndex windex({std::make_shared<WonkoVersionList>("list1"), std::make_shared<WonkoVersionList>("list2"), std::make_shared<WonkoVersionList>("list3")});
|
|
||||||
QCOMPARE(windex.lists().size(), 3);
|
|
||||||
windex.merge(std::shared_ptr<WonkoIndex>(new WonkoIndex({std::make_shared<WonkoVersionList>("list1"), std::make_shared<WonkoVersionList>("list2"), std::make_shared<WonkoVersionList>("list3")})));
|
|
||||||
QCOMPARE(windex.lists().size(), 3);
|
|
||||||
windex.merge(std::shared_ptr<WonkoIndex>(new WonkoIndex({std::make_shared<WonkoVersionList>("list4"), std::make_shared<WonkoVersionList>("list2"), std::make_shared<WonkoVersionList>("list5")})));
|
|
||||||
QCOMPARE(windex.lists().size(), 5);
|
|
||||||
windex.merge(std::shared_ptr<WonkoIndex>(new WonkoIndex({std::make_shared<WonkoVersionList>("list6")})));
|
|
||||||
QCOMPARE(windex.lists().size(), 6);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
QTEST_GUILESS_MAIN(WonkoIndexTest)
|
|
||||||
|
|
||||||
#include "WonkoIndex_test.moc"
|
|
@ -1,44 +0,0 @@
|
|||||||
/* Copyright 2015-2017 MultiMC Contributors
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "WonkoReference.h"
|
|
||||||
|
|
||||||
WonkoReference::WonkoReference(const QString &uid)
|
|
||||||
: m_uid(uid)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
QString WonkoReference::uid() const
|
|
||||||
{
|
|
||||||
return m_uid;
|
|
||||||
}
|
|
||||||
|
|
||||||
QString WonkoReference::version() const
|
|
||||||
{
|
|
||||||
return m_version;
|
|
||||||
}
|
|
||||||
void WonkoReference::setVersion(const QString &version)
|
|
||||||
{
|
|
||||||
m_version = version;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool WonkoReference::operator==(const WonkoReference &other) const
|
|
||||||
{
|
|
||||||
return m_uid == other.m_uid && m_version == other.m_version;
|
|
||||||
}
|
|
||||||
bool WonkoReference::operator!=(const WonkoReference &other) const
|
|
||||||
{
|
|
||||||
return m_uid != other.m_uid || m_version != other.m_version;
|
|
||||||
}
|
|
@ -1,41 +0,0 @@
|
|||||||
/* Copyright 2015-2017 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 <QString>
|
|
||||||
#include <QMetaType>
|
|
||||||
|
|
||||||
#include "multimc_logic_export.h"
|
|
||||||
|
|
||||||
class MULTIMC_LOGIC_EXPORT WonkoReference
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
WonkoReference() {}
|
|
||||||
explicit WonkoReference(const QString &uid);
|
|
||||||
|
|
||||||
QString uid() const;
|
|
||||||
|
|
||||||
QString version() const;
|
|
||||||
void setVersion(const QString &version);
|
|
||||||
|
|
||||||
bool operator==(const WonkoReference &other) const;
|
|
||||||
bool operator!=(const WonkoReference &other) const;
|
|
||||||
|
|
||||||
private:
|
|
||||||
QString m_uid;
|
|
||||||
QString m_version;
|
|
||||||
};
|
|
||||||
Q_DECLARE_METATYPE(WonkoReference)
|
|
@ -1,47 +0,0 @@
|
|||||||
/* Copyright 2015-2017 MultiMC Contributors
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "WonkoUtil.h"
|
|
||||||
|
|
||||||
#include <QUrl>
|
|
||||||
#include <QDir>
|
|
||||||
|
|
||||||
#include "Env.h"
|
|
||||||
|
|
||||||
namespace Wonko
|
|
||||||
{
|
|
||||||
QUrl rootUrl()
|
|
||||||
{
|
|
||||||
return ENV.wonkoRootUrl();
|
|
||||||
}
|
|
||||||
QUrl indexUrl()
|
|
||||||
{
|
|
||||||
return rootUrl().resolved(QStringLiteral("index.json"));
|
|
||||||
}
|
|
||||||
QUrl versionListUrl(const QString &uid)
|
|
||||||
{
|
|
||||||
return rootUrl().resolved(uid + ".json");
|
|
||||||
}
|
|
||||||
QUrl versionUrl(const QString &uid, const QString &version)
|
|
||||||
{
|
|
||||||
return rootUrl().resolved(uid + "/" + version + ".json");
|
|
||||||
}
|
|
||||||
|
|
||||||
QDir localWonkoDir()
|
|
||||||
{
|
|
||||||
return QDir("wonko");
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -1,102 +0,0 @@
|
|||||||
/* Copyright 2015-2017 MultiMC Contributors
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "WonkoVersion.h"
|
|
||||||
|
|
||||||
#include <QDateTime>
|
|
||||||
|
|
||||||
#include "tasks/BaseWonkoEntityLocalLoadTask.h"
|
|
||||||
#include "tasks/BaseWonkoEntityRemoteLoadTask.h"
|
|
||||||
#include "format/WonkoFormat.h"
|
|
||||||
|
|
||||||
WonkoVersion::WonkoVersion(const QString &uid, const QString &version)
|
|
||||||
: BaseVersion(), m_uid(uid), m_version(version)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
QString WonkoVersion::descriptor()
|
|
||||||
{
|
|
||||||
return m_version;
|
|
||||||
}
|
|
||||||
QString WonkoVersion::name()
|
|
||||||
{
|
|
||||||
return m_version;
|
|
||||||
}
|
|
||||||
QString WonkoVersion::typeString() const
|
|
||||||
{
|
|
||||||
return m_type;
|
|
||||||
}
|
|
||||||
|
|
||||||
QDateTime WonkoVersion::time() const
|
|
||||||
{
|
|
||||||
return QDateTime::fromMSecsSinceEpoch(m_time * 1000, Qt::UTC);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::unique_ptr<Task> WonkoVersion::remoteUpdateTask()
|
|
||||||
{
|
|
||||||
return std::unique_ptr<WonkoVersionRemoteLoadTask>(new WonkoVersionRemoteLoadTask(this, this));
|
|
||||||
}
|
|
||||||
std::unique_ptr<Task> WonkoVersion::localUpdateTask()
|
|
||||||
{
|
|
||||||
return std::unique_ptr<WonkoVersionLocalLoadTask>(new WonkoVersionLocalLoadTask(this, this));
|
|
||||||
}
|
|
||||||
|
|
||||||
void WonkoVersion::merge(const std::shared_ptr<BaseWonkoEntity> &other)
|
|
||||||
{
|
|
||||||
WonkoVersionPtr version = std::dynamic_pointer_cast<WonkoVersion>(other);
|
|
||||||
if (m_type != version->m_type)
|
|
||||||
{
|
|
||||||
setType(version->m_type);
|
|
||||||
}
|
|
||||||
if (m_time != version->m_time)
|
|
||||||
{
|
|
||||||
setTime(version->m_time);
|
|
||||||
}
|
|
||||||
if (m_requires != version->m_requires)
|
|
||||||
{
|
|
||||||
setRequires(version->m_requires);
|
|
||||||
}
|
|
||||||
|
|
||||||
setData(version->m_data);
|
|
||||||
}
|
|
||||||
|
|
||||||
QString WonkoVersion::localFilename() const
|
|
||||||
{
|
|
||||||
return m_uid + '/' + m_version + ".json";
|
|
||||||
}
|
|
||||||
QJsonObject WonkoVersion::serialized() const
|
|
||||||
{
|
|
||||||
return WonkoFormat::serializeVersion(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
void WonkoVersion::setType(const QString &type)
|
|
||||||
{
|
|
||||||
m_type = type;
|
|
||||||
emit typeChanged();
|
|
||||||
}
|
|
||||||
void WonkoVersion::setTime(const qint64 time)
|
|
||||||
{
|
|
||||||
m_time = time;
|
|
||||||
emit timeChanged();
|
|
||||||
}
|
|
||||||
void WonkoVersion::setRequires(const QVector<WonkoReference> &requires)
|
|
||||||
{
|
|
||||||
m_requires = requires;
|
|
||||||
emit requiresChanged();
|
|
||||||
}
|
|
||||||
void WonkoVersion::setData(const VersionFilePtr &data)
|
|
||||||
{
|
|
||||||
m_data = data;
|
|
||||||
}
|
|
@ -1,283 +0,0 @@
|
|||||||
/* Copyright 2015-2017 MultiMC Contributors
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "WonkoVersionList.h"
|
|
||||||
|
|
||||||
#include <QDateTime>
|
|
||||||
|
|
||||||
#include "WonkoVersion.h"
|
|
||||||
#include "tasks/BaseWonkoEntityRemoteLoadTask.h"
|
|
||||||
#include "tasks/BaseWonkoEntityLocalLoadTask.h"
|
|
||||||
#include "format/WonkoFormat.h"
|
|
||||||
#include "WonkoReference.h"
|
|
||||||
|
|
||||||
class WVLLoadTask : public Task
|
|
||||||
{
|
|
||||||
Q_OBJECT
|
|
||||||
public:
|
|
||||||
explicit WVLLoadTask(WonkoVersionList *list, QObject *parent = nullptr)
|
|
||||||
: Task(parent), m_list(list)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
bool canAbort() const override
|
|
||||||
{
|
|
||||||
return !m_currentTask || m_currentTask->canAbort();
|
|
||||||
}
|
|
||||||
bool abort() override
|
|
||||||
{
|
|
||||||
return m_currentTask->abort();
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
void executeTask() override
|
|
||||||
{
|
|
||||||
if (!m_list->isLocalLoaded())
|
|
||||||
{
|
|
||||||
m_currentTask = m_list->localUpdateTask();
|
|
||||||
connect(m_currentTask.get(), &Task::succeeded, this, &WVLLoadTask::next);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
m_currentTask = m_list->remoteUpdateTask();
|
|
||||||
connect(m_currentTask.get(), &Task::succeeded, this, &WVLLoadTask::emitSucceeded);
|
|
||||||
}
|
|
||||||
connect(m_currentTask.get(), &Task::status, this, &WVLLoadTask::setStatus);
|
|
||||||
connect(m_currentTask.get(), &Task::progress, this, &WVLLoadTask::setProgress);
|
|
||||||
connect(m_currentTask.get(), &Task::failed, this, &WVLLoadTask::emitFailed);
|
|
||||||
m_currentTask->start();
|
|
||||||
}
|
|
||||||
|
|
||||||
void next()
|
|
||||||
{
|
|
||||||
m_currentTask = m_list->remoteUpdateTask();
|
|
||||||
connect(m_currentTask.get(), &Task::status, this, &WVLLoadTask::setStatus);
|
|
||||||
connect(m_currentTask.get(), &Task::progress, this, &WVLLoadTask::setProgress);
|
|
||||||
connect(m_currentTask.get(), &Task::succeeded, this, &WVLLoadTask::emitSucceeded);
|
|
||||||
m_currentTask->start();
|
|
||||||
}
|
|
||||||
|
|
||||||
WonkoVersionList *m_list;
|
|
||||||
std::unique_ptr<Task> m_currentTask;
|
|
||||||
};
|
|
||||||
|
|
||||||
WonkoVersionList::WonkoVersionList(const QString &uid, QObject *parent)
|
|
||||||
: BaseVersionList(parent), m_uid(uid)
|
|
||||||
{
|
|
||||||
setObjectName("Wonko version list: " + uid);
|
|
||||||
}
|
|
||||||
|
|
||||||
Task *WonkoVersionList::getLoadTask()
|
|
||||||
{
|
|
||||||
return new WVLLoadTask(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool WonkoVersionList::isLoaded()
|
|
||||||
{
|
|
||||||
return isLocalLoaded() && isRemoteLoaded();
|
|
||||||
}
|
|
||||||
|
|
||||||
const BaseVersionPtr WonkoVersionList::at(int i) const
|
|
||||||
{
|
|
||||||
return m_versions.at(i);
|
|
||||||
}
|
|
||||||
int WonkoVersionList::count() const
|
|
||||||
{
|
|
||||||
return m_versions.size();
|
|
||||||
}
|
|
||||||
|
|
||||||
void WonkoVersionList::sortVersions()
|
|
||||||
{
|
|
||||||
beginResetModel();
|
|
||||||
std::sort(m_versions.begin(), m_versions.end(), [](const WonkoVersionPtr &a, const WonkoVersionPtr &b)
|
|
||||||
{
|
|
||||||
return *a.get() < *b.get();
|
|
||||||
});
|
|
||||||
endResetModel();
|
|
||||||
}
|
|
||||||
|
|
||||||
QVariant WonkoVersionList::data(const QModelIndex &index, int role) const
|
|
||||||
{
|
|
||||||
if (!index.isValid() || index.row() < 0 || index.row() >= m_versions.size() || index.parent().isValid())
|
|
||||||
{
|
|
||||||
return QVariant();
|
|
||||||
}
|
|
||||||
|
|
||||||
WonkoVersionPtr version = m_versions.at(index.row());
|
|
||||||
|
|
||||||
switch (role)
|
|
||||||
{
|
|
||||||
case VersionPointerRole: return QVariant::fromValue(std::dynamic_pointer_cast<BaseVersion>(version));
|
|
||||||
case VersionRole:
|
|
||||||
case VersionIdRole:
|
|
||||||
return version->version();
|
|
||||||
case ParentGameVersionRole:
|
|
||||||
{
|
|
||||||
const auto end = version->requires().end();
|
|
||||||
const auto it = std::find_if(version->requires().begin(), end,
|
|
||||||
[](const WonkoReference &ref) { return ref.uid() == "net.minecraft"; });
|
|
||||||
if (it != end)
|
|
||||||
{
|
|
||||||
return (*it).version();
|
|
||||||
}
|
|
||||||
return QVariant();
|
|
||||||
}
|
|
||||||
case TypeRole: return version->type();
|
|
||||||
|
|
||||||
case UidRole: return version->uid();
|
|
||||||
case TimeRole: return version->time();
|
|
||||||
case RequiresRole: return QVariant::fromValue(version->requires());
|
|
||||||
case SortRole: return version->rawTime();
|
|
||||||
case WonkoVersionPtrRole: return QVariant::fromValue(version);
|
|
||||||
case RecommendedRole: return version == getRecommended();
|
|
||||||
case LatestRole: return version == getLatestStable();
|
|
||||||
default: return QVariant();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
BaseVersionList::RoleList WonkoVersionList::providesRoles() const
|
|
||||||
{
|
|
||||||
return {VersionPointerRole, VersionRole, VersionIdRole, ParentGameVersionRole,
|
|
||||||
TypeRole, UidRole, TimeRole, RequiresRole, SortRole,
|
|
||||||
RecommendedRole, LatestRole, WonkoVersionPtrRole};
|
|
||||||
}
|
|
||||||
|
|
||||||
QHash<int, QByteArray> WonkoVersionList::roleNames() const
|
|
||||||
{
|
|
||||||
QHash<int, QByteArray> roles = BaseVersionList::roleNames();
|
|
||||||
roles.insert(UidRole, "uid");
|
|
||||||
roles.insert(TimeRole, "time");
|
|
||||||
roles.insert(SortRole, "sort");
|
|
||||||
roles.insert(RequiresRole, "requires");
|
|
||||||
return roles;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::unique_ptr<Task> WonkoVersionList::remoteUpdateTask()
|
|
||||||
{
|
|
||||||
return std::unique_ptr<WonkoVersionListRemoteLoadTask>(new WonkoVersionListRemoteLoadTask(this, this));
|
|
||||||
}
|
|
||||||
std::unique_ptr<Task> WonkoVersionList::localUpdateTask()
|
|
||||||
{
|
|
||||||
return std::unique_ptr<WonkoVersionListLocalLoadTask>(new WonkoVersionListLocalLoadTask(this, this));
|
|
||||||
}
|
|
||||||
|
|
||||||
QString WonkoVersionList::localFilename() const
|
|
||||||
{
|
|
||||||
return m_uid + ".json";
|
|
||||||
}
|
|
||||||
QJsonObject WonkoVersionList::serialized() const
|
|
||||||
{
|
|
||||||
return WonkoFormat::serializeVersionList(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
QString WonkoVersionList::humanReadable() const
|
|
||||||
{
|
|
||||||
return m_name.isEmpty() ? m_uid : m_name;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool WonkoVersionList::hasVersion(const QString &version) const
|
|
||||||
{
|
|
||||||
return m_lookup.contains(version);
|
|
||||||
}
|
|
||||||
WonkoVersionPtr WonkoVersionList::getVersion(const QString &version) const
|
|
||||||
{
|
|
||||||
return m_lookup.value(version);
|
|
||||||
}
|
|
||||||
|
|
||||||
void WonkoVersionList::setName(const QString &name)
|
|
||||||
{
|
|
||||||
m_name = name;
|
|
||||||
emit nameChanged(name);
|
|
||||||
}
|
|
||||||
void WonkoVersionList::setVersions(const QVector<WonkoVersionPtr> &versions)
|
|
||||||
{
|
|
||||||
beginResetModel();
|
|
||||||
m_versions = versions;
|
|
||||||
std::sort(m_versions.begin(), m_versions.end(), [](const WonkoVersionPtr &a, const WonkoVersionPtr &b)
|
|
||||||
{
|
|
||||||
return a->rawTime() > b->rawTime();
|
|
||||||
});
|
|
||||||
for (int i = 0; i < m_versions.size(); ++i)
|
|
||||||
{
|
|
||||||
m_lookup.insert(m_versions.at(i)->version(), m_versions.at(i));
|
|
||||||
setupAddedVersion(i, m_versions.at(i));
|
|
||||||
}
|
|
||||||
|
|
||||||
m_latest = m_versions.isEmpty() ? nullptr : m_versions.first();
|
|
||||||
auto recommendedIt = std::find_if(m_versions.constBegin(), m_versions.constEnd(), [](const WonkoVersionPtr &ptr) { return ptr->type() == "release"; });
|
|
||||||
m_recommended = recommendedIt == m_versions.constEnd() ? nullptr : *recommendedIt;
|
|
||||||
endResetModel();
|
|
||||||
}
|
|
||||||
|
|
||||||
void WonkoVersionList::merge(const BaseWonkoEntity::Ptr &other)
|
|
||||||
{
|
|
||||||
const WonkoVersionListPtr list = std::dynamic_pointer_cast<WonkoVersionList>(other);
|
|
||||||
if (m_name != list->m_name)
|
|
||||||
{
|
|
||||||
setName(list->m_name);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (m_versions.isEmpty())
|
|
||||||
{
|
|
||||||
setVersions(list->m_versions);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
for (const WonkoVersionPtr &version : list->m_versions)
|
|
||||||
{
|
|
||||||
if (m_lookup.contains(version->version()))
|
|
||||||
{
|
|
||||||
m_lookup.value(version->version())->merge(version);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
beginInsertRows(QModelIndex(), m_versions.size(), m_versions.size());
|
|
||||||
setupAddedVersion(m_versions.size(), version);
|
|
||||||
m_versions.append(version);
|
|
||||||
m_lookup.insert(version->uid(), version);
|
|
||||||
endInsertRows();
|
|
||||||
|
|
||||||
if (!m_latest || version->rawTime() > m_latest->rawTime())
|
|
||||||
{
|
|
||||||
m_latest = version;
|
|
||||||
emit dataChanged(index(0), index(m_versions.size() - 1), QVector<int>() << LatestRole);
|
|
||||||
}
|
|
||||||
if (!m_recommended || (version->type() == "release" && version->rawTime() > m_recommended->rawTime()))
|
|
||||||
{
|
|
||||||
m_recommended = version;
|
|
||||||
emit dataChanged(index(0), index(m_versions.size() - 1), QVector<int>() << RecommendedRole);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void WonkoVersionList::setupAddedVersion(const int row, const WonkoVersionPtr &version)
|
|
||||||
{
|
|
||||||
connect(version.get(), &WonkoVersion::requiresChanged, this, [this, row]() { emit dataChanged(index(row), index(row), QVector<int>() << RequiresRole); });
|
|
||||||
connect(version.get(), &WonkoVersion::timeChanged, this, [this, row]() { emit dataChanged(index(row), index(row), QVector<int>() << TimeRole << SortRole); });
|
|
||||||
connect(version.get(), &WonkoVersion::typeChanged, this, [this, row]() { emit dataChanged(index(row), index(row), QVector<int>() << TypeRole); });
|
|
||||||
}
|
|
||||||
|
|
||||||
BaseVersionPtr WonkoVersionList::getLatestStable() const
|
|
||||||
{
|
|
||||||
return m_latest;
|
|
||||||
}
|
|
||||||
BaseVersionPtr WonkoVersionList::getRecommended() const
|
|
||||||
{
|
|
||||||
return m_recommended;
|
|
||||||
}
|
|
||||||
|
|
||||||
#include "WonkoVersionList.moc"
|
|
@ -1,80 +0,0 @@
|
|||||||
/* Copyright 2015-2017 MultiMC Contributors
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "WonkoFormat.h"
|
|
||||||
|
|
||||||
#include "WonkoFormatV1.h"
|
|
||||||
|
|
||||||
#include "wonko/WonkoIndex.h"
|
|
||||||
#include "wonko/WonkoVersion.h"
|
|
||||||
#include "wonko/WonkoVersionList.h"
|
|
||||||
|
|
||||||
static int formatVersion(const QJsonObject &obj)
|
|
||||||
{
|
|
||||||
if (!obj.contains("formatVersion")) {
|
|
||||||
throw WonkoParseException(QObject::tr("Missing required field: 'formatVersion'"));
|
|
||||||
}
|
|
||||||
if (!obj.value("formatVersion").isDouble()) {
|
|
||||||
throw WonkoParseException(QObject::tr("Required field has invalid type: 'formatVersion'"));
|
|
||||||
}
|
|
||||||
return obj.value("formatVersion").toInt();
|
|
||||||
}
|
|
||||||
|
|
||||||
void WonkoFormat::parseIndex(const QJsonObject &obj, WonkoIndex *ptr)
|
|
||||||
{
|
|
||||||
const int version = formatVersion(obj);
|
|
||||||
switch (version) {
|
|
||||||
case 1:
|
|
||||||
ptr->merge(WonkoFormatV1().parseIndexInternal(obj));
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
throw WonkoParseException(QObject::tr("Unknown formatVersion: %1").arg(version));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
void WonkoFormat::parseVersion(const QJsonObject &obj, WonkoVersion *ptr)
|
|
||||||
{
|
|
||||||
const int version = formatVersion(obj);
|
|
||||||
switch (version) {
|
|
||||||
case 1:
|
|
||||||
ptr->merge(WonkoFormatV1().parseVersionInternal(obj));
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
throw WonkoParseException(QObject::tr("Unknown formatVersion: %1").arg(version));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
void WonkoFormat::parseVersionList(const QJsonObject &obj, WonkoVersionList *ptr)
|
|
||||||
{
|
|
||||||
const int version = formatVersion(obj);
|
|
||||||
switch (version) {
|
|
||||||
case 10:
|
|
||||||
ptr->merge(WonkoFormatV1().parseVersionListInternal(obj));
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
throw WonkoParseException(QObject::tr("Unknown formatVersion: %1").arg(version));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
QJsonObject WonkoFormat::serializeIndex(const WonkoIndex *ptr)
|
|
||||||
{
|
|
||||||
return WonkoFormatV1().serializeIndexInternal(ptr);
|
|
||||||
}
|
|
||||||
QJsonObject WonkoFormat::serializeVersion(const WonkoVersion *ptr)
|
|
||||||
{
|
|
||||||
return WonkoFormatV1().serializeVersionInternal(ptr);
|
|
||||||
}
|
|
||||||
QJsonObject WonkoFormat::serializeVersionList(const WonkoVersionList *ptr)
|
|
||||||
{
|
|
||||||
return WonkoFormatV1().serializeVersionListInternal(ptr);
|
|
||||||
}
|
|
@ -1,54 +0,0 @@
|
|||||||
/* Copyright 2015-2017 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 <QJsonObject>
|
|
||||||
#include <memory>
|
|
||||||
|
|
||||||
#include "Exception.h"
|
|
||||||
#include "wonko/BaseWonkoEntity.h"
|
|
||||||
|
|
||||||
class WonkoIndex;
|
|
||||||
class WonkoVersion;
|
|
||||||
class WonkoVersionList;
|
|
||||||
|
|
||||||
class WonkoParseException : public Exception
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
using Exception::Exception;
|
|
||||||
};
|
|
||||||
|
|
||||||
class WonkoFormat
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
virtual ~WonkoFormat() {}
|
|
||||||
|
|
||||||
static void parseIndex(const QJsonObject &obj, WonkoIndex *ptr);
|
|
||||||
static void parseVersion(const QJsonObject &obj, WonkoVersion *ptr);
|
|
||||||
static void parseVersionList(const QJsonObject &obj, WonkoVersionList *ptr);
|
|
||||||
|
|
||||||
static QJsonObject serializeIndex(const WonkoIndex *ptr);
|
|
||||||
static QJsonObject serializeVersion(const WonkoVersion *ptr);
|
|
||||||
static QJsonObject serializeVersionList(const WonkoVersionList *ptr);
|
|
||||||
|
|
||||||
protected:
|
|
||||||
virtual BaseWonkoEntity::Ptr parseIndexInternal(const QJsonObject &obj) const = 0;
|
|
||||||
virtual BaseWonkoEntity::Ptr parseVersionInternal(const QJsonObject &obj) const = 0;
|
|
||||||
virtual BaseWonkoEntity::Ptr parseVersionListInternal(const QJsonObject &obj) const = 0;
|
|
||||||
virtual QJsonObject serializeIndexInternal(const WonkoIndex *ptr) const = 0;
|
|
||||||
virtual QJsonObject serializeVersionInternal(const WonkoVersion *ptr) const = 0;
|
|
||||||
virtual QJsonObject serializeVersionListInternal(const WonkoVersionList *ptr) const = 0;
|
|
||||||
};
|
|
@ -1,158 +0,0 @@
|
|||||||
/* Copyright 2015-2017 MultiMC Contributors
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "WonkoFormatV1.h"
|
|
||||||
#include <minecraft/onesix/OneSixVersionFormat.h>
|
|
||||||
|
|
||||||
#include "Json.h"
|
|
||||||
|
|
||||||
#include "wonko/WonkoIndex.h"
|
|
||||||
#include "wonko/WonkoVersion.h"
|
|
||||||
#include "wonko/WonkoVersionList.h"
|
|
||||||
#include "Env.h"
|
|
||||||
|
|
||||||
using namespace Json;
|
|
||||||
|
|
||||||
static WonkoVersionPtr parseCommonVersion(const QString &uid, const QJsonObject &obj)
|
|
||||||
{
|
|
||||||
const QVector<QJsonObject> requiresRaw = obj.contains("requires") ? requireIsArrayOf<QJsonObject>(obj, "requires") : QVector<QJsonObject>();
|
|
||||||
QVector<WonkoReference> requires;
|
|
||||||
requires.reserve(requiresRaw.size());
|
|
||||||
std::transform(requiresRaw.begin(), requiresRaw.end(), std::back_inserter(requires), [](const QJsonObject &rObj)
|
|
||||||
{
|
|
||||||
WonkoReference ref(requireString(rObj, "uid"));
|
|
||||||
ref.setVersion(ensureString(rObj, "version", QString()));
|
|
||||||
return ref;
|
|
||||||
});
|
|
||||||
|
|
||||||
WonkoVersionPtr version = std::make_shared<WonkoVersion>(uid, requireString(obj, "version"));
|
|
||||||
if (obj.value("time").isString())
|
|
||||||
{
|
|
||||||
version->setTime(QDateTime::fromString(requireString(obj, "time"), Qt::ISODate).toMSecsSinceEpoch() / 1000);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
version->setTime(requireInteger(obj, "time"));
|
|
||||||
}
|
|
||||||
version->setType(ensureString(obj, "type", QString()));
|
|
||||||
version->setRequires(requires);
|
|
||||||
return version;
|
|
||||||
}
|
|
||||||
static void serializeCommonVersion(const WonkoVersion *version, QJsonObject &obj)
|
|
||||||
{
|
|
||||||
QJsonArray requires;
|
|
||||||
for (const WonkoReference &ref : version->requires())
|
|
||||||
{
|
|
||||||
if (ref.version().isEmpty())
|
|
||||||
{
|
|
||||||
QJsonObject out;
|
|
||||||
out["uid"] = ref.uid();
|
|
||||||
requires.append(out);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
QJsonObject out;
|
|
||||||
out["uid"] = ref.uid();
|
|
||||||
out["version"] = ref.version();
|
|
||||||
requires.append(out);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
obj.insert("version", version->version());
|
|
||||||
obj.insert("type", version->type());
|
|
||||||
obj.insert("time", version->time().toString(Qt::ISODate));
|
|
||||||
obj.insert("requires", requires);
|
|
||||||
}
|
|
||||||
|
|
||||||
BaseWonkoEntity::Ptr WonkoFormatV1::parseIndexInternal(const QJsonObject &obj) const
|
|
||||||
{
|
|
||||||
const QVector<QJsonObject> objects = requireIsArrayOf<QJsonObject>(obj, "index");
|
|
||||||
QVector<WonkoVersionListPtr> lists;
|
|
||||||
lists.reserve(objects.size());
|
|
||||||
std::transform(objects.begin(), objects.end(), std::back_inserter(lists), [](const QJsonObject &obj)
|
|
||||||
{
|
|
||||||
WonkoVersionListPtr list = std::make_shared<WonkoVersionList>(requireString(obj, "uid"));
|
|
||||||
list->setName(ensureString(obj, "name", QString()));
|
|
||||||
return list;
|
|
||||||
});
|
|
||||||
return std::make_shared<WonkoIndex>(lists);
|
|
||||||
}
|
|
||||||
BaseWonkoEntity::Ptr WonkoFormatV1::parseVersionInternal(const QJsonObject &obj) const
|
|
||||||
{
|
|
||||||
WonkoVersionPtr version = parseCommonVersion(requireString(obj, "uid"), obj);
|
|
||||||
|
|
||||||
version->setData(OneSixVersionFormat::versionFileFromJson(QJsonDocument(obj),
|
|
||||||
QString("%1/%2.json").arg(version->uid(), version->version()),
|
|
||||||
obj.contains("order")));
|
|
||||||
return version;
|
|
||||||
}
|
|
||||||
BaseWonkoEntity::Ptr WonkoFormatV1::parseVersionListInternal(const QJsonObject &obj) const
|
|
||||||
{
|
|
||||||
const QString uid = requireString(obj, "uid");
|
|
||||||
|
|
||||||
const QVector<QJsonObject> versionsRaw = requireIsArrayOf<QJsonObject>(obj, "versions");
|
|
||||||
QVector<WonkoVersionPtr> versions;
|
|
||||||
versions.reserve(versionsRaw.size());
|
|
||||||
std::transform(versionsRaw.begin(), versionsRaw.end(), std::back_inserter(versions), [this, uid](const QJsonObject &vObj)
|
|
||||||
{ return parseCommonVersion(uid, vObj); });
|
|
||||||
|
|
||||||
WonkoVersionListPtr list = std::make_shared<WonkoVersionList>(uid);
|
|
||||||
list->setName(ensureString(obj, "name", QString()));
|
|
||||||
list->setVersions(versions);
|
|
||||||
return list;
|
|
||||||
}
|
|
||||||
|
|
||||||
QJsonObject WonkoFormatV1::serializeIndexInternal(const WonkoIndex *ptr) const
|
|
||||||
{
|
|
||||||
QJsonArray index;
|
|
||||||
for (const WonkoVersionListPtr &list : ptr->lists())
|
|
||||||
{
|
|
||||||
QJsonObject out;
|
|
||||||
out["uid"] = list->uid();
|
|
||||||
out["version"] = list->name();
|
|
||||||
index.append(out);
|
|
||||||
}
|
|
||||||
QJsonObject out;
|
|
||||||
out["formatVersion"] = 1;
|
|
||||||
out["index"] = index;
|
|
||||||
return out;
|
|
||||||
}
|
|
||||||
QJsonObject WonkoFormatV1::serializeVersionInternal(const WonkoVersion *ptr) const
|
|
||||||
{
|
|
||||||
QJsonObject obj = OneSixVersionFormat::versionFileToJson(ptr->data(), true).object();
|
|
||||||
serializeCommonVersion(ptr, obj);
|
|
||||||
obj.insert("formatVersion", 1);
|
|
||||||
obj.insert("uid", ptr->uid());
|
|
||||||
// TODO: the name should be looked up in the UI based on the uid
|
|
||||||
obj.insert("name", ENV.wonkoIndex()->getListGuaranteed(ptr->uid())->name());
|
|
||||||
|
|
||||||
return obj;
|
|
||||||
}
|
|
||||||
QJsonObject WonkoFormatV1::serializeVersionListInternal(const WonkoVersionList *ptr) const
|
|
||||||
{
|
|
||||||
QJsonArray versions;
|
|
||||||
for (const WonkoVersionPtr &version : ptr->versions())
|
|
||||||
{
|
|
||||||
QJsonObject obj;
|
|
||||||
serializeCommonVersion(version.get(), obj);
|
|
||||||
versions.append(obj);
|
|
||||||
}
|
|
||||||
QJsonObject out;
|
|
||||||
out["formatVersion"] = 10;
|
|
||||||
out["uid"] = ptr->uid();
|
|
||||||
out["name"] = ptr->name().isNull() ? QJsonValue() : ptr->name();
|
|
||||||
out["versions"] = versions;
|
|
||||||
return out;
|
|
||||||
}
|
|
@ -1,30 +0,0 @@
|
|||||||
/* Copyright 2015-2017 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 "WonkoFormat.h"
|
|
||||||
|
|
||||||
class WonkoFormatV1 : public WonkoFormat
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
BaseWonkoEntity::Ptr parseIndexInternal(const QJsonObject &obj) const override;
|
|
||||||
BaseWonkoEntity::Ptr parseVersionInternal(const QJsonObject &obj) const override;
|
|
||||||
BaseWonkoEntity::Ptr parseVersionListInternal(const QJsonObject &obj) const override;
|
|
||||||
|
|
||||||
QJsonObject serializeIndexInternal(const WonkoIndex *ptr) const override;
|
|
||||||
QJsonObject serializeVersionInternal(const WonkoVersion *ptr) const override;
|
|
||||||
QJsonObject serializeVersionListInternal(const WonkoVersionList *ptr) const override;
|
|
||||||
};
|
|
@ -1,117 +0,0 @@
|
|||||||
/* Copyright 2015-2017 MultiMC Contributors
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "BaseWonkoEntityLocalLoadTask.h"
|
|
||||||
|
|
||||||
#include <QFile>
|
|
||||||
|
|
||||||
#include "wonko/format/WonkoFormat.h"
|
|
||||||
#include "wonko/WonkoUtil.h"
|
|
||||||
#include "wonko/WonkoIndex.h"
|
|
||||||
#include "wonko/WonkoVersion.h"
|
|
||||||
#include "wonko/WonkoVersionList.h"
|
|
||||||
#include "Env.h"
|
|
||||||
#include "Json.h"
|
|
||||||
|
|
||||||
BaseWonkoEntityLocalLoadTask::BaseWonkoEntityLocalLoadTask(BaseWonkoEntity *entity, QObject *parent)
|
|
||||||
: Task(parent), m_entity(entity)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void BaseWonkoEntityLocalLoadTask::executeTask()
|
|
||||||
{
|
|
||||||
const QString fname = Wonko::localWonkoDir().absoluteFilePath(filename());
|
|
||||||
if (!QFile::exists(fname))
|
|
||||||
{
|
|
||||||
emitFailed(tr("File doesn't exist"));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
setStatus(tr("Reading %1...").arg(name()));
|
|
||||||
setProgress(0, 0);
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
parse(Json::requireObject(Json::requireDocument(fname, name()), name()));
|
|
||||||
m_entity->notifyLocalLoadComplete();
|
|
||||||
emitSucceeded();
|
|
||||||
}
|
|
||||||
catch (Exception &e)
|
|
||||||
{
|
|
||||||
emitFailed(tr("Unable to parse file %1: %2").arg(fname, e.cause()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// WONKO INDEX //
|
|
||||||
WonkoIndexLocalLoadTask::WonkoIndexLocalLoadTask(WonkoIndex *index, QObject *parent)
|
|
||||||
: BaseWonkoEntityLocalLoadTask(index, parent)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
QString WonkoIndexLocalLoadTask::filename() const
|
|
||||||
{
|
|
||||||
return "index.json";
|
|
||||||
}
|
|
||||||
QString WonkoIndexLocalLoadTask::name() const
|
|
||||||
{
|
|
||||||
return tr("Wonko Index");
|
|
||||||
}
|
|
||||||
void WonkoIndexLocalLoadTask::parse(const QJsonObject &obj) const
|
|
||||||
{
|
|
||||||
WonkoFormat::parseIndex(obj, dynamic_cast<WonkoIndex *>(entity()));
|
|
||||||
}
|
|
||||||
|
|
||||||
// WONKO VERSION LIST //
|
|
||||||
WonkoVersionListLocalLoadTask::WonkoVersionListLocalLoadTask(WonkoVersionList *list, QObject *parent)
|
|
||||||
: BaseWonkoEntityLocalLoadTask(list, parent)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
QString WonkoVersionListLocalLoadTask::filename() const
|
|
||||||
{
|
|
||||||
return list()->uid() + ".json";
|
|
||||||
}
|
|
||||||
QString WonkoVersionListLocalLoadTask::name() const
|
|
||||||
{
|
|
||||||
return tr("Wonko Version List for %1").arg(list()->humanReadable());
|
|
||||||
}
|
|
||||||
void WonkoVersionListLocalLoadTask::parse(const QJsonObject &obj) const
|
|
||||||
{
|
|
||||||
WonkoFormat::parseVersionList(obj, list());
|
|
||||||
}
|
|
||||||
WonkoVersionList *WonkoVersionListLocalLoadTask::list() const
|
|
||||||
{
|
|
||||||
return dynamic_cast<WonkoVersionList *>(entity());
|
|
||||||
}
|
|
||||||
|
|
||||||
// WONKO VERSION //
|
|
||||||
WonkoVersionLocalLoadTask::WonkoVersionLocalLoadTask(WonkoVersion *version, QObject *parent)
|
|
||||||
: BaseWonkoEntityLocalLoadTask(version, parent)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
QString WonkoVersionLocalLoadTask::filename() const
|
|
||||||
{
|
|
||||||
return version()->uid() + "/" + version()->version() + ".json";
|
|
||||||
}
|
|
||||||
QString WonkoVersionLocalLoadTask::name() const
|
|
||||||
{
|
|
||||||
return tr("Wonko Version for %1").arg(version()->name());
|
|
||||||
}
|
|
||||||
void WonkoVersionLocalLoadTask::parse(const QJsonObject &obj) const
|
|
||||||
{
|
|
||||||
WonkoFormat::parseVersion(obj, version());
|
|
||||||
}
|
|
||||||
WonkoVersion *WonkoVersionLocalLoadTask::version() const
|
|
||||||
{
|
|
||||||
return dynamic_cast<WonkoVersion *>(entity());
|
|
||||||
}
|
|
@ -1,81 +0,0 @@
|
|||||||
/* Copyright 2015-2017 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 "tasks/Task.h"
|
|
||||||
#include <memory>
|
|
||||||
|
|
||||||
class BaseWonkoEntity;
|
|
||||||
class WonkoIndex;
|
|
||||||
class WonkoVersionList;
|
|
||||||
class WonkoVersion;
|
|
||||||
|
|
||||||
class BaseWonkoEntityLocalLoadTask : public Task
|
|
||||||
{
|
|
||||||
Q_OBJECT
|
|
||||||
public:
|
|
||||||
explicit BaseWonkoEntityLocalLoadTask(BaseWonkoEntity *entity, QObject *parent = nullptr);
|
|
||||||
|
|
||||||
protected:
|
|
||||||
virtual QString filename() const = 0;
|
|
||||||
virtual QString name() const = 0;
|
|
||||||
virtual void parse(const QJsonObject &obj) const = 0;
|
|
||||||
|
|
||||||
BaseWonkoEntity *entity() const { return m_entity; }
|
|
||||||
|
|
||||||
private:
|
|
||||||
void executeTask() override;
|
|
||||||
|
|
||||||
BaseWonkoEntity *m_entity;
|
|
||||||
};
|
|
||||||
|
|
||||||
class WonkoIndexLocalLoadTask : public BaseWonkoEntityLocalLoadTask
|
|
||||||
{
|
|
||||||
Q_OBJECT
|
|
||||||
public:
|
|
||||||
explicit WonkoIndexLocalLoadTask(WonkoIndex *index, QObject *parent = nullptr);
|
|
||||||
|
|
||||||
private:
|
|
||||||
QString filename() const override;
|
|
||||||
QString name() const override;
|
|
||||||
void parse(const QJsonObject &obj) const override;
|
|
||||||
};
|
|
||||||
class WonkoVersionListLocalLoadTask : public BaseWonkoEntityLocalLoadTask
|
|
||||||
{
|
|
||||||
Q_OBJECT
|
|
||||||
public:
|
|
||||||
explicit WonkoVersionListLocalLoadTask(WonkoVersionList *list, QObject *parent = nullptr);
|
|
||||||
|
|
||||||
private:
|
|
||||||
QString filename() const override;
|
|
||||||
QString name() const override;
|
|
||||||
void parse(const QJsonObject &obj) const override;
|
|
||||||
|
|
||||||
WonkoVersionList *list() const;
|
|
||||||
};
|
|
||||||
class WonkoVersionLocalLoadTask : public BaseWonkoEntityLocalLoadTask
|
|
||||||
{
|
|
||||||
Q_OBJECT
|
|
||||||
public:
|
|
||||||
explicit WonkoVersionLocalLoadTask(WonkoVersion *version, QObject *parent = nullptr);
|
|
||||||
|
|
||||||
private:
|
|
||||||
QString filename() const override;
|
|
||||||
QString name() const override;
|
|
||||||
void parse(const QJsonObject &obj) const override;
|
|
||||||
|
|
||||||
WonkoVersion *version() const;
|
|
||||||
};
|
|
@ -1,126 +0,0 @@
|
|||||||
/* Copyright 2015-2017 MultiMC Contributors
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "BaseWonkoEntityRemoteLoadTask.h"
|
|
||||||
|
|
||||||
#include "net/Download.h"
|
|
||||||
#include "net/HttpMetaCache.h"
|
|
||||||
#include "net/NetJob.h"
|
|
||||||
#include "wonko/format/WonkoFormat.h"
|
|
||||||
#include "wonko/WonkoUtil.h"
|
|
||||||
#include "wonko/WonkoIndex.h"
|
|
||||||
#include "wonko/WonkoVersion.h"
|
|
||||||
#include "wonko/WonkoVersionList.h"
|
|
||||||
#include "Env.h"
|
|
||||||
#include "Json.h"
|
|
||||||
|
|
||||||
BaseWonkoEntityRemoteLoadTask::BaseWonkoEntityRemoteLoadTask(BaseWonkoEntity *entity, QObject *parent)
|
|
||||||
: Task(parent), m_entity(entity)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void BaseWonkoEntityRemoteLoadTask::executeTask()
|
|
||||||
{
|
|
||||||
NetJob *job = new NetJob(name());
|
|
||||||
|
|
||||||
auto entry = ENV.metacache()->resolveEntry("wonko", url().toString());
|
|
||||||
entry->setStale(true);
|
|
||||||
m_dl = Net::Download::makeCached(url(), entry);
|
|
||||||
job->addNetAction(m_dl);
|
|
||||||
connect(job, &NetJob::failed, this, &BaseWonkoEntityRemoteLoadTask::emitFailed);
|
|
||||||
connect(job, &NetJob::succeeded, this, &BaseWonkoEntityRemoteLoadTask::networkFinished);
|
|
||||||
connect(job, &NetJob::status, this, &BaseWonkoEntityRemoteLoadTask::setStatus);
|
|
||||||
connect(job, &NetJob::progress, this, &BaseWonkoEntityRemoteLoadTask::setProgress);
|
|
||||||
job->start();
|
|
||||||
}
|
|
||||||
|
|
||||||
void BaseWonkoEntityRemoteLoadTask::networkFinished()
|
|
||||||
{
|
|
||||||
setStatus(tr("Parsing..."));
|
|
||||||
setProgress(0, 0);
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
parse(Json::requireObject(Json::requireDocument(m_dl->getTargetFilepath(), name()), name()));
|
|
||||||
m_entity->notifyRemoteLoadComplete();
|
|
||||||
emitSucceeded();
|
|
||||||
}
|
|
||||||
catch (Exception &e)
|
|
||||||
{
|
|
||||||
emitFailed(tr("Unable to parse response: %1").arg(e.cause()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// WONKO INDEX //
|
|
||||||
WonkoIndexRemoteLoadTask::WonkoIndexRemoteLoadTask(WonkoIndex *index, QObject *parent)
|
|
||||||
: BaseWonkoEntityRemoteLoadTask(index, parent)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
QUrl WonkoIndexRemoteLoadTask::url() const
|
|
||||||
{
|
|
||||||
return Wonko::indexUrl();
|
|
||||||
}
|
|
||||||
QString WonkoIndexRemoteLoadTask::name() const
|
|
||||||
{
|
|
||||||
return tr("Wonko Index");
|
|
||||||
}
|
|
||||||
void WonkoIndexRemoteLoadTask::parse(const QJsonObject &obj) const
|
|
||||||
{
|
|
||||||
WonkoFormat::parseIndex(obj, dynamic_cast<WonkoIndex *>(entity()));
|
|
||||||
}
|
|
||||||
|
|
||||||
// WONKO VERSION LIST //
|
|
||||||
WonkoVersionListRemoteLoadTask::WonkoVersionListRemoteLoadTask(WonkoVersionList *list, QObject *parent)
|
|
||||||
: BaseWonkoEntityRemoteLoadTask(list, parent)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
QUrl WonkoVersionListRemoteLoadTask::url() const
|
|
||||||
{
|
|
||||||
return Wonko::versionListUrl(list()->uid());
|
|
||||||
}
|
|
||||||
QString WonkoVersionListRemoteLoadTask::name() const
|
|
||||||
{
|
|
||||||
return tr("Wonko Version List for %1").arg(list()->humanReadable());
|
|
||||||
}
|
|
||||||
void WonkoVersionListRemoteLoadTask::parse(const QJsonObject &obj) const
|
|
||||||
{
|
|
||||||
WonkoFormat::parseVersionList(obj, list());
|
|
||||||
}
|
|
||||||
WonkoVersionList *WonkoVersionListRemoteLoadTask::list() const
|
|
||||||
{
|
|
||||||
return dynamic_cast<WonkoVersionList *>(entity());
|
|
||||||
}
|
|
||||||
|
|
||||||
// WONKO VERSION //
|
|
||||||
WonkoVersionRemoteLoadTask::WonkoVersionRemoteLoadTask(WonkoVersion *version, QObject *parent)
|
|
||||||
: BaseWonkoEntityRemoteLoadTask(version, parent)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
QUrl WonkoVersionRemoteLoadTask::url() const
|
|
||||||
{
|
|
||||||
return Wonko::versionUrl(version()->uid(), version()->version());
|
|
||||||
}
|
|
||||||
QString WonkoVersionRemoteLoadTask::name() const
|
|
||||||
{
|
|
||||||
return tr("Wonko Version for %1").arg(version()->name());
|
|
||||||
}
|
|
||||||
void WonkoVersionRemoteLoadTask::parse(const QJsonObject &obj) const
|
|
||||||
{
|
|
||||||
WonkoFormat::parseVersion(obj, version());
|
|
||||||
}
|
|
||||||
WonkoVersion *WonkoVersionRemoteLoadTask::version() const
|
|
||||||
{
|
|
||||||
return dynamic_cast<WonkoVersion *>(entity());
|
|
||||||
}
|
|
@ -1,90 +0,0 @@
|
|||||||
/* Copyright 2015-2017 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 "tasks/Task.h"
|
|
||||||
#include <memory>
|
|
||||||
|
|
||||||
namespace Net
|
|
||||||
{
|
|
||||||
class Download;
|
|
||||||
}
|
|
||||||
|
|
||||||
class BaseWonkoEntity;
|
|
||||||
class WonkoIndex;
|
|
||||||
class WonkoVersionList;
|
|
||||||
class WonkoVersion;
|
|
||||||
|
|
||||||
class BaseWonkoEntityRemoteLoadTask : public Task
|
|
||||||
{
|
|
||||||
Q_OBJECT
|
|
||||||
public:
|
|
||||||
explicit BaseWonkoEntityRemoteLoadTask(BaseWonkoEntity *entity, QObject *parent = nullptr);
|
|
||||||
|
|
||||||
protected:
|
|
||||||
virtual QUrl url() const = 0;
|
|
||||||
virtual QString name() const = 0;
|
|
||||||
virtual void parse(const QJsonObject &obj) const = 0;
|
|
||||||
|
|
||||||
BaseWonkoEntity *entity() const { return m_entity; }
|
|
||||||
|
|
||||||
private slots:
|
|
||||||
void networkFinished();
|
|
||||||
|
|
||||||
private:
|
|
||||||
void executeTask() override;
|
|
||||||
|
|
||||||
BaseWonkoEntity *m_entity;
|
|
||||||
std::shared_ptr<Net::Download> m_dl;
|
|
||||||
};
|
|
||||||
|
|
||||||
class WonkoIndexRemoteLoadTask : public BaseWonkoEntityRemoteLoadTask
|
|
||||||
{
|
|
||||||
Q_OBJECT
|
|
||||||
public:
|
|
||||||
explicit WonkoIndexRemoteLoadTask(WonkoIndex *index, QObject *parent = nullptr);
|
|
||||||
|
|
||||||
private:
|
|
||||||
QUrl url() const override;
|
|
||||||
QString name() const override;
|
|
||||||
void parse(const QJsonObject &obj) const override;
|
|
||||||
};
|
|
||||||
class WonkoVersionListRemoteLoadTask : public BaseWonkoEntityRemoteLoadTask
|
|
||||||
{
|
|
||||||
Q_OBJECT
|
|
||||||
public:
|
|
||||||
explicit WonkoVersionListRemoteLoadTask(WonkoVersionList *list, QObject *parent = nullptr);
|
|
||||||
|
|
||||||
private:
|
|
||||||
QUrl url() const override;
|
|
||||||
QString name() const override;
|
|
||||||
void parse(const QJsonObject &obj) const override;
|
|
||||||
|
|
||||||
WonkoVersionList *list() const;
|
|
||||||
};
|
|
||||||
class WonkoVersionRemoteLoadTask : public BaseWonkoEntityRemoteLoadTask
|
|
||||||
{
|
|
||||||
Q_OBJECT
|
|
||||||
public:
|
|
||||||
explicit WonkoVersionRemoteLoadTask(WonkoVersion *version, QObject *parent = nullptr);
|
|
||||||
|
|
||||||
private:
|
|
||||||
QUrl url() const override;
|
|
||||||
QString name() const override;
|
|
||||||
void parse(const QJsonObject &obj) const override;
|
|
||||||
|
|
||||||
WonkoVersion *version() const;
|
|
||||||
};
|
|
@ -33,7 +33,6 @@ Config::Config()
|
|||||||
VERSION_STR = "@MultiMC_VERSION_STRING@";
|
VERSION_STR = "@MultiMC_VERSION_STRING@";
|
||||||
NEWS_RSS_URL = "@MultiMC_NEWS_RSS_URL@";
|
NEWS_RSS_URL = "@MultiMC_NEWS_RSS_URL@";
|
||||||
PASTE_EE_KEY = "@MultiMC_PASTE_EE_API_KEY@";
|
PASTE_EE_KEY = "@MultiMC_PASTE_EE_API_KEY@";
|
||||||
WONKO_ROOT_URL = "@MultiMC_WONKO_ROOT_URL@";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
QString Config::printableVersionString() const
|
QString Config::printableVersionString() const
|
||||||
|
@ -60,11 +60,6 @@ public:
|
|||||||
*/
|
*/
|
||||||
QString PASTE_EE_KEY;
|
QString PASTE_EE_KEY;
|
||||||
|
|
||||||
/**
|
|
||||||
* Root URL for wonko things. Other wonko URLs will be resolved relative to this.
|
|
||||||
*/
|
|
||||||
QString WONKO_ROOT_URL;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \brief Converts the Version to a string.
|
* \brief Converts the Version to a string.
|
||||||
* \return The version number in string format (major.minor.revision.build).
|
* \return The version number in string format (major.minor.revision.build).
|
||||||
|
@ -30,9 +30,6 @@ set(MultiMC_ANALYTICS_ID "" CACHE STRING "ID you can get from Google analytics")
|
|||||||
include(GetGitRevisionDescription)
|
include(GetGitRevisionDescription)
|
||||||
get_git_head_revision(MultiMC_GIT_REFSPEC MultiMC_GIT_COMMIT)
|
get_git_head_revision(MultiMC_GIT_REFSPEC MultiMC_GIT_COMMIT)
|
||||||
|
|
||||||
# Root URL for wonko files
|
|
||||||
set(MultiMC_WONKO_ROOT_URL "" CACHE STRING "Root URL for wonko stuff")
|
|
||||||
|
|
||||||
message(STATUS "Git commit: ${MultiMC_GIT_COMMIT}")
|
message(STATUS "Git commit: ${MultiMC_GIT_COMMIT}")
|
||||||
message(STATUS "Git refspec: ${MultiMC_GIT_REFSPEC}")
|
message(STATUS "Git refspec: ${MultiMC_GIT_REFSPEC}")
|
||||||
|
|
||||||
@ -99,8 +96,6 @@ SET(MULTIMC_SOURCES
|
|||||||
VersionProxyModel.cpp
|
VersionProxyModel.cpp
|
||||||
ColorCache.h
|
ColorCache.h
|
||||||
ColorCache.cpp
|
ColorCache.cpp
|
||||||
WonkoGui.h
|
|
||||||
WonkoGui.cpp
|
|
||||||
|
|
||||||
# GUI - windows
|
# GUI - windows
|
||||||
MainWindow.h
|
MainWindow.h
|
||||||
@ -189,8 +184,8 @@ SET(MULTIMC_SOURCES
|
|||||||
pages/global/ProxyPage.h
|
pages/global/ProxyPage.h
|
||||||
pages/global/PasteEEPage.cpp
|
pages/global/PasteEEPage.cpp
|
||||||
pages/global/PasteEEPage.h
|
pages/global/PasteEEPage.h
|
||||||
pages/global/WonkoPage.cpp
|
pages/global/PackagesPage.cpp
|
||||||
pages/global/WonkoPage.h
|
pages/global/PackagesPage.h
|
||||||
|
|
||||||
# GUI - dialogs
|
# GUI - dialogs
|
||||||
dialogs/AboutDialog.cpp
|
dialogs/AboutDialog.cpp
|
||||||
@ -289,7 +284,7 @@ SET(MULTIMC_UIS
|
|||||||
pages/global/MultiMCPage.ui
|
pages/global/MultiMCPage.ui
|
||||||
pages/global/ProxyPage.ui
|
pages/global/ProxyPage.ui
|
||||||
pages/global/PasteEEPage.ui
|
pages/global/PasteEEPage.ui
|
||||||
pages/global/WonkoPage.ui
|
pages/global/PackagesPage.ui
|
||||||
|
|
||||||
# Dialogs
|
# Dialogs
|
||||||
dialogs/CopyInstanceDialog.ui
|
dialogs/CopyInstanceDialog.ui
|
||||||
@ -318,7 +313,6 @@ set(MULTIMC_QRCS
|
|||||||
resources/pe_blue/pe_blue.qrc
|
resources/pe_blue/pe_blue.qrc
|
||||||
resources/OSX/OSX.qrc
|
resources/OSX/OSX.qrc
|
||||||
resources/iOS/iOS.qrc
|
resources/iOS/iOS.qrc
|
||||||
resources/versions/versions.qrc
|
|
||||||
resources/certs/certs.qrc
|
resources/certs/certs.qrc
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -54,7 +54,6 @@
|
|||||||
#include <java/JavaUtils.h>
|
#include <java/JavaUtils.h>
|
||||||
#include <java/JavaInstallList.h>
|
#include <java/JavaInstallList.h>
|
||||||
#include <launch/LaunchTask.h>
|
#include <launch/LaunchTask.h>
|
||||||
#include <minecraft/MinecraftVersionList.h>
|
|
||||||
#include <minecraft/legacy/LwjglVersionList.h>
|
#include <minecraft/legacy/LwjglVersionList.h>
|
||||||
#include <minecraft/auth/MojangAccountList.h>
|
#include <minecraft/auth/MojangAccountList.h>
|
||||||
#include <SkinUtils.h>
|
#include <SkinUtils.h>
|
||||||
@ -555,19 +554,8 @@ MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new MainWindow
|
|||||||
job->start();
|
job->start();
|
||||||
}
|
}
|
||||||
|
|
||||||
// run the things that load and download other things... FIXME: this is NOT the place
|
// load the news
|
||||||
// FIXME: invisible actions in the background = NOPE.
|
|
||||||
{
|
{
|
||||||
if (!MMC->minecraftlist()->isLoaded())
|
|
||||||
{
|
|
||||||
m_versionLoadTask = MMC->minecraftlist()->getLoadTask();
|
|
||||||
startTask(m_versionLoadTask);
|
|
||||||
}
|
|
||||||
if (!MMC->lwjgllist()->isLoaded())
|
|
||||||
{
|
|
||||||
MMC->lwjgllist()->loadList();
|
|
||||||
}
|
|
||||||
|
|
||||||
m_newsChecker->reloadNews();
|
m_newsChecker->reloadNews();
|
||||||
updateNewsLabel();
|
updateNewsLabel();
|
||||||
}
|
}
|
||||||
@ -1014,18 +1002,6 @@ void MainWindow::setCatBackground(bool enabled)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// FIXME: eliminate, should not be needed
|
|
||||||
void MainWindow::waitForMinecraftVersions()
|
|
||||||
{
|
|
||||||
if (!MMC->minecraftlist()->isLoaded() && m_versionLoadTask && m_versionLoadTask->isRunning())
|
|
||||||
{
|
|
||||||
QEventLoop waitLoop;
|
|
||||||
waitLoop.connect(m_versionLoadTask, &Task::failed, &waitLoop, &QEventLoop::quit);
|
|
||||||
waitLoop.connect(m_versionLoadTask, &Task::succeeded, &waitLoop, &QEventLoop::quit);
|
|
||||||
waitLoop.exec();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void MainWindow::runModalTask(Task *task)
|
void MainWindow::runModalTask(Task *task)
|
||||||
{
|
{
|
||||||
connect(task, &Task::failed, [this](QString reason)
|
connect(task, &Task::failed, [this](QString reason)
|
||||||
@ -1117,8 +1093,6 @@ void MainWindow::on_actionAddInstance_triggered()
|
|||||||
groupName = map["group"].toString();
|
groupName = map["group"].toString();
|
||||||
} while(0);
|
} while(0);
|
||||||
|
|
||||||
waitForMinecraftVersions();
|
|
||||||
|
|
||||||
if(groupName.isEmpty())
|
if(groupName.isEmpty())
|
||||||
{
|
{
|
||||||
groupName = MMC->settings()->get("LastUsedGroupForNewInstance").toString();
|
groupName = MMC->settings()->get("LastUsedGroupForNewInstance").toString();
|
||||||
|
@ -167,7 +167,6 @@ private:
|
|||||||
void updateInstanceToolIcon(QString new_icon);
|
void updateInstanceToolIcon(QString new_icon);
|
||||||
void setSelectedInstanceById(const QString &id);
|
void setSelectedInstanceById(const QString &id);
|
||||||
|
|
||||||
void waitForMinecraftVersions();
|
|
||||||
void runModalTask(Task *task);
|
void runModalTask(Task *task);
|
||||||
void instanceFromVersion(QString instName, QString instGroup, QString instIcon, BaseVersionPtr version);
|
void instanceFromVersion(QString instName, QString instGroup, QString instIcon, BaseVersionPtr version);
|
||||||
void instanceFromZipPack(QString instName, QString instGroup, QString instIcon, QUrl url);
|
void instanceFromZipPack(QString instName, QString instGroup, QString instIcon, QUrl url);
|
||||||
|
@ -10,6 +10,7 @@
|
|||||||
#include "pages/global/ExternalToolsPage.h"
|
#include "pages/global/ExternalToolsPage.h"
|
||||||
#include "pages/global/AccountListPage.h"
|
#include "pages/global/AccountListPage.h"
|
||||||
#include "pages/global/PasteEEPage.h"
|
#include "pages/global/PasteEEPage.h"
|
||||||
|
#include "pages/global/PackagesPage.h"
|
||||||
|
|
||||||
#include "themes/ITheme.h"
|
#include "themes/ITheme.h"
|
||||||
#include "themes/SystemTheme.h"
|
#include "themes/SystemTheme.h"
|
||||||
@ -41,9 +42,6 @@
|
|||||||
#include "icons/IconList.h"
|
#include "icons/IconList.h"
|
||||||
//FIXME: get rid of this
|
//FIXME: get rid of this
|
||||||
#include "minecraft/legacy/LwjglVersionList.h"
|
#include "minecraft/legacy/LwjglVersionList.h"
|
||||||
#include "minecraft/MinecraftVersionList.h"
|
|
||||||
#include "minecraft/liteloader/LiteLoaderVersionList.h"
|
|
||||||
#include "minecraft/forge/ForgeVersionList.h"
|
|
||||||
|
|
||||||
#include "net/HttpMetaCache.h"
|
#include "net/HttpMetaCache.h"
|
||||||
#include "net/URLConstants.h"
|
#include "net/URLConstants.h"
|
||||||
@ -337,7 +335,6 @@ MultiMC::MultiMC(int &argc, char **argv) : QApplication(argc, argv)
|
|||||||
initIcons();
|
initIcons();
|
||||||
initThemes();
|
initThemes();
|
||||||
// make sure we have at least some minecraft versions before we init instances
|
// make sure we have at least some minecraft versions before we init instances
|
||||||
minecraftlist();
|
|
||||||
initInstances();
|
initInstances();
|
||||||
initAccounts();
|
initAccounts();
|
||||||
initNetwork();
|
initNetwork();
|
||||||
@ -842,6 +839,7 @@ void MultiMC::initGlobalSettings()
|
|||||||
m_globalSettingsProvider->addPage<MinecraftPage>();
|
m_globalSettingsProvider->addPage<MinecraftPage>();
|
||||||
m_globalSettingsProvider->addPage<JavaPage>();
|
m_globalSettingsProvider->addPage<JavaPage>();
|
||||||
m_globalSettingsProvider->addPage<ProxyPage>();
|
m_globalSettingsProvider->addPage<ProxyPage>();
|
||||||
|
m_globalSettingsProvider->addPage<PackagesPage>();
|
||||||
m_globalSettingsProvider->addPage<ExternalToolsPage>();
|
m_globalSettingsProvider->addPage<ExternalToolsPage>();
|
||||||
m_globalSettingsProvider->addPage<AccountListPage>();
|
m_globalSettingsProvider->addPage<AccountListPage>();
|
||||||
m_globalSettingsProvider->addPage<PasteEEPage>();
|
m_globalSettingsProvider->addPage<PasteEEPage>();
|
||||||
@ -868,36 +866,6 @@ std::shared_ptr<LWJGLVersionList> MultiMC::lwjgllist()
|
|||||||
return m_lwjgllist;
|
return m_lwjgllist;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<ForgeVersionList> MultiMC::forgelist()
|
|
||||||
{
|
|
||||||
if (!m_forgelist)
|
|
||||||
{
|
|
||||||
m_forgelist.reset(new ForgeVersionList());
|
|
||||||
ENV.registerVersionList("net.minecraftforge", m_forgelist);
|
|
||||||
}
|
|
||||||
return m_forgelist;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::shared_ptr<LiteLoaderVersionList> MultiMC::liteloaderlist()
|
|
||||||
{
|
|
||||||
if (!m_liteloaderlist)
|
|
||||||
{
|
|
||||||
m_liteloaderlist.reset(new LiteLoaderVersionList());
|
|
||||||
ENV.registerVersionList("com.mumfrey.liteloader", m_liteloaderlist);
|
|
||||||
}
|
|
||||||
return m_liteloaderlist;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::shared_ptr<MinecraftVersionList> MultiMC::minecraftlist()
|
|
||||||
{
|
|
||||||
if (!m_minecraftlist)
|
|
||||||
{
|
|
||||||
m_minecraftlist.reset(new MinecraftVersionList());
|
|
||||||
ENV.registerVersionList("net.minecraft", m_minecraftlist);
|
|
||||||
}
|
|
||||||
return m_minecraftlist;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::shared_ptr<JavaInstallList> MultiMC::javalist()
|
std::shared_ptr<JavaInstallList> MultiMC::javalist()
|
||||||
{
|
{
|
||||||
if (!m_javalist)
|
if (!m_javalist)
|
||||||
|
@ -18,7 +18,6 @@ class SetupWizard;
|
|||||||
class FolderInstanceProvider;
|
class FolderInstanceProvider;
|
||||||
class GenericPageProvider;
|
class GenericPageProvider;
|
||||||
class QFile;
|
class QFile;
|
||||||
class MinecraftVersionList;
|
|
||||||
class LWJGLVersionList;
|
class LWJGLVersionList;
|
||||||
class HttpMetaCache;
|
class HttpMetaCache;
|
||||||
class SettingsObject;
|
class SettingsObject;
|
||||||
@ -26,8 +25,6 @@ class InstanceList;
|
|||||||
class MojangAccountList;
|
class MojangAccountList;
|
||||||
class IconList;
|
class IconList;
|
||||||
class QNetworkAccessManager;
|
class QNetworkAccessManager;
|
||||||
class ForgeVersionList;
|
|
||||||
class LiteLoaderVersionList;
|
|
||||||
class JavaInstallList;
|
class JavaInstallList;
|
||||||
class UpdateChecker;
|
class UpdateChecker;
|
||||||
class BaseProfilerFactory;
|
class BaseProfilerFactory;
|
||||||
@ -96,10 +93,7 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<TranslationsModel> translations();
|
std::shared_ptr<TranslationsModel> translations();
|
||||||
std::shared_ptr<MinecraftVersionList> minecraftlist();
|
|
||||||
std::shared_ptr<LWJGLVersionList> lwjgllist();
|
std::shared_ptr<LWJGLVersionList> lwjgllist();
|
||||||
std::shared_ptr<ForgeVersionList> forgelist();
|
|
||||||
std::shared_ptr<LiteLoaderVersionList> liteloaderlist();
|
|
||||||
std::shared_ptr<JavaInstallList> javalist();
|
std::shared_ptr<JavaInstallList> javalist();
|
||||||
|
|
||||||
std::shared_ptr<InstanceList> instances() const
|
std::shared_ptr<InstanceList> instances() const
|
||||||
@ -202,9 +196,6 @@ private:
|
|||||||
std::shared_ptr<UpdateChecker> m_updateChecker;
|
std::shared_ptr<UpdateChecker> m_updateChecker;
|
||||||
std::shared_ptr<MojangAccountList> m_accounts;
|
std::shared_ptr<MojangAccountList> m_accounts;
|
||||||
std::shared_ptr<LWJGLVersionList> m_lwjgllist;
|
std::shared_ptr<LWJGLVersionList> m_lwjgllist;
|
||||||
std::shared_ptr<ForgeVersionList> m_forgelist;
|
|
||||||
std::shared_ptr<LiteLoaderVersionList> m_liteloaderlist;
|
|
||||||
std::shared_ptr<MinecraftVersionList> m_minecraftlist;
|
|
||||||
std::shared_ptr<JavaInstallList> m_javalist;
|
std::shared_ptr<JavaInstallList> m_javalist;
|
||||||
std::shared_ptr<TranslationsModel> m_translations;
|
std::shared_ptr<TranslationsModel> m_translations;
|
||||||
std::shared_ptr<GenericPageProvider> m_globalSettingsProvider;
|
std::shared_ptr<GenericPageProvider> m_globalSettingsProvider;
|
||||||
|
@ -26,19 +26,9 @@ public:
|
|||||||
|
|
||||||
switch(role)
|
switch(role)
|
||||||
{
|
{
|
||||||
case BaseVersionList::ParentGameVersionRole:
|
case BaseVersionList::ParentVersionRole:
|
||||||
case BaseVersionList::VersionIdRole:
|
case BaseVersionList::VersionIdRole:
|
||||||
{
|
// TODO: work with metadata here. Previous implementation based on the Version class is not sufficient
|
||||||
auto versionString = data.toString();
|
|
||||||
if(it.value().exact)
|
|
||||||
{
|
|
||||||
return versionString == it.value().string;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return versionIsInInterval(versionString, it.value().string);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
default:
|
default:
|
||||||
{
|
{
|
||||||
auto match = data.toString();
|
auto match = data.toString();
|
||||||
@ -146,7 +136,7 @@ QVariant VersionProxyModel::data(const QModelIndex &index, int role) const
|
|||||||
case Name:
|
case Name:
|
||||||
return sourceModel()->data(parentIndex, BaseVersionList::VersionRole);
|
return sourceModel()->data(parentIndex, BaseVersionList::VersionRole);
|
||||||
case ParentVersion:
|
case ParentVersion:
|
||||||
return sourceModel()->data(parentIndex, BaseVersionList::ParentGameVersionRole);
|
return sourceModel()->data(parentIndex, BaseVersionList::ParentVersionRole);
|
||||||
case Branch:
|
case Branch:
|
||||||
return sourceModel()->data(parentIndex, BaseVersionList::BranchRole);
|
return sourceModel()->data(parentIndex, BaseVersionList::BranchRole);
|
||||||
case Type:
|
case Type:
|
||||||
@ -313,9 +303,9 @@ void VersionProxyModel::setSourceModel(QAbstractItemModel *replacingRaw)
|
|||||||
auto replacing = dynamic_cast<BaseVersionList *>(replacingRaw);
|
auto replacing = dynamic_cast<BaseVersionList *>(replacingRaw);
|
||||||
beginResetModel();
|
beginResetModel();
|
||||||
|
|
||||||
|
m_columns.clear();
|
||||||
if(!replacing)
|
if(!replacing)
|
||||||
{
|
{
|
||||||
m_columns.clear();
|
|
||||||
roles.clear();
|
roles.clear();
|
||||||
filterModel->setSourceModel(replacing);
|
filterModel->setSourceModel(replacing);
|
||||||
return;
|
return;
|
||||||
@ -327,7 +317,7 @@ void VersionProxyModel::setSourceModel(QAbstractItemModel *replacingRaw)
|
|||||||
m_columns.push_back(Name);
|
m_columns.push_back(Name);
|
||||||
}
|
}
|
||||||
/*
|
/*
|
||||||
if(roles.contains(BaseVersionList::ParentGameVersionRole))
|
if(roles.contains(BaseVersionList::ParentVersionRole))
|
||||||
{
|
{
|
||||||
m_columns.push_back(ParentVersion);
|
m_columns.push_back(ParentVersion);
|
||||||
}
|
}
|
||||||
|
@ -1,74 +0,0 @@
|
|||||||
#include "WonkoGui.h"
|
|
||||||
|
|
||||||
#include "dialogs/ProgressDialog.h"
|
|
||||||
#include "wonko/WonkoIndex.h"
|
|
||||||
#include "wonko/WonkoVersionList.h"
|
|
||||||
#include "wonko/WonkoVersion.h"
|
|
||||||
#include "Env.h"
|
|
||||||
|
|
||||||
WonkoIndexPtr Wonko::ensureIndexLoaded(QWidget *parent)
|
|
||||||
{
|
|
||||||
if (!ENV.wonkoIndex()->isLocalLoaded())
|
|
||||||
{
|
|
||||||
ProgressDialog(parent).execWithTask(ENV.wonkoIndex()->localUpdateTask());
|
|
||||||
if (!ENV.wonkoIndex()->isRemoteLoaded() && ENV.wonkoIndex()->lists().size() == 0)
|
|
||||||
{
|
|
||||||
ProgressDialog(parent).execWithTask(ENV.wonkoIndex()->remoteUpdateTask());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return ENV.wonkoIndex();
|
|
||||||
}
|
|
||||||
|
|
||||||
WonkoVersionListPtr Wonko::ensureVersionListExists(const QString &uid, QWidget *parent)
|
|
||||||
{
|
|
||||||
ensureIndexLoaded(parent);
|
|
||||||
if (!ENV.wonkoIndex()->isRemoteLoaded() && !ENV.wonkoIndex()->hasUid(uid))
|
|
||||||
{
|
|
||||||
ProgressDialog(parent).execWithTask(ENV.wonkoIndex()->remoteUpdateTask());
|
|
||||||
}
|
|
||||||
return ENV.wonkoIndex()->getList(uid);
|
|
||||||
}
|
|
||||||
WonkoVersionListPtr Wonko::ensureVersionListLoaded(const QString &uid, QWidget *parent)
|
|
||||||
{
|
|
||||||
WonkoVersionListPtr list = ensureVersionListExists(uid, parent);
|
|
||||||
if (!list)
|
|
||||||
{
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
if (!list->isLocalLoaded())
|
|
||||||
{
|
|
||||||
ProgressDialog(parent).execWithTask(list->localUpdateTask());
|
|
||||||
if (!list->isLocalLoaded())
|
|
||||||
{
|
|
||||||
ProgressDialog(parent).execWithTask(list->remoteUpdateTask());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return list->isComplete() ? list : nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
WonkoVersionPtr Wonko::ensureVersionExists(const QString &uid, const QString &version, QWidget *parent)
|
|
||||||
{
|
|
||||||
WonkoVersionListPtr list = ensureVersionListLoaded(uid, parent);
|
|
||||||
if (!list)
|
|
||||||
{
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
return list->getVersion(version);
|
|
||||||
}
|
|
||||||
WonkoVersionPtr Wonko::ensureVersionLoaded(const QString &uid, const QString &version, QWidget *parent, const UpdateType update)
|
|
||||||
{
|
|
||||||
WonkoVersionPtr vptr = ensureVersionExists(uid, version, parent);
|
|
||||||
if (!vptr)
|
|
||||||
{
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
if (!vptr->isLocalLoaded() || update == AlwaysUpdate)
|
|
||||||
{
|
|
||||||
ProgressDialog(parent).execWithTask(vptr->localUpdateTask());
|
|
||||||
if (!vptr->isLocalLoaded() || update == AlwaysUpdate)
|
|
||||||
{
|
|
||||||
ProgressDialog(parent).execWithTask(vptr->remoteUpdateTask());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return vptr->isComplete() ? vptr : nullptr;
|
|
||||||
}
|
|
@ -1,29 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include <memory>
|
|
||||||
#include "QObjectPtr.h"
|
|
||||||
|
|
||||||
class QWidget;
|
|
||||||
class QString;
|
|
||||||
|
|
||||||
using WonkoIndexPtr = shared_qobject_ptr<class WonkoIndex>;
|
|
||||||
using WonkoVersionListPtr = std::shared_ptr<class WonkoVersionList>;
|
|
||||||
using WonkoVersionPtr = std::shared_ptr<class WonkoVersion>;
|
|
||||||
|
|
||||||
namespace Wonko
|
|
||||||
{
|
|
||||||
enum UpdateType
|
|
||||||
{
|
|
||||||
AlwaysUpdate,
|
|
||||||
UpdateIfNeeded
|
|
||||||
};
|
|
||||||
|
|
||||||
/// Ensures that the index has been loaded, either from the local cache or remotely
|
|
||||||
WonkoIndexPtr ensureIndexLoaded(QWidget *parent);
|
|
||||||
/// Ensures that the given uid exists. Returns a nullptr if it doesn't.
|
|
||||||
WonkoVersionListPtr ensureVersionListExists(const QString &uid, QWidget *parent);
|
|
||||||
/// Ensures that the given uid exists and is loaded, either from the local cache or remotely. Returns nullptr if it doesn't exist or couldn't be loaded.
|
|
||||||
WonkoVersionListPtr ensureVersionListLoaded(const QString &uid, QWidget *parent);
|
|
||||||
WonkoVersionPtr ensureVersionExists(const QString &uid, const QString &version, QWidget *parent);
|
|
||||||
WonkoVersionPtr ensureVersionLoaded(const QString &uid, const QString &version, QWidget *parent, const UpdateType update = UpdateIfNeeded);
|
|
||||||
}
|
|
@ -19,7 +19,6 @@
|
|||||||
|
|
||||||
#include <BaseVersion.h>
|
#include <BaseVersion.h>
|
||||||
#include <icons/IconList.h>
|
#include <icons/IconList.h>
|
||||||
#include <minecraft/MinecraftVersionList.h>
|
|
||||||
#include <tasks/Task.h>
|
#include <tasks/Task.h>
|
||||||
#include <InstanceList.h>
|
#include <InstanceList.h>
|
||||||
|
|
||||||
@ -32,6 +31,9 @@
|
|||||||
#include <QFileDialog>
|
#include <QFileDialog>
|
||||||
#include <QValidator>
|
#include <QValidator>
|
||||||
|
|
||||||
|
#include <meta/Index.h>
|
||||||
|
#include <meta/VersionList.h>
|
||||||
|
|
||||||
class UrlValidator : public QValidator
|
class UrlValidator : public QValidator
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@ -62,7 +64,25 @@ NewInstanceDialog::NewInstanceDialog(const QString & initialGroup, QWidget *pare
|
|||||||
resize(minimumSizeHint());
|
resize(minimumSizeHint());
|
||||||
layout()->setSizeConstraint(QLayout::SetFixedSize);
|
layout()->setSizeConstraint(QLayout::SetFixedSize);
|
||||||
|
|
||||||
setSelectedVersion(MMC->minecraftlist()->getRecommended());
|
auto vlist = ENV.metadataIndex()->get("net.minecraft");
|
||||||
|
if(vlist->isLoaded())
|
||||||
|
{
|
||||||
|
setSelectedVersion(vlist->getRecommended());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
vlist->load();
|
||||||
|
auto task = vlist->getLoadTask();
|
||||||
|
if(vlist->isLoaded())
|
||||||
|
{
|
||||||
|
setSelectedVersion(vlist->getRecommended());
|
||||||
|
}
|
||||||
|
if(task)
|
||||||
|
{
|
||||||
|
connect(task.get(), &Task::succeeded, this, &NewInstanceDialog::versionListUpdated);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
InstIconKey = "default";
|
InstIconKey = "default";
|
||||||
ui->iconButton->setIcon(MMC->icons()->getIcon(InstIconKey));
|
ui->iconButton->setIcon(MMC->icons()->getIcon(InstIconKey));
|
||||||
|
|
||||||
@ -95,6 +115,15 @@ NewInstanceDialog::NewInstanceDialog(const QString & initialGroup, QWidget *pare
|
|||||||
updateDialogState();
|
updateDialogState();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void NewInstanceDialog::versionListUpdated()
|
||||||
|
{
|
||||||
|
if(!m_versionSetByUser)
|
||||||
|
{
|
||||||
|
auto vlist = ENV.metadataIndex()->get("net.minecraft");
|
||||||
|
setSelectedVersion(vlist->getRecommended());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
NewInstanceDialog::~NewInstanceDialog()
|
NewInstanceDialog::~NewInstanceDialog()
|
||||||
{
|
{
|
||||||
delete ui;
|
delete ui;
|
||||||
@ -134,7 +163,7 @@ void NewInstanceDialog::setSelectedVersion(BaseVersionPtr version)
|
|||||||
|
|
||||||
if (m_selectedVersion)
|
if (m_selectedVersion)
|
||||||
{
|
{
|
||||||
ui->versionTextBox->setText(version->name());
|
ui->versionTextBox->setText(version->descriptor());
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -192,15 +221,17 @@ BaseVersionPtr NewInstanceDialog::selectedVersion() const
|
|||||||
|
|
||||||
void NewInstanceDialog::on_btnChangeVersion_clicked()
|
void NewInstanceDialog::on_btnChangeVersion_clicked()
|
||||||
{
|
{
|
||||||
VersionSelectDialog vselect(MMC->minecraftlist().get(), tr("Change Minecraft version"),
|
VersionSelectDialog vselect(ENV.metadataIndex()->get("net.minecraft").get(), tr("Change Minecraft version"), this);
|
||||||
this);
|
|
||||||
vselect.exec();
|
vselect.exec();
|
||||||
if (vselect.result() == QDialog::Accepted)
|
if (vselect.result() == QDialog::Accepted)
|
||||||
{
|
{
|
||||||
BaseVersionPtr version = vselect.selectedVersion();
|
BaseVersionPtr version = vselect.selectedVersion();
|
||||||
if (version)
|
if (version)
|
||||||
|
{
|
||||||
|
m_versionSetByUser = true;
|
||||||
setSelectedVersion(version);
|
setSelectedVersion(version);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void NewInstanceDialog::on_iconButton_clicked()
|
void NewInstanceDialog::on_iconButton_clicked()
|
||||||
|
@ -36,8 +36,6 @@ public:
|
|||||||
|
|
||||||
void setSelectedVersion(BaseVersionPtr version);
|
void setSelectedVersion(BaseVersionPtr version);
|
||||||
|
|
||||||
void loadVersionList();
|
|
||||||
|
|
||||||
QString instName() const;
|
QString instName() const;
|
||||||
QString instGroup() const;
|
QString instGroup() const;
|
||||||
QString iconKey() const;
|
QString iconKey() const;
|
||||||
@ -50,10 +48,12 @@ slots:
|
|||||||
void on_iconButton_clicked();
|
void on_iconButton_clicked();
|
||||||
void on_modpackBtn_clicked();
|
void on_modpackBtn_clicked();
|
||||||
void on_instNameTextBox_textChanged(const QString &arg1);
|
void on_instNameTextBox_textChanged(const QString &arg1);
|
||||||
|
void versionListUpdated();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Ui::NewInstanceDialog *ui;
|
Ui::NewInstanceDialog *ui;
|
||||||
|
|
||||||
|
bool m_versionSetByUser = false;
|
||||||
BaseVersionPtr m_selectedVersion;
|
BaseVersionPtr m_selectedVersion;
|
||||||
QString InstIconKey;
|
QString InstIconKey;
|
||||||
QString originalPlaceholderText;
|
QString originalPlaceholderText;
|
||||||
|
@ -38,7 +38,6 @@ int main(int argc, char *argv[])
|
|||||||
{
|
{
|
||||||
Q_INIT_RESOURCE(multimc);
|
Q_INIT_RESOURCE(multimc);
|
||||||
Q_INIT_RESOURCE(backgrounds);
|
Q_INIT_RESOURCE(backgrounds);
|
||||||
Q_INIT_RESOURCE(versions);
|
|
||||||
|
|
||||||
Q_INIT_RESOURCE(pe_dark);
|
Q_INIT_RESOURCE(pe_dark);
|
||||||
Q_INIT_RESOURCE(pe_light);
|
Q_INIT_RESOURCE(pe_light);
|
||||||
|
@ -36,19 +36,16 @@
|
|||||||
#include <QUrl>
|
#include <QUrl>
|
||||||
|
|
||||||
#include "minecraft/MinecraftProfile.h"
|
#include "minecraft/MinecraftProfile.h"
|
||||||
#include "minecraft/forge/ForgeVersionList.h"
|
|
||||||
#include "minecraft/forge/ForgeInstaller.h"
|
|
||||||
#include "minecraft/liteloader/LiteLoaderVersionList.h"
|
|
||||||
#include "minecraft/liteloader/LiteLoaderInstaller.h"
|
|
||||||
#include "minecraft/auth/MojangAccountList.h"
|
#include "minecraft/auth/MojangAccountList.h"
|
||||||
#include "minecraft/Mod.h"
|
#include "minecraft/Mod.h"
|
||||||
#include "minecraft/MinecraftVersion.h"
|
|
||||||
#include "minecraft/MinecraftVersionList.h"
|
|
||||||
#include "icons/IconList.h"
|
#include "icons/IconList.h"
|
||||||
#include "Exception.h"
|
#include "Exception.h"
|
||||||
|
|
||||||
#include "MultiMC.h"
|
#include "MultiMC.h"
|
||||||
|
|
||||||
|
#include <meta/Index.h>
|
||||||
|
#include <meta/VersionList.h>
|
||||||
|
|
||||||
class IconProxy : public QIdentityProxyModel
|
class IconProxy : public QIdentityProxyModel
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
@ -155,14 +152,14 @@ void VersionPage::packageCurrent(const QModelIndex ¤t, const QModelIndex &
|
|||||||
auto severity = patch->getProblemSeverity();
|
auto severity = patch->getProblemSeverity();
|
||||||
switch(severity)
|
switch(severity)
|
||||||
{
|
{
|
||||||
case PROBLEM_WARNING:
|
case ProblemSeverity::Warning:
|
||||||
ui->frame->setModText(tr("%1 possibly has issues.").arg(patch->getName()));
|
ui->frame->setModText(tr("%1 possibly has issues.").arg(patch->getName()));
|
||||||
break;
|
break;
|
||||||
case PROBLEM_ERROR:
|
case ProblemSeverity::Error:
|
||||||
ui->frame->setModText(tr("%1 has issues!").arg(patch->getName()));
|
ui->frame->setModText(tr("%1 has issues!").arg(patch->getName()));
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
case PROBLEM_NONE:
|
case ProblemSeverity::None:
|
||||||
ui->frame->clear();
|
ui->frame->clear();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -171,11 +168,11 @@ void VersionPage::packageCurrent(const QModelIndex ¤t, const QModelIndex &
|
|||||||
QString problemOut;
|
QString problemOut;
|
||||||
for (auto &problem: problems)
|
for (auto &problem: problems)
|
||||||
{
|
{
|
||||||
if(problem.getSeverity() == PROBLEM_ERROR)
|
if(problem.getSeverity() == ProblemSeverity::Error)
|
||||||
{
|
{
|
||||||
problemOut += tr("Error: ");
|
problemOut += tr("Error: ");
|
||||||
}
|
}
|
||||||
else if(problem.getSeverity() == PROBLEM_WARNING)
|
else if(problem.getSeverity() == ProblemSeverity::Warning)
|
||||||
{
|
{
|
||||||
problemOut += tr("Warning: ");
|
problemOut += tr("Warning: ");
|
||||||
}
|
}
|
||||||
@ -326,8 +323,20 @@ void VersionPage::on_moveDownBtn_clicked()
|
|||||||
|
|
||||||
void VersionPage::on_changeVersionBtn_clicked()
|
void VersionPage::on_changeVersionBtn_clicked()
|
||||||
{
|
{
|
||||||
VersionSelectDialog vselect(m_inst->versionList().get(), tr("Change Minecraft version"),
|
auto versionRow = currentRow();
|
||||||
this);
|
if(versionRow == -1)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
auto patch = m_profile->versionPatch(versionRow);
|
||||||
|
auto name = patch->getName();
|
||||||
|
auto list = patch->getVersionList();
|
||||||
|
if(!list)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
auto uid = list->uid();
|
||||||
|
VersionSelectDialog vselect(list.get(), tr("Change %1 version").arg(name), this);
|
||||||
if (!vselect.exec() || !vselect.selectedVersion())
|
if (!vselect.exec() || !vselect.selectedVersion())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@ -341,6 +350,9 @@ void VersionPage::on_changeVersionBtn_clicked()
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
qDebug() << "Change" << uid << "to" << vselect.selectedVersion()->descriptor();
|
||||||
|
if(uid == "net.minecraft")
|
||||||
|
{
|
||||||
if (!m_profile->isVanilla())
|
if (!m_profile->isVanilla())
|
||||||
{
|
{
|
||||||
auto result = CustomMessageBox::selectable(
|
auto result = CustomMessageBox::selectable(
|
||||||
@ -355,7 +367,8 @@ void VersionPage::on_changeVersionBtn_clicked()
|
|||||||
m_profile->revertToVanilla();
|
m_profile->revertToVanilla();
|
||||||
reloadMinecraftProfile();
|
reloadMinecraftProfile();
|
||||||
}
|
}
|
||||||
m_inst->setIntendedVersionId(vselect.selectedVersion()->descriptor());
|
}
|
||||||
|
m_inst->setComponentVersion(uid, vselect.selectedVersion()->descriptor());
|
||||||
doUpdate();
|
doUpdate();
|
||||||
m_container->refreshContainer();
|
m_container->refreshContainer();
|
||||||
}
|
}
|
||||||
@ -377,16 +390,21 @@ int VersionPage::doUpdate()
|
|||||||
|
|
||||||
void VersionPage::on_forgeBtn_clicked()
|
void VersionPage::on_forgeBtn_clicked()
|
||||||
{
|
{
|
||||||
VersionSelectDialog vselect(MMC->forgelist().get(), tr("Select Forge version"), this);
|
auto vlist = ENV.metadataIndex()->get("net.minecraftforge");
|
||||||
vselect.setExactFilter(BaseVersionList::ParentGameVersionRole, m_inst->currentVersionId());
|
if(!vlist)
|
||||||
vselect.setEmptyString(tr("No Forge versions are currently available for Minecraft ") +
|
{
|
||||||
m_inst->currentVersionId());
|
return;
|
||||||
|
}
|
||||||
|
VersionSelectDialog vselect(vlist.get(), tr("Select Forge version"), this);
|
||||||
|
vselect.setExactFilter(BaseVersionList::ParentVersionRole, m_inst->currentVersionId());
|
||||||
|
vselect.setEmptyString(tr("No Forge versions are currently available for Minecraft ") + m_inst->currentVersionId());
|
||||||
vselect.setEmptyErrorString(tr("Couldn't load or download the Forge version lists!"));
|
vselect.setEmptyErrorString(tr("Couldn't load or download the Forge version lists!"));
|
||||||
if (vselect.exec() && vselect.selectedVersion())
|
if (vselect.exec() && vselect.selectedVersion())
|
||||||
{
|
{
|
||||||
ProgressDialog dialog(this);
|
auto vsn = vselect.selectedVersion();
|
||||||
dialog.execWithTask(
|
m_inst->setComponentVersion("net.minecraftforge", vsn->descriptor());
|
||||||
ForgeInstaller().createInstallTask(m_inst, vselect.selectedVersion(), this));
|
m_profile->reload();
|
||||||
|
// m_profile->installVersion();
|
||||||
preselect(m_profile->rowCount(QModelIndex())-1);
|
preselect(m_profile->rowCount(QModelIndex())-1);
|
||||||
m_container->refreshContainer();
|
m_container->refreshContainer();
|
||||||
}
|
}
|
||||||
@ -394,17 +412,21 @@ void VersionPage::on_forgeBtn_clicked()
|
|||||||
|
|
||||||
void VersionPage::on_liteloaderBtn_clicked()
|
void VersionPage::on_liteloaderBtn_clicked()
|
||||||
{
|
{
|
||||||
VersionSelectDialog vselect(MMC->liteloaderlist().get(), tr("Select LiteLoader version"),
|
auto vlist = ENV.metadataIndex()->get("com.mumfrey.liteloader");
|
||||||
this);
|
if(!vlist)
|
||||||
vselect.setExactFilter(BaseVersionList::ParentGameVersionRole, m_inst->currentVersionId());
|
{
|
||||||
vselect.setEmptyString(tr("No LiteLoader versions are currently available for Minecraft ") +
|
return;
|
||||||
m_inst->currentVersionId());
|
}
|
||||||
|
VersionSelectDialog vselect(vlist.get(), tr("Select LiteLoader version"), this);
|
||||||
|
vselect.setExactFilter(BaseVersionList::ParentVersionRole, m_inst->currentVersionId());
|
||||||
|
vselect.setEmptyString(tr("No LiteLoader versions are currently available for Minecraft ") + m_inst->currentVersionId());
|
||||||
vselect.setEmptyErrorString(tr("Couldn't load or download the LiteLoader version lists!"));
|
vselect.setEmptyErrorString(tr("Couldn't load or download the LiteLoader version lists!"));
|
||||||
if (vselect.exec() && vselect.selectedVersion())
|
if (vselect.exec() && vselect.selectedVersion())
|
||||||
{
|
{
|
||||||
ProgressDialog dialog(this);
|
auto vsn = vselect.selectedVersion();
|
||||||
dialog.execWithTask(
|
m_inst->setComponentVersion("com.mumfrey.liteloader", vsn->descriptor());
|
||||||
LiteLoaderInstaller().createInstallTask(m_inst, vselect.selectedVersion(), this));
|
m_profile->reload();
|
||||||
|
// m_profile->installVersion(vselect.selectedVersion());
|
||||||
preselect(m_profile->rowCount(QModelIndex())-1);
|
preselect(m_profile->rowCount(QModelIndex())-1);
|
||||||
m_container->refreshContainer();
|
m_container->refreshContainer();
|
||||||
}
|
}
|
||||||
@ -456,8 +478,9 @@ void VersionPage::updateButtons(int row)
|
|||||||
ui->moveDownBtn->setEnabled(patch->isMoveable());
|
ui->moveDownBtn->setEnabled(patch->isMoveable());
|
||||||
ui->moveUpBtn->setEnabled(patch->isMoveable());
|
ui->moveUpBtn->setEnabled(patch->isMoveable());
|
||||||
ui->changeVersionBtn->setEnabled(patch->isVersionChangeable());
|
ui->changeVersionBtn->setEnabled(patch->isVersionChangeable());
|
||||||
ui->editBtn->setEnabled(patch->isEditable());
|
ui->editBtn->setEnabled(patch->isCustom());
|
||||||
ui->customizeBtn->setEnabled(patch->isCustomizable());
|
// FIXME: temporarily disabled, bring it back when the new format is stable and ready to replace the 'OneSix' one...
|
||||||
|
ui->customizeBtn->setEnabled(false); // patch->isCustomizable()
|
||||||
ui->revertBtn->setEnabled(patch->isRevertible());
|
ui->revertBtn->setEnabled(patch->isRevertible());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -489,21 +512,19 @@ int VersionPage::currentRow()
|
|||||||
|
|
||||||
void VersionPage::on_customizeBtn_clicked()
|
void VersionPage::on_customizeBtn_clicked()
|
||||||
{
|
{
|
||||||
|
// FIXME: temporarily disabled, bring it back when the new format is stable and ready to replace the 'OneSix' one...
|
||||||
|
return;
|
||||||
auto version = currentRow();
|
auto version = currentRow();
|
||||||
if(version == -1)
|
if(version == -1)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
//HACK HACK remove, this is dumb
|
|
||||||
auto patch = m_profile->versionPatch(version);
|
auto patch = m_profile->versionPatch(version);
|
||||||
auto mc = std::dynamic_pointer_cast<MinecraftVersion>(patch);
|
if(!patch->getVersionFile())
|
||||||
if(mc && mc->needsUpdate())
|
|
||||||
{
|
|
||||||
if(!doUpdate())
|
|
||||||
{
|
{
|
||||||
|
// TODO: wait for the update task to finish here...
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
if(!m_profile->customize(version))
|
if(!m_profile->customize(version))
|
||||||
{
|
{
|
||||||
// TODO: some error box here
|
// TODO: some error box here
|
||||||
@ -535,15 +556,6 @@ void VersionPage::on_revertBtn_clicked()
|
|||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
auto mcraw = MMC->minecraftlist()->findVersion(m_inst->intendedVersionId());
|
|
||||||
auto mc = std::dynamic_pointer_cast<MinecraftVersion>(mcraw);
|
|
||||||
if(mc && mc->needsUpdate())
|
|
||||||
{
|
|
||||||
if(!doUpdate())
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if(!m_profile->revertToBase(version))
|
if(!m_profile->revertToBase(version))
|
||||||
{
|
{
|
||||||
// TODO: some error box here
|
// TODO: some error box here
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user