aboutsummaryrefslogtreecommitdiff
path: root/logic
diff options
context:
space:
mode:
Diffstat (limited to 'logic')
-rw-r--r--logic/JavaChecker.cpp2
-rw-r--r--logic/LegacyUpdate.cpp18
-rw-r--r--logic/OneSixUpdate.cpp14
-rw-r--r--logic/auth/MojangAccount.cpp26
-rw-r--r--logic/auth/MojangAccount.h2
-rw-r--r--logic/auth/YggdrasilTask.cpp30
-rw-r--r--logic/auth/YggdrasilTask.h2
-rw-r--r--logic/auth/flows/AuthenticateTask.cpp4
-rw-r--r--logic/auth/flows/RefreshTask.cpp4
-rw-r--r--logic/auth/flows/ValidateTask.cpp4
-rw-r--r--logic/lists/ForgeVersionList.cpp206
-rw-r--r--logic/lists/ForgeVersionList.h12
-rw-r--r--logic/lists/JavaVersionList.cpp13
-rw-r--r--logic/lists/JavaVersionList.h1
-rw-r--r--logic/lists/MinecraftVersionList.cpp2
-rw-r--r--logic/net/ForgeXzDownload.cpp45
-rw-r--r--logic/net/URLConstants.h2
-rw-r--r--logic/updater/DownloadUpdateTask.cpp16
18 files changed, 310 insertions, 93 deletions
diff --git a/logic/JavaChecker.cpp b/logic/JavaChecker.cpp
index 2b94fbb6..113974ff 100644
--- a/logic/JavaChecker.cpp
+++ b/logic/JavaChecker.cpp
@@ -99,6 +99,7 @@ void JavaChecker::error(QProcess::ProcessError err)
if(err == QProcess::FailedToStart)
{
killTimer.stop();
+ checkerJar.remove();
JavaCheckResult result;
{
@@ -116,6 +117,5 @@ void JavaChecker::timeout()
if(process)
{
process->kill();
- process.reset();
}
}
diff --git a/logic/LegacyUpdate.cpp b/logic/LegacyUpdate.cpp
index e71b270e..fb9dcf2b 100644
--- a/logic/LegacyUpdate.cpp
+++ b/logic/LegacyUpdate.cpp
@@ -76,7 +76,7 @@ void LegacyUpdate::lwjglStart()
return;
}
- setStatus("Downloading new LWJGL.");
+ setStatus(tr("Downloading new LWJGL..."));
auto version = list->getVersion(lwjglVersion);
if (!version)
{
@@ -144,7 +144,7 @@ void LegacyUpdate::lwjglFinished(QNetworkReply *reply)
saveMe.open(QIODevice::WriteOnly);
saveMe.write(m_reply->readAll());
saveMe.close();
- setStatus("Installing new LWJGL...");
+ setStatus(tr("Installing new LWJGL..."));
extractLwjgl();
jarStart();
}
@@ -220,7 +220,7 @@ void LegacyUpdate::extractLwjgl()
// Now if destFileName is still empty, go to the next file.
if (!destFileName.isEmpty())
{
- setStatus("Installing new LWJGL - Extracting " + name);
+ setStatus(tr("Installing new LWJGL - extracting ") + name + "...");
QFile output(destFileName);
output.open(QIODevice::WriteOnly);
output.write(file.readAll()); // FIXME: wste of memory!?
@@ -250,7 +250,7 @@ void LegacyUpdate::jarStart()
return;
}
- setStatus("Checking for jar updates...");
+ setStatus(tr("Checking for jar updates..."));
// Make directories
QDir binDir(inst->binDir());
if (!binDir.exists() && !binDir.mkpath("."))
@@ -260,7 +260,7 @@ void LegacyUpdate::jarStart()
}
// Build a list of URLs that will need to be downloaded.
- setStatus("Downloading new minecraft.jar");
+ setStatus(tr("Downloading new minecraft.jar ..."));
QString version_id = inst->intendedVersionId();
QString localPath = version_id + "/" + version_id + ".jar";
@@ -294,7 +294,7 @@ void LegacyUpdate::jarFailed()
bool LegacyUpdate::MergeZipFiles(QuaZip *into, QFileInfo from, QSet<QString> &contained,
MetainfAction metainf)
{
- setStatus("Installing mods - Adding " + from.fileName());
+ setStatus(tr("Installing mods: Adding ") + from.fileName() + " ...");
QuaZip modZip(from.filePath());
modZip.open(QuaZip::mdUnzip);
@@ -380,7 +380,7 @@ void LegacyUpdate::ModTheJar()
return;
}
- setStatus("Installing mods - backing up minecraft.jar...");
+ setStatus(tr("Installing mods: Backing up minecraft.jar ..."));
if (!baseJar.exists() && !QFile::copy(runnableJar.filePath(), baseJar.filePath()))
{
emitFailed("It seems both the active and base jar are gone. A fresh base jar will "
@@ -405,7 +405,7 @@ void LegacyUpdate::ModTheJar()
}
// TaskStep(); // STEP 1
- setStatus("Installing mods - Opening minecraft.jar");
+ setStatus(tr("Installing mods: Opening minecraft.jar ..."));
QuaZip zipOut(runnableJar.filePath());
if (!zipOut.open(QuaZip::mdCreate))
@@ -419,7 +419,7 @@ void LegacyUpdate::ModTheJar()
QSet<QString> addedFiles;
// Modify the jar
- setStatus("Installing mods - Adding mod files...");
+ setStatus(tr("Installing mods: Adding mod files..."));
for (int i = modList->size() - 1; i >= 0; i--)
{
auto &mod = modList->operator[](i);
diff --git a/logic/OneSixUpdate.cpp b/logic/OneSixUpdate.cpp
index 696eeff0..4d93477a 100644
--- a/logic/OneSixUpdate.cpp
+++ b/logic/OneSixUpdate.cpp
@@ -57,7 +57,7 @@ void OneSixUpdate::executeTask()
/*
* FIXME: in offline mode, do not proceed!
*/
- setStatus("Testing the Java installation.");
+ setStatus(tr("Testing the Java installation..."));
QString java_path = m_inst->settings().get("JavaPath").toString();
checker.reset(new JavaChecker());
@@ -89,7 +89,7 @@ void OneSixUpdate::executeTask()
void OneSixUpdate::checkJavaOnline()
{
- setStatus("Testing the Java installation.");
+ setStatus(tr("Testing the Java installation..."));
QString java_path = m_inst->settings().get("JavaPath").toString();
checker.reset(new JavaChecker());
@@ -128,7 +128,7 @@ void OneSixUpdate::checkFinishedOffline(JavaCheckResult result)
void OneSixUpdate::versionFileStart()
{
QLOG_INFO() << m_inst->name() << ": getting version file.";
- setStatus("Getting the version files from Mojang.");
+ setStatus(tr("Getting the version files from Mojang..."));
QString urlstr = "http://" + URLConstants::AWS_DOWNLOAD_VERSIONS + targetVersion->descriptor() + "/" + targetVersion->descriptor() + ".json";
auto job = new NetJob("Version index");
@@ -196,7 +196,7 @@ void OneSixUpdate::versionFileFailed()
void OneSixUpdate::assetIndexStart()
{
- setStatus("Updating asset index.");
+ setStatus(tr("Updating assets index..."));
OneSixInstance *inst = (OneSixInstance *)m_inst;
std::shared_ptr<OneSixVersion> version = inst->getFullVersion();
QString assetName = version->assets;
@@ -247,7 +247,7 @@ void OneSixUpdate::assetIndexFinished()
}
if(dls.size())
{
- setStatus("Getting the assets files from Mojang...");
+ setStatus(tr("Getting the assets files from Mojang..."));
auto job = new NetJob("Assets for " + inst->name());
for(auto dl: dls)
job->addNetAction(dl);
@@ -281,7 +281,7 @@ void OneSixUpdate::assetsFailed()
void OneSixUpdate::jarlibStart()
{
- setStatus("Getting the library files from Mojang.");
+ setStatus(tr("Getting the library files from Mojang..."));
QLOG_INFO() << m_inst->name() << ": downloading libraries";
OneSixInstance *inst = (OneSixInstance *)m_inst;
bool successful = inst->reloadFullVersion();
@@ -369,7 +369,7 @@ void OneSixUpdate::jarlibFailed()
void OneSixUpdate::prepareForLaunch()
{
- setStatus("Preparing for launch.");
+ setStatus(tr("Preparing for launch..."));
QLOG_INFO() << m_inst->name() << ": preparing for launch";
auto onesix_inst = (OneSixInstance *)m_inst;
diff --git a/logic/auth/MojangAccount.cpp b/logic/auth/MojangAccount.cpp
index bc6af98f..a462eda5 100644
--- a/logic/auth/MojangAccount.cpp
+++ b/logic/auth/MojangAccount.cpp
@@ -32,7 +32,8 @@ MojangAccountPtr MojangAccount::loadFromJson(const QJsonObject &object)
// The JSON object must at least have a username for it to be valid.
if (!object.value("username").isString())
{
- QLOG_ERROR() << "Can't load Mojang account info from JSON object. Username field is missing or of the wrong type.";
+ QLOG_ERROR() << "Can't load Mojang account info from JSON object. Username field is "
+ "missing or of the wrong type.";
return nullptr;
}
@@ -43,7 +44,8 @@ MojangAccountPtr MojangAccount::loadFromJson(const QJsonObject &object)
QJsonArray profileArray = object.value("profiles").toArray();
if (profileArray.size() < 1)
{
- QLOG_ERROR() << "Can't load Mojang account with username \"" << username << "\". No profiles found.";
+ QLOG_ERROR() << "Can't load Mojang account with username \"" << username
+ << "\". No profiles found.";
return nullptr;
}
@@ -63,7 +65,7 @@ MojangAccountPtr MojangAccount::loadFromJson(const QJsonObject &object)
}
MojangAccountPtr account(new MojangAccount());
- if(object.value("user").isObject())
+ if (object.value("user").isObject())
{
User u;
QJsonObject userStructure = object.value("user").toObject();
@@ -92,7 +94,7 @@ MojangAccountPtr MojangAccount::loadFromJson(const QJsonObject &object)
return account;
}
-MojangAccountPtr MojangAccount::createFromUsername(const QString& username)
+MojangAccountPtr MojangAccount::createFromUsername(const QString &username)
{
MojangAccountPtr account(new MojangAccount());
account->m_clientToken = QUuid::createUuid().toString().remove(QRegExp("[{}-]"));
@@ -152,27 +154,27 @@ bool MojangAccount::setCurrentProfile(const QString &profileId)
return false;
}
-const AccountProfile* MojangAccount::currentProfile() const
+const AccountProfile *MojangAccount::currentProfile() const
{
- if(m_currentProfile == -1)
+ if (m_currentProfile == -1)
return nullptr;
return &m_profiles[m_currentProfile];
}
AccountStatus MojangAccount::accountStatus() const
{
- if(m_accessToken.isEmpty())
+ if (m_accessToken.isEmpty())
return NotVerified;
- if(!m_online)
+ if (!m_online)
return Verified;
return Online;
}
-std::shared_ptr<Task> MojangAccount::login(QString password)
+std::shared_ptr<YggdrasilTask> MojangAccount::login(QString password)
{
- if(m_currentTask)
+ if (m_currentTask)
return m_currentTask;
- if(password.isEmpty())
+ if (password.isEmpty())
{
m_currentTask.reset(new RefreshTask(this));
}
@@ -196,7 +198,7 @@ void MojangAccount::authFailed(QString reason)
{
// This is emitted when the yggdrasil tasks time out or are cancelled.
// -> we treat the error as no-op
- if(reason != "Yggdrasil task cancelled.")
+ if (reason != "Yggdrasil task cancelled.")
{
m_online = false;
m_accessToken = QString();
diff --git a/logic/auth/MojangAccount.h b/logic/auth/MojangAccount.h
index 325aa826..dd5d54ae 100644
--- a/logic/auth/MojangAccount.h
+++ b/logic/auth/MojangAccount.h
@@ -95,7 +95,7 @@ public: /* manipulation */
* Attempt to login. Empty password means we use the token.
* If the attempt fails because we already are performing some task, it returns false.
*/
- std::shared_ptr<Task> login(QString password = QString());
+ std::shared_ptr<YggdrasilTask> login(QString password = QString());
void downgrade()
{
diff --git a/logic/auth/YggdrasilTask.cpp b/logic/auth/YggdrasilTask.cpp
index 088e1fc0..3ba53bd7 100644
--- a/logic/auth/YggdrasilTask.cpp
+++ b/logic/auth/YggdrasilTask.cpp
@@ -48,6 +48,7 @@ void YggdrasilTask::executeTask()
connect(m_netReply, &QNetworkReply::finished, this, &YggdrasilTask::processReply);
connect(m_netReply, &QNetworkReply::uploadProgress, this, &YggdrasilTask::refreshTimers);
connect(m_netReply, &QNetworkReply::downloadProgress, this, &YggdrasilTask::refreshTimers);
+ connect(m_netReply, &QNetworkReply::sslErrors, this, &YggdrasilTask::sslErrors);
timeout_keeper.setSingleShot(true);
timeout_keeper.start(timeout_max);
counter.setSingleShot(false);
@@ -75,10 +76,33 @@ void YggdrasilTask::abort()
m_netReply->abort();
}
+void YggdrasilTask::sslErrors(QList<QSslError> errors)
+{
+ int i = 1;
+ for(auto error: errors)
+ {
+ QLOG_ERROR() << "LOGIN SSL Error #" << i << " : " << error.errorString();
+ auto cert = error.certificate();
+ QLOG_ERROR() << "Certificate in question:\n" << cert.toText();
+ i++;
+ }
+}
+
void YggdrasilTask::processReply()
{
setStatus(getStateMessage(STATE_PROCESSING_RESPONSE));
+ if (m_netReply->error() == QNetworkReply::SslHandshakeFailedError)
+ {
+ emitFailed(tr("<b>SSL Handshake failed.</b><br/>There might be a few causes for it:<br/>"
+ "<ul>"
+ "<li>You use Windows XP and need to <a href=\"http://www.microsoft.com/en-us/download/details.aspx?id=38918\">update your root certificates</a></li>"
+ "<li>Some device on your network is interfering with SSL traffic. In that case, you have bigger worries than Minecraft not starting.</li>"
+ "<li>Possibly something else. Check the MultiMC log file for details</li>"
+ "</ul>"));
+ return;
+ }
+
// any network errors lead to offline mode right now
if (m_netReply->error() >= QNetworkReply::ConnectionRefusedError &&
m_netReply->error() <= QNetworkReply::UnknownNetworkError)
@@ -172,10 +196,10 @@ QString YggdrasilTask::getStateMessage(const YggdrasilTask::State state) const
switch (state)
{
case STATE_SENDING_REQUEST:
- return tr("Sending request to auth servers.");
+ return tr("Sending request to auth servers...");
case STATE_PROCESSING_RESPONSE:
- return tr("Processing response from servers.");
+ return tr("Processing response from servers...");
default:
- return tr("Processing. Please wait.");
+ return tr("Processing. Please wait...");
}
}
diff --git a/logic/auth/YggdrasilTask.h b/logic/auth/YggdrasilTask.h
index 1f81a2d0..85f5a1e1 100644
--- a/logic/auth/YggdrasilTask.h
+++ b/logic/auth/YggdrasilTask.h
@@ -20,6 +20,7 @@
#include <QString>
#include <QJsonObject>
#include <QTimer>
+#include <qsslerror.h>
#include "logic/auth/MojangAccount.h"
@@ -99,6 +100,7 @@ slots:
void processReply();
void refreshTimers(qint64, qint64);
void heartbeat();
+ void sslErrors(QList<QSslError>);
public
slots:
diff --git a/logic/auth/flows/AuthenticateTask.cpp b/logic/auth/flows/AuthenticateTask.cpp
index f60be35d..6548c4e9 100644
--- a/logic/auth/flows/AuthenticateTask.cpp
+++ b/logic/auth/flows/AuthenticateTask.cpp
@@ -194,9 +194,9 @@ QString AuthenticateTask::getStateMessage(const YggdrasilTask::State state) cons
switch (state)
{
case STATE_SENDING_REQUEST:
- return tr("Authenticating: Sending request.");
+ return tr("Authenticating: Sending request...");
case STATE_PROCESSING_RESPONSE:
- return tr("Authenticating: Processing response.");
+ return tr("Authenticating: Processing response...");
default:
return YggdrasilTask::getStateMessage(state);
}
diff --git a/logic/auth/flows/RefreshTask.cpp b/logic/auth/flows/RefreshTask.cpp
index 5f68ccc7..f63c736e 100644
--- a/logic/auth/flows/RefreshTask.cpp
+++ b/logic/auth/flows/RefreshTask.cpp
@@ -145,9 +145,9 @@ QString RefreshTask::getStateMessage(const YggdrasilTask::State state) const
switch (state)
{
case STATE_SENDING_REQUEST:
- return tr("Refreshing login token.");
+ return tr("Refreshing login token...");
case STATE_PROCESSING_RESPONSE:
- return tr("Refreshing login token: Processing response.");
+ return tr("Refreshing login token: Processing response...");
default:
return YggdrasilTask::getStateMessage(state);
}
diff --git a/logic/auth/flows/ValidateTask.cpp b/logic/auth/flows/ValidateTask.cpp
index 84d5e703..4f7323fd 100644
--- a/logic/auth/flows/ValidateTask.cpp
+++ b/logic/auth/flows/ValidateTask.cpp
@@ -55,9 +55,9 @@ QString ValidateTask::getStateMessage(const YggdrasilTask::State state) const
switch (state)
{
case STATE_SENDING_REQUEST:
- return tr("Validating Access Token: Sending request.");
+ return tr("Validating access token: Sending request...");
case STATE_PROCESSING_RESPONSE:
- return tr("Validating Access Token: Processing response.");
+ return tr("Validating access token: Processing response...");
default:
return YggdrasilTask::getStateMessage(state);
}
diff --git a/logic/lists/ForgeVersionList.cpp b/logic/lists/ForgeVersionList.cpp
index d6d353da..56eca744 100644
--- a/logic/lists/ForgeVersionList.cpp
+++ b/logic/lists/ForgeVersionList.cpp
@@ -15,6 +15,7 @@
#include "ForgeVersionList.h"
#include <logic/net/NetJob.h>
+#include <logic/net/URLConstants.h>
#include "MultiMC.h"
#include <QtNetwork>
@@ -23,8 +24,6 @@
#include "logger/QsLog.h"
-#define JSON_URL "http://files.minecraftforge.net/minecraftforge/json"
-
ForgeVersionList::ForgeVersionList(QObject *parent) : BaseVersionList(parent)
{
}
@@ -159,45 +158,43 @@ ForgeListLoadTask::ForgeListLoadTask(ForgeVersionList *vlist) : Task()
void ForgeListLoadTask::executeTask()
{
- setStatus(tr("Fetching Forge version list"));
+ 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 = MMC->metacache()->resolveEntry("minecraftforge", "list.json");
+ auto gradleForgeListEntry = MMC->metacache()->resolveEntry("minecraftforge", "json");
// verify by poking the server.
forgeListEntry->stale = true;
+ gradleForgeListEntry->stale = true;
+
+ job->addNetAction(listDownload = CacheDownload::make(QUrl(URLConstants::FORGE_LEGACY_URL),
+ forgeListEntry));
+ job->addNetAction(gradleListDownload = CacheDownload::make(
+ QUrl(URLConstants::FORGE_GRADLE_URL), gradleForgeListEntry));
+
+ connect(listDownload.get(), SIGNAL(failed(int)), SLOT(listFailed()));
+ connect(gradleListDownload.get(), SIGNAL(failed(int)), SLOT(gradleListFailed()));
- job->addNetAction(CacheDownload::make(QUrl(JSON_URL), forgeListEntry));
listJob.reset(job);
- connect(listJob.get(), SIGNAL(succeeded()), SLOT(list_downloaded()));
- connect(listJob.get(), SIGNAL(failed()), SLOT(list_failed()));
+ connect(listJob.get(), SIGNAL(succeeded()), SLOT(listDownloaded()));
connect(listJob.get(), SIGNAL(progress(qint64, qint64)), SIGNAL(progress(qint64, qint64)));
listJob->start();
}
-void ForgeListLoadTask::list_failed()
-{
- auto DlJob = listJob->first();
- auto reply = DlJob->m_reply;
- if (reply)
- {
- QLOG_ERROR() << "Getting forge version list failed: " << reply->errorString();
- }
- else
- QLOG_ERROR() << "Getting forge version list failed for reasons unknown.";
-}
-
-void ForgeListLoadTask::list_downloaded()
+bool ForgeListLoadTask::parseForgeList(QList<BaseVersionPtr> &out)
{
QByteArray data;
{
- auto DlJob = listJob->first();
- auto filename = std::dynamic_pointer_cast<CacheDownload>(DlJob)->m_target_path;
+ auto dlJob = listDownload;
+ auto filename = std::dynamic_pointer_cast<CacheDownload>(dlJob)->m_target_path;
QFile listFile(filename);
if (!listFile.open(QIODevice::ReadOnly))
- return;
+ {
+ return false;
+ }
data = listFile.readAll();
- DlJob.reset();
+ dlJob.reset();
}
QJsonParseError jsonError;
@@ -206,13 +203,13 @@ void ForgeListLoadTask::list_downloaded()
if (jsonError.error != QJsonParseError::NoError)
{
emitFailed("Error parsing version list JSON:" + jsonError.errorString());
- return;
+ return false;
}
if (!jsonDoc.isObject())
{
- emitFailed("Error parsing version list JSON: jsonDoc is not an object");
- return;
+ emitFailed("Error parsing version list JSON: JSON root is not an object");
+ return false;
}
QJsonObject root = jsonDoc.object();
@@ -222,11 +219,10 @@ void ForgeListLoadTask::list_downloaded()
{
emitFailed(
"Error parsing version list JSON: version list object is missing 'builds' array");
- return;
+ return false;
}
QJsonArray builds = root.value("builds").toArray();
- QList<BaseVersionPtr> tempList;
for (int i = 0; i < builds.count(); i++)
{
// Load the version info.
@@ -247,7 +243,9 @@ void ForgeListLoadTask::list_downloaded()
for (int j = 0; j < files.count(); j++)
{
if (!files[j].isObject())
+ {
continue;
+ }
QJsonObject file = files[j].toObject();
buildtype = file.value("buildtype").toString();
if ((buildtype == "client" || buildtype == "universal") && !valid)
@@ -263,7 +261,9 @@ void ForgeListLoadTask::list_downloaded()
{
QString ext = file.value("ext").toString();
if (ext.isEmpty())
+ {
continue;
+ }
changelog_url = file.value("url").toString();
}
else if (buildtype == "installer")
@@ -283,15 +283,161 @@ void ForgeListLoadTask::list_downloaded()
fVersion->jobbuildver = jobbuildver;
fVersion->mcver = mcver;
if (installer_filename.isEmpty())
+ {
fVersion->filename = filename;
+ }
else
+ {
fVersion->filename = installer_filename;
+ }
fVersion->m_buildnr = build_nr;
- tempList.append(fVersion);
+ out.append(fVersion);
+ }
+ }
+
+ return true;
+}
+
+bool ForgeListLoadTask::parseForgeGradleList(QList<BaseVersionPtr> &out)
+{
+ QByteArray data;
+ {
+ auto dlJob = gradleListDownload;
+ auto filename = std::dynamic_pointer_cast<CacheDownload>(dlJob)->m_target_path;
+ QFile listFile(filename);
+ if (!listFile.open(QIODevice::ReadOnly))
+ {
+ return false;
+ }
+ data = listFile.readAll();
+ dlJob.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();
+ fVersion->jobbuildver = number.value("version").toString();
+ fVersion->mcver = number.value("mcversion").toString();
+ fVersion->filename = "";
+ QString 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;
+ }
+ if (file.at(1).toString() == "installer")
+ {
+ fVersion->installer_url = QString("%1/%2-%3/%4-%2-%3-installer.%5").arg(
+ webpath, fVersion->mcver, fVersion->jobbuildver, artifact,
+ file.at(0).toString());
+ installer_filename = QString("%1-%2-%3-installer.%4").arg(
+ artifact, fVersion->mcver, fVersion->jobbuildver, file.at(0).toString());
+ }
+ else if (file.at(1).toString() == "universal")
+ {
+ fVersion->universal_url = QString("%1/%2-%3/%4-%2-%3-universal.%5").arg(
+ webpath, fVersion->mcver, fVersion->jobbuildver, artifact,
+ file.at(0).toString());
+ filename = QString("%1-%2-%3-universal.%4").arg(
+ artifact, fVersion->mcver, fVersion->jobbuildver, file.at(0).toString());
+ }
+ else if (file.at(1).toString() == "changelog")
+ {
+ fVersion->changelog_url = QString("%1/%2-%3/%4-%2-%3-changelog.%5").arg(
+ webpath, fVersion->mcver, fVersion->jobbuildver, artifact,
+ file.at(0).toString());
+ }
+ }
+ if (fVersion->installer_url.isEmpty() && fVersion->universal_url.isEmpty())
+ {
+ continue;
}
+ fVersion->filename = fVersion->installer_url.isEmpty() ? filename : installer_filename;
+ out.append(fVersion);
}
- m_list->updateListData(tempList);
+
+ return true;
+}
+
+void ForgeListLoadTask::listDownloaded()
+{
+ QList<BaseVersionPtr> list;
+ bool ret = true;
+ if (!parseForgeList(list))
+ {
+ ret = false;
+ }
+ if (!parseForgeGradleList(list))
+ {
+ ret = false;
+ }
+
+ if (!ret)
+ {
+ return;
+ }
+
+ qSort(list.begin(), list.end(), [](const BaseVersionPtr & p1, const BaseVersionPtr & p2)
+ {
+ // TODO better comparison (takes major/minor/build number into account)
+ return p1->name() > p2->name();
+ });
+
+ m_list->updateListData(list);
emitSucceeded();
return;
}
+
+void ForgeListLoadTask::listFailed()
+{
+ auto reply = listDownload->m_reply;
+ if (reply)
+ {
+ QLOG_ERROR() << "Getting forge version list failed: " << reply->errorString();
+ }
+ else
+ {
+ QLOG_ERROR() << "Getting forge version list failed for reasons unknown.";
+ }
+}
+void ForgeListLoadTask::gradleListFailed()
+{
+ auto reply = gradleListDownload->m_reply;
+ if (reply)
+ {
+ QLOG_ERROR() << "Getting forge version list failed: " << reply->errorString();
+ }
+ else
+ {
+ QLOG_ERROR() << "Getting forge version list failed for reasons unknown.";
+ }
+}
diff --git a/logic/lists/ForgeVersionList.h b/logic/lists/ForgeVersionList.h
index f32975ed..924084ae 100644
--- a/logic/lists/ForgeVersionList.h
+++ b/logic/lists/ForgeVersionList.h
@@ -98,10 +98,18 @@ public:
protected
slots:
- void list_downloaded();
- void list_failed();
+ void listDownloaded();
+ void listFailed();
+ void gradleListFailed();
protected:
NetJobPtr listJob;
ForgeVersionList *m_list;
+
+ CacheDownloadPtr listDownload;
+ CacheDownloadPtr gradleListDownload;
+
+private:
+ bool parseForgeList(QList<BaseVersionPtr> &out);
+ bool parseForgeGradleList(QList<BaseVersionPtr> &out);
};
diff --git a/logic/lists/JavaVersionList.cpp b/logic/lists/JavaVersionList.cpp
index d2f0972c..e8c5acd0 100644
--- a/logic/lists/JavaVersionList.cpp
+++ b/logic/lists/JavaVersionList.cpp
@@ -172,14 +172,14 @@ JavaListLoadTask::~JavaListLoadTask()
void JavaListLoadTask::executeTask()
{
- setStatus("Detecting Java installations...");
+ setStatus(tr("Detecting Java installations..."));
JavaUtils ju;
QList<QString> candidate_paths = ju.FindJavaPaths();
- auto job = new JavaCheckerJob("Java detection");
- connect(job, SIGNAL(finished(QList<JavaCheckResult>)), this, SLOT(javaCheckerFinished(QList<JavaCheckResult>)));
- connect(job, SIGNAL(progress(int, int)), this, SLOT(checkerProgress(int, int)));
+ m_job = std::shared_ptr<JavaCheckerJob>(new JavaCheckerJob("Java detection"));
+ connect(m_job.get(), SIGNAL(finished(QList<JavaCheckResult>)), this, SLOT(javaCheckerFinished(QList<JavaCheckResult>)));
+ connect(m_job.get(), SIGNAL(progress(int, int)), this, SLOT(checkerProgress(int, int)));
QLOG_DEBUG() << "Probing the following Java paths: ";
for(QString candidate : candidate_paths)
@@ -188,10 +188,10 @@ void JavaListLoadTask::executeTask()
auto candidate_checker = new JavaChecker();
candidate_checker->path = candidate;
- job->addJavaCheckerAction(JavaCheckerPtr(candidate_checker));
+ m_job->addJavaCheckerAction(JavaCheckerPtr(candidate_checker));
}
- job->start();
+ m_job->start();
}
void JavaListLoadTask::checkerProgress(int current, int total)
@@ -203,6 +203,7 @@ void JavaListLoadTask::checkerProgress(int current, int total)
void JavaListLoadTask::javaCheckerFinished(QList<JavaCheckResult> results)
{
QList<JavaVersionPtr> candidates;
+ m_job.reset();
QLOG_DEBUG() << "Found the following valid Java installations:";
for(JavaCheckResult result : results)
diff --git a/logic/lists/JavaVersionList.h b/logic/lists/JavaVersionList.h
index 879b2480..e6cc8e5f 100644
--- a/logic/lists/JavaVersionList.h
+++ b/logic/lists/JavaVersionList.h
@@ -90,6 +90,7 @@ public slots:
void checkerProgress(int current, int total);
protected:
+ std::shared_ptr<JavaCheckerJob> m_job;
JavaVersionList *m_list;
JavaVersion *m_currentRecommended;
};
diff --git a/logic/lists/MinecraftVersionList.cpp b/logic/lists/MinecraftVersionList.cpp
index 523b81ac..91f86df0 100644
--- a/logic/lists/MinecraftVersionList.cpp
+++ b/logic/lists/MinecraftVersionList.cpp
@@ -139,7 +139,7 @@ MCVListLoadTask::~MCVListLoadTask()
void MCVListLoadTask::executeTask()
{
- setStatus("Loading instance version list...");
+ setStatus(tr("Loading instance version list..."));
auto worker = MMC->qnam();
vlistReply = worker->get(QNetworkRequest(QUrl("http://" + URLConstants::AWS_DOWNLOAD_VERSIONS + "versions.json")));
connect(vlistReply, SIGNAL(finished()), this, SLOT(list_downloaded()));
diff --git a/logic/net/ForgeXzDownload.cpp b/logic/net/ForgeXzDownload.cpp
index 83cbabd0..359ad858 100644
--- a/logic/net/ForgeXzDownload.cpp
+++ b/logic/net/ForgeXzDownload.cpp
@@ -311,18 +311,51 @@ void ForgeXzDownload::decompressAndInstall()
m_pack200_xz_file.remove();
// revert pack200
- pack200_file.close();
- QString pack_name = pack200_file.fileName();
- QString source_native = QDir::toNativeSeparators(pack_name);
- QString target_native = QDir::toNativeSeparators(m_target_path);
+ pack200_file.seek(0);
+ int handle_in = pack200_file.handle();
+ // FIXME: dispose of file handles, pointers and the like. Ideally wrap in objects.
+ if(handle_in == -1)
+ {
+ QLOG_ERROR() << "Error reopening " << pack200_file.fileName();
+ failAndTryNextMirror();
+ return;
+ }
+ FILE * file_in = fdopen(handle_in,"r");
+ if(!file_in)
+ {
+ QLOG_ERROR() << "Error reopening " << pack200_file.fileName();
+ failAndTryNextMirror();
+ return;
+ }
+ QFile qfile_out(m_target_path);
+ if(!qfile_out.open(QIODevice::WriteOnly))
+ {
+ QLOG_ERROR() << "Error opening " << qfile_out.fileName();
+ failAndTryNextMirror();
+ return;
+ }
+ int handle_out = qfile_out.handle();
+ if(handle_out == -1)
+ {
+ QLOG_ERROR() << "Error opening " << qfile_out.fileName();
+ failAndTryNextMirror();
+ return;
+ }
+ FILE * file_out = fdopen(handle_out,"w");
+ if(!file_out)
+ {
+ QLOG_ERROR() << "Error opening " << qfile_out.fileName();
+ failAndTryNextMirror();
+ return;
+ }
try
{
- unpack_200(source_native.toStdString(), target_native.toStdString());
+ unpack_200(file_in, file_out);
}
catch (std::runtime_error &err)
{
m_status = Job_Failed;
- QLOG_ERROR() << "Error unpacking " << pack_name.toUtf8() << " : " << err.what();
+ QLOG_ERROR() << "Error unpacking " << pack200_file.fileName() << " : " << err.what();
QFile f(m_target_path);
if (f.exists())
f.remove();
diff --git a/logic/net/URLConstants.h b/logic/net/URLConstants.h
index dcd5c2b1..9579198d 100644
--- a/logic/net/URLConstants.h
+++ b/logic/net/URLConstants.h
@@ -29,4 +29,6 @@ const QString RESOURCE_BASE("resources.download.minecraft.net/");
const QString LIBRARY_BASE("libraries.minecraft.net/");
const QString SKINS_BASE("skins.minecraft.net/MinecraftSkins/");
const QString AUTH_BASE("authserver.mojang.com/");
+const QString FORGE_LEGACY_URL("http://files.minecraftforge.net/minecraftforge/json");
+const QString FORGE_GRADLE_URL("http://files.minecraftforge.net/maven/net/minecraftforge/forge/json");
}
diff --git a/logic/updater/DownloadUpdateTask.cpp b/logic/updater/DownloadUpdateTask.cpp
index 6157608f..5f05b0ba 100644
--- a/logic/updater/DownloadUpdateTask.cpp
+++ b/logic/updater/DownloadUpdateTask.cpp
@@ -77,7 +77,7 @@ void DownloadUpdateTask::processChannels()
void DownloadUpdateTask::findCurrentVersionInfo()
{
- setStatus(tr("Finding information about the current version."));
+ setStatus(tr("Finding information about the current version..."));
auto checker = MMC->updateChecker();
@@ -98,7 +98,7 @@ void DownloadUpdateTask::findCurrentVersionInfo()
void DownloadUpdateTask::loadVersionInfo()
{
- setStatus(tr("Loading version information."));
+ setStatus(tr("Loading version information..."));
// Create the net job for loading version info.
NetJob *netJob = new NetJob("Version Info");
@@ -153,10 +153,8 @@ void DownloadUpdateTask::vinfoDownloadFailed()
void DownloadUpdateTask::parseDownloadedVersionInfo()
{
- setStatus(tr("Reading file lists."));
-
- setStatus(tr("Reading file list for new version."));
- QLOG_DEBUG() << "Reading file list for new version.";
+ setStatus(tr("Reading file list for new version..."));
+ QLOG_DEBUG() << "Reading file list for new version...";
QString error;
if (!parseVersionInfo(
std::dynamic_pointer_cast<ByteArrayDownload>(m_vinfoNetJob->first())->m_data,
@@ -170,8 +168,8 @@ void DownloadUpdateTask::parseDownloadedVersionInfo()
// info.
if (m_vinfoNetJob->size() >= 2 && m_vinfoNetJob->operator[](1)->m_status != Job_Failed)
{
- setStatus(tr("Reading file list for current version."));
- QLOG_DEBUG() << "Reading file list for current version.";
+ setStatus(tr("Reading file list for current version..."));
+ QLOG_DEBUG() << "Reading file list for current version...";
QString error;
parseVersionInfo(
std::dynamic_pointer_cast<ByteArrayDownload>(m_vinfoNetJob->operator[](1))->m_data,
@@ -278,7 +276,7 @@ DownloadUpdateTask::processFileLists(NetJob *job,
const DownloadUpdateTask::VersionFileList &newVersion,
DownloadUpdateTask::UpdateOperationList &ops)
{
- setStatus(tr("Processing file lists. Figuring out how to install the update."));
+ setStatus(tr("Processing file lists - figuring out how to install the update..."));
// First, if we've loaded the current version's file list, we need to iterate through it and
// delete anything in the current one version's list that isn't in the new version's list.