aboutsummaryrefslogtreecommitdiff
path: root/logic/minecraft
diff options
context:
space:
mode:
authorPetr Mrázek <peterix@gmail.com>2014-05-11 12:37:21 +0200
committerPetr Mrázek <peterix@gmail.com>2014-06-09 01:38:30 +0200
commit69c3e7111f93290d1278d6116e9fd50079b4fe79 (patch)
treecbaed3022e8705f1da29777afea0fca16c1abe60 /logic/minecraft
parent92abe4c603e1f4931cd02ae6b752cb7054d8e30d (diff)
downloadPrismLauncher-69c3e7111f93290d1278d6116e9fd50079b4fe79.tar.gz
PrismLauncher-69c3e7111f93290d1278d6116e9fd50079b4fe79.tar.bz2
PrismLauncher-69c3e7111f93290d1278d6116e9fd50079b4fe79.zip
Make 1.6+ work with new instance format.
Diffstat (limited to 'logic/minecraft')
-rw-r--r--logic/minecraft/JarMod.cpp12
-rw-r--r--logic/minecraft/JarMod.h1
-rw-r--r--logic/minecraft/MinecraftVersion.cpp60
-rw-r--r--logic/minecraft/MinecraftVersion.h73
-rw-r--r--logic/minecraft/MinecraftVersionList.cpp518
-rw-r--r--logic/minecraft/MinecraftVersionList.h36
-rw-r--r--logic/minecraft/OneSixLibrary.cpp79
-rw-r--r--logic/minecraft/OneSixLibrary.h32
-rw-r--r--logic/minecraft/OneSixRule.h7
-rw-r--r--logic/minecraft/ParseUtils.cpp7
-rw-r--r--logic/minecraft/ParseUtils.h2
-rw-r--r--logic/minecraft/RawLibrary.cpp155
-rw-r--r--logic/minecraft/RawLibrary.h37
-rw-r--r--logic/minecraft/VersionBuilder.h6
-rw-r--r--logic/minecraft/VersionFile.cpp203
-rw-r--r--logic/minecraft/VersionFile.h6
-rw-r--r--logic/minecraft/VersionPatch.h2
-rw-r--r--logic/minecraft/VersionSource.h9
18 files changed, 822 insertions, 423 deletions
diff --git a/logic/minecraft/JarMod.cpp b/logic/minecraft/JarMod.cpp
index 99a30aa5..18a9411c 100644
--- a/logic/minecraft/JarMod.cpp
+++ b/logic/minecraft/JarMod.cpp
@@ -1,5 +1,6 @@
#include "JarMod.h"
#include "logic/MMCJson.h"
+using namespace MMCJson;
JarmodPtr Jarmod::fromJson(const QJsonObject &libObj, const QString &filename)
{
@@ -28,6 +29,7 @@ JarmodPtr Jarmod::fromJson(const QJsonObject &libObj, const QString &filename)
};
readString("url", out->baseurl);
+ readString("MMC-hint", out->hint);
readString("MMC-absoluteUrl", out->absoluteUrl);
if(!out->baseurl.isEmpty() && out->absoluteUrl.isEmpty())
{
@@ -36,6 +38,16 @@ JarmodPtr Jarmod::fromJson(const QJsonObject &libObj, const QString &filename)
return out;
}
+QJsonObject Jarmod::toJson()
+{
+ QJsonObject out;
+ writeString(out, "name", name);
+ writeString(out, "url", baseurl);
+ writeString(out, "MMC-absoluteUrl", absoluteUrl);
+ writeString(out, "MMC-hint", hint);
+ return out;
+}
+
QString Jarmod::url()
{
if(!absoluteUrl.isEmpty())
diff --git a/logic/minecraft/JarMod.h b/logic/minecraft/JarMod.h
index da5d8db0..c438dbcd 100644
--- a/logic/minecraft/JarMod.h
+++ b/logic/minecraft/JarMod.h
@@ -8,6 +8,7 @@ class Jarmod
{
public: /* methods */
static JarmodPtr fromJson(const QJsonObject &libObj, const QString &filename);
+ QJsonObject toJson();
QString url();
public: /* data */
QString name;
diff --git a/logic/minecraft/MinecraftVersion.cpp b/logic/minecraft/MinecraftVersion.cpp
index 2191e8af..e0cbce8d 100644
--- a/logic/minecraft/MinecraftVersion.cpp
+++ b/logic/minecraft/MinecraftVersion.cpp
@@ -1,29 +1,26 @@
#include "MinecraftVersion.h"
#include "VersionFinal.h"
+#include "VersionBuildError.h"
+#include "VersionBuilder.h"
bool MinecraftVersion::usesLegacyLauncher()
{
return m_traits.contains("legacyLaunch") || m_traits.contains("aplhaLaunch");
}
+
QString MinecraftVersion::descriptor()
{
return m_descriptor;
}
+
QString MinecraftVersion::name()
{
return m_name;
}
+
QString MinecraftVersion::typeString() const
{
- if (is_latest && is_snapshot)
- {
- return QObject::tr("Latest snapshot");
- }
- else if (is_latest)
- {
- return QObject::tr("Latest release");
- }
- else if (is_snapshot)
+ if (is_snapshot)
{
return QObject::tr("Snapshot");
}
@@ -32,22 +29,41 @@ QString MinecraftVersion::typeString() const
return QObject::tr("Regular release");
}
}
+
bool MinecraftVersion::hasJarMods()
{
return false;
}
-bool MinecraftVersion::isVanilla()
+
+bool MinecraftVersion::isMinecraftVersion()
{
return true;
}
+// 1. assume the local file is good. load, check. If it's good, apply.
+// 2. if discrepancies are found, fall out and fail (impossible to apply incomplete version).
+void MinecraftVersion::applyFileTo(VersionFinal *version)
+{
+ QFileInfo versionFile(QString("versions/%1/%1.json").arg(m_descriptor));
+
+ auto versionObj = VersionBuilder::parseJsonFile(versionFile, false, false);
+ versionObj->applyTo(version);
+}
+
void MinecraftVersion::applyTo(VersionFinal *version)
{
- // FIXME: make this work.
- if(m_versionSource != Builtin)
+ // do we have this one cached?
+ if (m_versionSource == Local)
{
+ applyFileTo(version);
return;
}
+ // if not builtin, do not proceed any further.
+ if (m_versionSource != Builtin)
+ {
+ throw VersionIncomplete(QObject::tr(
+ "Minecraft version %1 could not be applied: version files are missing.").arg(m_descriptor));
+ }
if (!m_descriptor.isNull())
{
version->id = m_descriptor;
@@ -81,15 +97,35 @@ void MinecraftVersion::applyTo(VersionFinal *version)
}
version->traits.unite(m_traits);
}
+
int MinecraftVersion::getOrder()
{
return order;
}
+
void MinecraftVersion::setOrder(int order)
{
this->order = order;
}
+
QList<JarmodPtr> MinecraftVersion::getJarMods()
{
return QList<JarmodPtr>();
}
+
+QString MinecraftVersion::getPatchName()
+{
+ return "Minecraft";
+}
+QString MinecraftVersion::getPatchVersion()
+{
+ return m_descriptor;
+}
+QString MinecraftVersion::getPatchID()
+{
+ return "net.minecraft";
+}
+QString MinecraftVersion::getPatchFilename()
+{
+ return QString();
+}
diff --git a/logic/minecraft/MinecraftVersion.h b/logic/minecraft/MinecraftVersion.h
index 6a1c54cb..02afd709 100644
--- a/logic/minecraft/MinecraftVersion.h
+++ b/logic/minecraft/MinecraftVersion.h
@@ -22,26 +22,49 @@
#include "logic/BaseVersion.h"
#include "VersionPatch.h"
#include "VersionFile.h"
+#include "VersionSource.h"
class VersionFinal;
+class MinecraftVersion;
+typedef std::shared_ptr<MinecraftVersion> MinecraftVersionPtr;
-struct MinecraftVersion : public BaseVersion, public VersionPatch
+class MinecraftVersion : public BaseVersion, public VersionPatch
{
+public: /* methods */
+ bool usesLegacyLauncher();
+ virtual QString descriptor() override;
+ virtual QString name() override;
+ virtual QString typeString() const override;
+ virtual bool hasJarMods() override;
+ virtual bool isMinecraftVersion() override;
+ virtual void applyTo(VersionFinal *version) override;
+ virtual int getOrder();
+ virtual void setOrder(int order);
+ virtual QList<JarmodPtr> getJarMods() override;
+ virtual QString getPatchID() override;
+ virtual QString getPatchVersion() override;
+ virtual QString getPatchName() override;
+ virtual QString getPatchFilename() override;
+ bool needsUpdate()
+ {
+ return m_versionSource == Remote;
+ }
+ bool hasUpdate()
+ {
+ return m_versionSource == Remote || (m_versionSource == Local && upstreamUpdate);
+ }
+
+private: /* methods */
+ void applyFileTo(VersionFinal *version);
+
+public: /* data */
/// The URL that this version will be downloaded from. maybe.
QString download_url;
- /// is this the latest version?
- bool is_latest = false;
-
/// is this a snapshot?
bool is_snapshot = false;
- /// where is this from?
- enum VersionSource
- {
- Builtin,
- Mojang
- } m_versionSource = Builtin;
+ VersionSource m_versionSource = Builtin;
/// the human readable version name
QString m_name;
@@ -74,31 +97,7 @@ struct MinecraftVersion : public BaseVersion, public VersionPatch
/// order of this file... default = -2
int order = -2;
-
- bool usesLegacyLauncher();
- virtual QString descriptor() override;
- virtual QString name() override;
- virtual QString typeString() const override;
- virtual bool hasJarMods() override;
- virtual bool isVanilla() override;
- virtual void applyTo(VersionFinal *version) override;
- virtual int getOrder();
- virtual void setOrder(int order);
- virtual QList<JarmodPtr> getJarMods() override;
- virtual QString getPatchID()
- {
- return "net.minecraft";
- }
- virtual QString getPatchVersion()
- {
- return m_descriptor;
- }
- virtual QString getPatchName()
- {
- return "Minecraft";
- }
- virtual QString getPatchFilename()
- {
- return QString();
- };
+
+ /// an update available from Mojang
+ MinecraftVersionPtr upstreamUpdate;
};
diff --git a/logic/minecraft/MinecraftVersionList.cpp b/logic/minecraft/MinecraftVersionList.cpp
index 1aa220e8..5a5ea348 100644
--- a/logic/minecraft/MinecraftVersionList.cpp
+++ b/logic/minecraft/MinecraftVersionList.cpp
@@ -13,27 +13,35 @@
* limitations under the License.
*/
-#include "MinecraftVersionList.h"
-#include "MultiMC.h"
-#include "logic/net/URLConstants.h"
+#include <QtXml>
#include "logic/MMCJson.h"
-#include "ParseUtils.h"
+#include <QtAlgorithms>
+#include <QtNetwork>
-#include <QtXml>
+#include "MultiMC.h"
+#include "MMCError.h"
-#include <QJsonDocument>
-#include <QJsonObject>
-#include <QJsonArray>
-#include <QJsonValue>
-#include <QJsonParseError>
+#include "MinecraftVersionList.h"
+#include "logic/net/URLConstants.h"
-#include <QtAlgorithms>
+#include "ParseUtils.h"
+#include "VersionBuilder.h"
+#include <logic/VersionFilterData.h>
+#include <pathutils.h>
-#include <QtNetwork>
+class ListLoadError : public MMCError
+{
+public:
+ ListLoadError(QString cause) : MMCError(cause) {};
+ virtual ~ListLoadError() noexcept
+ {
+ }
+};
MinecraftVersionList::MinecraftVersionList(QObject *parent) : BaseVersionList(parent)
{
loadBuiltinList();
+ loadCachedList();
}
Task *MinecraftVersionList::getLoadTask()
@@ -68,6 +76,35 @@ void MinecraftVersionList::sortInternal()
qSort(m_vlist.begin(), m_vlist.end(), cmpVersions);
}
+void MinecraftVersionList::loadCachedList()
+{
+ QFile localIndex("versions/versions.json");
+ if (!localIndex.exists())
+ {
+ return;
+ }
+ if (!localIndex.open(QIODevice::ReadOnly))
+ {
+ // FIXME: this is actually a very bad thing! How do we deal with this?
+ QLOG_ERROR() << "The minecraft version cache can't be read.";
+ return;
+ }
+ auto data = localIndex.readAll();
+ try
+ {
+ loadMojangList(data, Local);
+ }
+ catch (MMCError &e)
+ {
+ // the cache has gone bad for some reason... flush it.
+ QLOG_ERROR() << "The minecraft version cache is corrupted. Flushing cache.";
+ localIndex.close();
+ localIndex.remove();
+ return;
+ }
+ m_hasLocalIndex = true;
+}
+
void MinecraftVersionList::loadBuiltinList()
{
// grab the version list data from internal resources.
@@ -93,19 +130,22 @@ void MinecraftVersionList::loadBuiltinList()
continue;
}
+ if (g_VersionFilterData.legacyBlacklist.contains(versionID))
+ {
+ QLOG_ERROR() << "Blacklisted legacy version ignored: " << versionID;
+ continue;
+ }
+
// Now, we construct the version object and add it to the list.
std::shared_ptr<MinecraftVersion> mcVersion(new MinecraftVersion());
mcVersion->m_name = mcVersion->m_descriptor = versionID;
// Parse the timestamp.
- try
- {
- parse_timestamp(versionObj.value("releaseTime").toString(""),
- mcVersion->m_releaseTimeString, mcVersion->m_releaseTime);
- }
- catch (MMCError &e)
+ if (!parse_timestamp(versionObj.value("releaseTime").toString(""),
+ mcVersion->m_releaseTimeString, mcVersion->m_releaseTime))
{
- QLOG_ERROR() << "Error while parsing version" << versionID << ":" << e.cause();
+ QLOG_ERROR() << "Error while parsing version" << versionID
+ << ": invalid version timestamp";
continue;
}
@@ -113,7 +153,7 @@ void MinecraftVersionList::loadBuiltinList()
mcVersion->download_url =
"http://" + URLConstants::AWS_DOWNLOAD_VERSIONS + versionID + "/";
- mcVersion->m_versionSource = MinecraftVersion::Builtin;
+ mcVersion->m_versionSource = Builtin;
mcVersion->m_appletClass = versionObj.value("appletClass").toString("");
mcVersion->m_mainClass = versionObj.value("mainClass").toString("");
mcVersion->m_processArguments = versionObj.value("processArguments").toString("legacy");
@@ -124,10 +164,141 @@ void MinecraftVersionList::loadBuiltinList()
mcVersion->m_traits.insert(MMCJson::ensureString(traitVal));
}
}
+ m_lookup[versionID] = mcVersion;
m_vlist.append(mcVersion);
}
}
+void MinecraftVersionList::loadMojangList(QByteArray data, VersionSource source)
+{
+ QJsonParseError jsonError;
+ QJsonDocument jsonDoc = QJsonDocument::fromJson(data, &jsonError);
+
+ if (jsonError.error != QJsonParseError::NoError)
+ {
+ throw ListLoadError(
+ tr("Error parsing version list JSON: %1").arg(jsonError.errorString()));
+ }
+
+ QLOG_INFO() << ((source == Remote) ? "Remote version list: " : "Local version list:") << data;
+ if (!jsonDoc.isObject())
+ {
+ throw ListLoadError(tr("Error parsing version list JSON: jsonDoc is not an object"));
+ }
+
+ QJsonObject root = jsonDoc.object();
+
+ try
+ {
+ QJsonObject latest = MMCJson::ensureObject(root.value("latest"));
+ m_latestReleaseID = MMCJson::ensureString(latest.value("release"));
+ m_latestSnapshotID = MMCJson::ensureString(latest.value("snapshot"));
+ }
+ catch (MMCError &err)
+ {
+ QLOG_ERROR()
+ << tr("Error parsing version list JSON: couldn't determine latest versions");
+ }
+
+ // Now, get the array of versions.
+ if (!root.value("versions").isArray())
+ {
+ throw ListLoadError(tr("Error parsing version list JSON: version list object is "
+ "missing 'versions' array"));
+ }
+ QJsonArray versions = root.value("versions").toArray();
+
+ QList<BaseVersionPtr> tempList;
+ for (auto version : versions)
+ {
+ bool is_snapshot = false;
+
+ // Load the version info.
+ if (!version.isObject())
+ {
+ QLOG_ERROR() << "Error while parsing version list : invalid JSON structure";
+ continue;
+ }
+
+ QJsonObject versionObj = version.toObject();
+ QString versionID = versionObj.value("id").toString("");
+ if (versionID.isEmpty())
+ {
+ QLOG_ERROR() << "Error while parsing version : version ID is missing";
+ continue;
+ }
+
+ if (g_VersionFilterData.legacyBlacklist.contains(versionID))
+ {
+ QLOG_ERROR() << "Blacklisted legacy version ignored: " << versionID;
+ continue;
+ }
+
+ // Now, we construct the version object and add it to the list.
+ std::shared_ptr<MinecraftVersion> mcVersion(new MinecraftVersion());
+ mcVersion->m_name = mcVersion->m_descriptor = versionID;
+
+ if (!parse_timestamp(versionObj.value("releaseTime").toString(""),
+ mcVersion->m_releaseTimeString, mcVersion->m_releaseTime))
+ {
+ QLOG_ERROR() << "Error while parsing version" << versionID
+ << ": invalid release timestamp";
+ continue;
+ }
+ if (!parse_timestamp(versionObj.value("time").toString(""),
+ mcVersion->m_updateTimeString, mcVersion->m_updateTime))
+ {
+ QLOG_ERROR() << "Error while parsing version" << versionID
+ << ": invalid update timestamp";
+ continue;
+ }
+
+ if (mcVersion->m_releaseTime < g_VersionFilterData.legacyCutoffDate)
+ {
+ QLOG_ERROR() << "Ignoring Mojang version: " << versionID;
+ continue;
+ }
+
+ // depends on where we load the version from -- network request or local file?
+ mcVersion->m_versionSource = source;
+
+ QString dlUrl = "http://" + URLConstants::AWS_DOWNLOAD_VERSIONS + versionID + "/";
+ mcVersion->download_url = dlUrl;
+ QString versionTypeStr = versionObj.value("type").toString("");
+ if (versionTypeStr.isEmpty())
+ {
+ // FIXME: log this somewhere
+ continue;
+ }
+ // OneSix or Legacy. use filter to determine type
+ if (versionTypeStr == "release")
+ {
+ is_snapshot = false;
+ }
+ else if (versionTypeStr == "snapshot") // It's a snapshot... yay
+ {
+ is_snapshot = true;
+ }
+ else if (versionTypeStr == "old_alpha")
+ {
+ is_snapshot = false;
+ }
+ else if (versionTypeStr == "old_beta")
+ {
+ is_snapshot = false;
+ }
+ else
+ {
+ // FIXME: log this somewhere
+ continue;
+ }
+ mcVersion->m_type = versionTypeStr;
+ mcVersion->is_snapshot = is_snapshot;
+ tempList.append(mcVersion);
+ }
+ updateListData(tempList);
+}
+
void MinecraftVersionList::sort()
{
beginResetModel();
@@ -137,14 +308,8 @@ void MinecraftVersionList::sort()
BaseVersionPtr MinecraftVersionList::getLatestStable() const
{
- for (int i = 0; i < m_vlist.length(); i++)
- {
- auto ver = std::dynamic_pointer_cast<MinecraftVersion>(m_vlist.at(i));
- if (ver->is_latest && !ver->is_snapshot)
- {
- return m_vlist.at(i);
- }
- }
+ if(m_lookup.contains(m_latestReleaseID))
+ return m_lookup[m_latestReleaseID];
return BaseVersionPtr();
}
@@ -154,17 +319,29 @@ void MinecraftVersionList::updateListData(QList<BaseVersionPtr> versions)
for (auto version : versions)
{
auto descr = version->descriptor();
- for (auto builtin_v : m_vlist)
+
+ if (!m_lookup.contains(descr))
{
- if (descr == builtin_v->descriptor())
- {
- goto SKIP_THIS_ONE;
- }
+ m_vlist.append(version);
+ continue;
}
- m_vlist.append(version);
- SKIP_THIS_ONE:
- {
- }
+ auto orig = std::dynamic_pointer_cast<MinecraftVersion>(m_lookup[descr]);
+ auto added = std::dynamic_pointer_cast<MinecraftVersion>(version);
+ // updateListData is called after Mojang list loads. those can be local or remote
+ // remote comes always after local
+ // any other options are ignored
+ if (orig->m_versionSource != Local || added->m_versionSource != Remote)
+ {
+ continue;
+ }
+ // is it actually an update?
+ if (orig->m_updateTime >= added->m_updateTime)
+ {
+ // nope.
+ continue;
+ }
+ // alright, it's an update. put it inside the original, for further processing.
+ orig->upstreamUpdate = added;
}
m_loaded = true;
sortInternal();
@@ -187,10 +364,6 @@ MCVListLoadTask::MCVListLoadTask(MinecraftVersionList *vlist)
vlistReply = nullptr;
}
-MCVListLoadTask::~MCVListLoadTask()
-{
-}
-
void MCVListLoadTask::executeTask()
{
setStatus(tr("Loading instance version list..."));
@@ -209,133 +382,196 @@ void MCVListLoadTask::list_downloaded()
return;
}
- auto foo = vlistReply->readAll();
- QJsonParseError jsonError;
- QLOG_INFO() << foo;
- QJsonDocument jsonDoc = QJsonDocument::fromJson(foo, &jsonError);
+ auto data = vlistReply->readAll();
vlistReply->deleteLater();
-
- if (jsonError.error != QJsonParseError::NoError)
+ try
{
- emitFailed("Error parsing version list JSON:" + jsonError.errorString());
- return;
+ m_list->loadMojangList(data, Remote);
}
-
- if (!jsonDoc.isObject())
+ catch (MMCError &e)
{
- emitFailed("Error parsing version list JSON: jsonDoc is not an object");
+ emitFailed(e.cause());
return;
}
- QJsonObject root = jsonDoc.object();
+ emitSucceeded();
+ return;
+}
- QString latestReleaseID = "INVALID";
- QString latestSnapshotID = "INVALID";
- try
+MCVListVersionUpdateTask::MCVListVersionUpdateTask(MinecraftVersionList *vlist,
+ QString updatedVersion)
+ : Task()
+{
+ m_list = vlist;
+ versionToUpdate = updatedVersion;
+}
+
+void MCVListVersionUpdateTask::executeTask()
+{
+ QString urlstr = "http://" + URLConstants::AWS_DOWNLOAD_VERSIONS + versionToUpdate + "/" +
+ versionToUpdate + ".json";
+ auto job = new NetJob("Version index");
+ job->addNetAction(ByteArrayDownload::make(QUrl(urlstr)));
+ specificVersionDownloadJob.reset(job);
+ connect(specificVersionDownloadJob.get(), SIGNAL(succeeded()), SLOT(json_downloaded()));
+ connect(specificVersionDownloadJob.get(), SIGNAL(failed(QString)), SIGNAL(failed(QString)));
+ connect(specificVersionDownloadJob.get(), SIGNAL(progress(qint64, qint64)),
+ SIGNAL(progress(qint64, qint64)));
+ specificVersionDownloadJob->start();
+}
+
+void MCVListVersionUpdateTask::json_downloaded()
+{
+ NetActionPtr DlJob = specificVersionDownloadJob->first();
+ auto data = std::dynamic_pointer_cast<ByteArrayDownload>(DlJob)->m_data;
+ specificVersionDownloadJob.reset();
+
+ QJsonParseError jsonError;
+ QJsonDocument jsonDoc = QJsonDocument::fromJson(data, &jsonError);
+
+ if (jsonError.error != QJsonParseError::NoError)
{
- QJsonObject latest = MMCJson::ensureObject(root.value("latest"));
- latestReleaseID = MMCJson::ensureString(latest.value("release"));
- latestSnapshotID = MMCJson::ensureString(latest.value("snapshot"));
+ emitFailed(tr("The download version file is not valid."));
+ return;
}
- catch (MMCError &err)
+ VersionFilePtr file;
+ try
{
- QLOG_ERROR()
- << tr("Error parsing version list JSON: couldn't determine latest versions");
+ file = VersionFile::fromJson(jsonDoc, "net.minecraft.json", false);
}
-
- // Now, get the array of versions.
- if (!root.value("versions").isArray())
+ catch (MMCError &e)
{
- emitFailed(
- "Error parsing version list JSON: version list object is missing 'versions' array");
+ emitFailed(tr("Couldn't process version file: %1").arg(e.cause()));
return;
}
- QJsonArray versions = root.value("versions").toArray();
-
- QList<BaseVersionPtr> tempList;
- for (auto version : versions)
+ QList<RawLibraryPtr> filteredLibs;
+ QList<RawLibraryPtr> lwjglLibs;
+ QSet<QString> lwjglFilter = {
+ "net.java.jinput:jinput", "net.java.jinput:jinput-platform",
+ "net.java.jutils:jutils", "org.lwjgl.lwjgl:lwjgl",
+ "org.lwjgl.lwjgl:lwjgl_util", "org.lwjgl.lwjgl:lwjgl-platform"};
+ for (auto lib : file->overwriteLibs)
{
- bool is_snapshot = false;
- bool is_latest = false;
-
- // Load the version info.
- if (!version.isObject())
+ if (lwjglFilter.contains(lib->fullname()))
{
- QLOG_ERROR() << "Error while parsing version list : invalid JSON structure";
- continue;
+ lwjglLibs.append(lib);
}
- QJsonObject versionObj = version.toObject();
- QString versionID = versionObj.value("id").toString("");
- if (versionID.isEmpty())
+ else
{
- QLOG_ERROR() << "Error while parsing version : version ID is missing";
- continue;
+ filteredLibs.append(lib);
}
- // Get the download URL.
- QString dlUrl = "http://" + URLConstants::AWS_DOWNLOAD_VERSIONS + versionID + "/";
+ }
+ file->overwriteLibs = filteredLibs;
- // 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;
+ // TODO: recognize and add LWJGL versions here.
- try
- {
- // Parse the timestamps.
- parse_timestamp(versionObj.value("releaseTime").toString(""),
- mcVersion->m_releaseTimeString, mcVersion->m_releaseTime);
+ file->fileId = "net.minecraft";
- parse_timestamp(versionObj.value("time").toString(""),
- mcVersion->m_updateTimeString, mcVersion->m_updateTime);
- }
- catch (MMCError &e)
- {
- QLOG_ERROR() << "Error while parsing version" << versionID << ":" << e.cause();
+ // now dump the file to disk
+ auto doc = file->toJson(false);
+ auto newdata = doc.toJson();
+ QLOG_INFO() << newdata;
+ QString targetPath = "versions/" + versionToUpdate + "/" + versionToUpdate + ".json";
+ ensureFilePathExists(targetPath);
+ QSaveFile vfile1(targetPath);
+ if (!vfile1.open(QIODevice::Truncate | QIODevice::WriteOnly))
+ {
+ emitFailed(tr("Can't open %1 for writing.").arg(targetPath));
+ return;
+ }
+ qint64 actual = 0;
+ if ((actual = vfile1.write(newdata)) != newdata.size())
+ {
+ emitFailed(tr("Failed to write into %1. Written %2 out of %3.")
+ .arg(targetPath)
+ .arg(actual)
+ .arg(newdata.size()));
+ return;
+ }
+ if (!vfile1.commit())
+ {
+ emitFailed(tr("Can't commit changes to %1").arg(targetPath));
+ return;
+ }
+
+ m_list->finalizeUpdate(versionToUpdate);
+ emitSucceeded();
+}
+
+std::shared_ptr<Task> MinecraftVersionList::createUpdateTask(QString version)
+{
+ return std::shared_ptr<Task>(new MCVListVersionUpdateTask(this, version));
+}
+
+void MinecraftVersionList::saveCachedList()
+{
+ // FIXME: throw.
+ if (!ensureFilePathExists("versions/versions.json"))
+ return;
+ QSaveFile tfile("versions/versions.json");
+ if (!tfile.open(QIODevice::WriteOnly | QIODevice::Truncate))
+ return;
+ QJsonObject toplevel;
+ QJsonArray entriesArr;
+ for (auto version : m_vlist)
+ {
+ auto mcversion = std::dynamic_pointer_cast<MinecraftVersion>(version);
+ // do not save the remote versions.
+ if (mcversion->m_versionSource != Local)
continue;
- }
+ QJsonObject entryObj;
- mcVersion->m_versionSource = MinecraftVersion::Builtin;
- mcVersion->download_url = dlUrl;
+ entryObj.insert("id", mcversion->descriptor());
+ entryObj.insert("time", mcversion->m_updateTimeString);
+ entryObj.insert("releaseTime", mcversion->m_releaseTimeString);
+ entryObj.insert("type", mcversion->m_type);
+ entriesArr.append(entryObj);
+ }
+ toplevel.insert("versions", entriesArr);
+ QJsonDocument doc(toplevel);
+ QByteArray jsonData = doc.toJson();
+ qint64 result = tfile.write(jsonData);
+ if (result == -1)
+ return;
+ if (result != jsonData.size())
+ return;
+ tfile.commit();
+}
+
+void MinecraftVersionList::finalizeUpdate(QString version)
+{
+ int idx = -1;
+ for (int i = 0; i < m_vlist.size(); i++)
+ {
+ if (version == m_vlist[i]->descriptor())
{
- QString versionTypeStr = versionObj.value("type").toString("");
- if (versionTypeStr.isEmpty())
- {
- // FIXME: log this somewhere
- continue;
- }
- // OneSix or Legacy. use filter to determine type
- if (versionTypeStr == "release")
- {
- is_latest = (versionID == latestReleaseID);
- is_snapshot = false;
- }
- else if (versionTypeStr == "snapshot") // It's a snapshot... yay
- {
- is_latest = (versionID == latestSnapshotID);
- is_snapshot = true;
- }
- else if (versionTypeStr == "old_alpha")
- {
- is_latest = false;
- is_snapshot = false;
- }
- else if (versionTypeStr == "old_beta")
- {
- is_latest = false;
- is_snapshot = false;
- }
- else
- {
- // FIXME: log this somewhere
- continue;
- }
- mcVersion->m_type = versionTypeStr;
- mcVersion->is_latest = is_latest;
- mcVersion->is_snapshot = is_snapshot;
+ idx = i;
+ break;
}
- tempList.append(mcVersion);
}
- m_list->updateListData(tempList);
+ if (idx == -1)
+ {
+ return;
+ }
- emitSucceeded();
- return;
+ auto updatedVersion = std::dynamic_pointer_cast<MinecraftVersion>(m_vlist[idx]);
+
+ if (updatedVersion->m_versionSource == Builtin)
+ return;
+
+ if (updatedVersion->upstreamUpdate)
+ {
+ auto updatedWith = updatedVersion->upstreamUpdate;
+ updatedWith->m_versionSource = Local;
+ m_vlist[idx] = updatedWith;
+ m_lookup[version] = updatedWith;
+ }
+ else
+ {
+ updatedVersion->m_versionSource = Local;
+ }
+
+ dataChanged(index(idx), index(idx));
+
+ saveCachedList();
}
diff --git a/logic/minecraft/MinecraftVersionList.h b/logic/minecraft/MinecraftVersionList.h
index 18b9b21e..bbbd71e1 100644
--- a/logic/minecraft/MinecraftVersionList.h
+++ b/logic/minecraft/MinecraftVersionList.h
@@ -22,8 +22,10 @@
#include "logic/BaseVersionList.h"
#include "logic/tasks/Task.h"
#include "logic/minecraft/MinecraftVersion.h"
+#include <logic/net/NetJob.h>
class MCVListLoadTask;
+class MCVListVersionUpdateTask;
class QNetworkReply;
class MinecraftVersionList : public BaseVersionList
@@ -32,11 +34,18 @@ class MinecraftVersionList : public BaseVersionList
private:
void sortInternal();
void loadBuiltinList();
+ void loadMojangList(QByteArray data, 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();
virtual bool isLoaded();
virtual const BaseVersionPtr at(int i) const;
@@ -47,8 +56,12 @@ public:
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:
@@ -61,9 +74,9 @@ class MCVListLoadTask : public Task
public:
explicit MCVListLoadTask(MinecraftVersionList *vlist);
- ~MCVListLoadTask();
+ virtual ~MCVListLoadTask() override{};
- virtual void executeTask();
+ virtual void executeTask() override;
protected
slots:
@@ -74,3 +87,22 @@ protected:
MinecraftVersionList *m_list;
MinecraftVersion *m_currentStable;
};
+
+class MCVListVersionUpdateTask : public Task
+{
+ Q_OBJECT
+
+public:
+ explicit MCVListVersionUpdateTask(MinecraftVersionList *vlist, QString updatedVersion);
+ virtual ~MCVListVersionUpdateTask() override{};
+ virtual void executeTask() override;
+
+protected
+slots:
+ void json_downloaded();
+
+protected:
+ NetJobPtr specificVersionDownloadJob;
+ QString versionToUpdate;
+ MinecraftVersionList *m_list;
+};
diff --git a/logic/minecraft/OneSixLibrary.cpp b/logic