summaryrefslogtreecommitdiffstats
path: root/api/logic/minecraft/legacy
diff options
context:
space:
mode:
Diffstat (limited to 'api/logic/minecraft/legacy')
-rw-r--r--api/logic/minecraft/legacy/LegacyInstance.cpp359
-rw-r--r--api/logic/minecraft/legacy/LegacyInstance.h115
-rw-r--r--api/logic/minecraft/legacy/LegacyModList.cpp533
-rw-r--r--api/logic/minecraft/legacy/LegacyModList.h112
-rw-r--r--api/logic/minecraft/legacy/LegacyUpdate.cpp399
-rw-r--r--api/logic/minecraft/legacy/LegacyUpdate.h70
-rw-r--r--api/logic/minecraft/legacy/LegacyUpgradeTask.cpp142
-rw-r--r--api/logic/minecraft/legacy/LegacyUpgradeTask.h38
-rw-r--r--api/logic/minecraft/legacy/LwjglVersionList.cpp169
-rw-r--r--api/logic/minecraft/legacy/LwjglVersionList.h116
10 files changed, 360 insertions, 1693 deletions
diff --git a/api/logic/minecraft/legacy/LegacyInstance.cpp b/api/logic/minecraft/legacy/LegacyInstance.cpp
index 0987d56f..6e318458 100644
--- a/api/logic/minecraft/legacy/LegacyInstance.cpp
+++ b/api/logic/minecraft/legacy/LegacyInstance.cpp
@@ -1,4 +1,4 @@
-/* Copyright 2013-2017 MultiMC Contributors
+/* Copyright 2013-2018 MultiMC Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -20,7 +20,6 @@
#include "LegacyInstance.h"
-#include "minecraft/legacy/LegacyUpdate.h"
#include "minecraft/legacy/LegacyModList.h"
#include "minecraft/ModList.h"
#include "minecraft/WorldList.h"
@@ -28,14 +27,12 @@
#include <FileSystem.h>
LegacyInstance::LegacyInstance(SettingsObjectPtr globalSettings, SettingsObjectPtr settings, const QString &rootDir)
- : MinecraftInstance(globalSettings, settings, rootDir)
+ : BaseInstance(globalSettings, settings, rootDir)
{
- m_lwjglFolderSetting = globalSettings->getSetting("LWJGLDir");
settings->registerSetting("NeedsRebuild", true);
settings->registerSetting("ShouldUpdate", false);
- settings->registerSetting("JarVersion", "Unknown");
- settings->registerSetting("LwjglVersion", "2.9.0");
- settings->registerSetting("IntendedJarVersion", "");
+ settings->registerSetting("JarVersion", QString());
+ settings->registerSetting("IntendedJarVersion", QString());
/*
* custom base jar has no default. it is determined in code... see the accessor methods for
*it
@@ -68,178 +65,102 @@ QString LegacyInstance::customBaseJar() const
return value;
}
-void LegacyInstance::setCustomBaseJar(QString val)
-{
- if (val.isNull() || val.isEmpty() || val == defaultCustomBaseJar())
- m_settings->reset("CustomBaseJar");
- else
- m_settings->set("CustomBaseJar", val);
-}
-
-void LegacyInstance::setShouldUseCustomBaseJar(bool val)
-{
- m_settings->set("UseCustomBaseJar", val);
-}
-
bool LegacyInstance::shouldUseCustomBaseJar() const
{
return m_settings->get("UseCustomBaseJar").toBool();
}
-shared_qobject_ptr<Task> LegacyInstance::createUpdateTask()
+shared_qobject_ptr<Task> LegacyInstance::createUpdateTask(Net::Mode)
{
- // make sure the jar mods list is initialized by asking for it.
- auto list = jarModList();
- // create an update task
- return shared_qobject_ptr<Task>(new LegacyUpdate(this, this));
+ return nullptr;
}
-std::shared_ptr<Task> LegacyInstance::createJarModdingTask()
+/*
+class LegacyJarModTask : public Task
{
- class JarModTask : public Task
+ //Q_OBJECT
+public:
+ explicit LegacyJarModTask(std::shared_ptr<LegacyInstance> inst) : Task(nullptr), m_inst(inst)
+ {
+ }
+ virtual void executeTask()
{
- public:
- explicit JarModTask(std::shared_ptr<LegacyInstance> inst) : Task(nullptr), m_inst(inst)
+ if (!m_inst->shouldRebuild())
{
+ emitSucceeded();
+ return;
}
- virtual void executeTask()
- {
- if (!m_inst->shouldRebuild())
- {
- emitSucceeded();
- return;
- }
- // Get the mod list
- auto modList = m_inst->getJarMods();
+ // Get the mod list
+ auto modList = m_inst->getJarMods();
- QFileInfo runnableJar(m_inst->runnableJar());
- QFileInfo baseJar(m_inst->baseJar());
- bool base_is_custom = m_inst->shouldUseCustomBaseJar();
+ QFileInfo runnableJar(m_inst->runnableJar());
+ QFileInfo baseJar(m_inst->baseJar());
+ bool base_is_custom = m_inst->shouldUseCustomBaseJar();
- // Nothing to do if there are no jar mods to install, no backup and just the mc jar
- if (base_is_custom)
- {
- // yes, this can happen if the instance only has the runnable jar and not the base jar
- // it *could* be assumed that such an instance is vanilla, but that wouldn't be safe
- // because that's not something mmc4 guarantees
- if (runnableJar.isFile() && !baseJar.exists() && modList.empty())
- {
- m_inst->setShouldRebuild(false);
- emitSucceeded();
- return;
- }
-
- 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 "
- "be used on next run.");
- m_inst->setShouldRebuild(true);
- m_inst->setShouldUpdate(true);
- m_inst->setShouldUseCustomBaseJar(false);
- return;
- }
- }
-
- if (!baseJar.exists())
+ // Nothing to do if there are no jar mods to install, no backup and just the mc jar
+ if (base_is_custom)
+ {
+ // yes, this can happen if the instance only has the runnable jar and not the base jar
+ // it *could* be assumed that such an instance is vanilla, but that wouldn't be safe
+ // because that's not something mmc4 guarantees
+ if (runnableJar.isFile() && !baseJar.exists() && modList.empty())
{
- emitFailed("The base jar " + baseJar.filePath() + " does not exist");
+ m_inst->setShouldRebuild(false);
+ emitSucceeded();
return;
}
- if (runnableJar.exists() && !QFile::remove(runnableJar.filePath()))
+ setStatus(tr("Installing mods: Backing up minecraft.jar ..."));
+ if (!baseJar.exists() && !QFile::copy(runnableJar.filePath(), baseJar.filePath()))
{
- emitFailed("Failed to delete old minecraft.jar");
+ emitFailed("It seems both the active and base jar are gone. A fresh base jar will "
+ "be used on next run.");
+ m_inst->setShouldRebuild(true);
+ m_inst->setShouldUpdate(true);
+ m_inst->setShouldUseCustomBaseJar(false);
return;
}
+ }
- setStatus(tr("Installing mods: Opening minecraft.jar ..."));
-
- QString outputJarPath = runnableJar.filePath();
- QString inputJarPath = baseJar.filePath();
-
- if(!MMCZip::createModdedJar(inputJarPath, outputJarPath, modList))
- {
- emitFailed(tr("Failed to create the custom Minecraft jar file."));
- return;
- }
- m_inst->setShouldRebuild(false);
- // inst->UpdateVersion(true);
- emitSucceeded();
+ if (!baseJar.exists())
+ {
+ emitFailed("The base jar " + baseJar.filePath() + " does not exist");
return;
-
}
- std::shared_ptr<LegacyInstance> m_inst;
- };
- return std::make_shared<JarModTask>(std::dynamic_pointer_cast<LegacyInstance>(shared_from_this()));
-}
-QString LegacyInstance::createLaunchScript(AuthSessionPtr session)
-{
- QString launchScript;
-
- // window size
- QString windowParams;
- if (settings()->get("LaunchMaximized").toBool())
- {
- windowParams = "max";
- }
- else
- {
- windowParams = QString("%1x%2").arg(settings()->get("MinecraftWinWidth").toInt()).arg(settings()->get("MinecraftWinHeight").toInt());
- }
-
- QString lwjgl = QDir(m_lwjglFolderSetting->get().toString() + "/" + lwjglVersion()).absolutePath();
- launchScript += "userName " + session->player_name + "\n";
- launchScript += "sessionId " + session->session + "\n";
- launchScript += "windowTitle " + windowTitle() + "\n";
- launchScript += "windowParams " + windowParams + "\n";
- launchScript += "cp bin/minecraft.jar\n";
- launchScript += "cp " + lwjgl + "/lwjgl.jar\n";
- launchScript += "cp " + lwjgl + "/lwjgl_util.jar\n";
- launchScript += "cp " + lwjgl + "/jinput.jar\n";
- launchScript += "natives " + lwjgl + "/natives\n";
- launchScript += "traits legacyLaunch\n";
- launchScript += "launcher onesix\n";
- return launchScript;
-}
+ if (runnableJar.exists() && !QFile::remove(runnableJar.filePath()))
+ {
+ emitFailed("Failed to delete old minecraft.jar");
+ return;
+ }
-std::shared_ptr<LaunchStep> LegacyInstance::createMainLaunchStep(LaunchTask * parent, AuthSessionPtr session)
-{
- auto step = std::make_shared<LauncherPartLaunch>(parent);
- step->setWorkingDirectory(minecraftRoot());
- step->setAuthSession(session);
- return step;
-}
+ setStatus(tr("Installing mods: Opening minecraft.jar ..."));
-QString LegacyInstance::launchMethod()
-{
- return "Legacy";
-}
+ QString outputJarPath = runnableJar.filePath();
+ QString inputJarPath = baseJar.filePath();
-QStringList LegacyInstance::validLaunchMethods()
-{
- return {"Legacy"};
-}
+ if(!MMCZip::createModdedJar(inputJarPath, outputJarPath, modList))
+ {
+ emitFailed(tr("Failed to create the custom Minecraft jar file."));
+ return;
+ }
+ m_inst->setShouldRebuild(false);
+ // inst->UpdateVersion(true);
+ emitSucceeded();
+ return;
-std::shared_ptr<ModList> LegacyInstance::coreModList() const
-{
- if (!core_mod_list)
- {
- core_mod_list.reset(new ModList(coreModsDir()));
}
- core_mod_list->update();
- return core_mod_list;
-}
+ std::shared_ptr<LegacyInstance> m_inst;
+};
+*/
std::shared_ptr<LegacyModList> LegacyInstance::jarModList() const
{
if (!jar_mod_list)
{
auto list = new LegacyModList(jarModsDir(), modListFile());
- connect(list, SIGNAL(changed()), SLOT(jarModsChanged()));
jar_mod_list.reset(list);
}
jar_mod_list->update();
@@ -251,39 +172,20 @@ QList<Mod> LegacyInstance::getJarMods() const
return jarModList()->allMods();
}
-void LegacyInstance::jarModsChanged()
+QString LegacyInstance::minecraftRoot() const
{
- qDebug() << "Jar mods of instance " << name() << " have changed. Jar will be rebuilt.";
- setShouldRebuild(true);
-}
+ QFileInfo mcDir(FS::PathCombine(instanceRoot(), "minecraft"));
+ QFileInfo dotMCDir(FS::PathCombine(instanceRoot(), ".minecraft"));
-std::shared_ptr<ModList> LegacyInstance::loaderModList() const
-{
- if (!loader_mod_list)
- {
- loader_mod_list.reset(new ModList(loaderModsDir()));
- }
- loader_mod_list->update();
- return loader_mod_list;
+ if (mcDir.exists() && !dotMCDir.exists())
+ return mcDir.filePath();
+ else
+ return dotMCDir.filePath();
}
-std::shared_ptr<ModList> LegacyInstance::texturePackList() const
+QString LegacyInstance::binRoot() const
{
- if (!texture_pack_list)
- {
- texture_pack_list.reset(new ModList(texturePacksDir()));
- }
- texture_pack_list->update();
- return texture_pack_list;
-}
-
-std::shared_ptr<WorldList> LegacyInstance::worldList() const
-{
- if (!m_world_list)
- {
- m_world_list.reset(new WorldList(savesDir()));
- }
- return m_world_list;
+ return FS::PathCombine(minecraftRoot(), "bin");
}
QString LegacyInstance::jarModsDir() const
@@ -340,38 +242,16 @@ bool LegacyInstance::shouldRebuild() const
return m_settings->get("NeedsRebuild").toBool();
}
-void LegacyInstance::setShouldRebuild(bool val)
-{
- m_settings->set("NeedsRebuild", val);
-}
-
QString LegacyInstance::currentVersionId() const
{
return m_settings->get("JarVersion").toString();
}
-QString LegacyInstance::lwjglVersion() const
-{
- return m_settings->get("LwjglVersion").toString();
-}
-
-void LegacyInstance::setLWJGLVersion(QString val)
-{
- m_settings->set("LwjglVersion", val);
-}
-
QString LegacyInstance::intendedVersionId() const
{
return m_settings->get("IntendedJarVersion").toString();
}
-bool LegacyInstance::setIntendedVersionId(QString version)
-{
- settings()->set("IntendedJarVersion", version);
- setShouldUpdate(true);
- return true;
-}
-
bool LegacyInstance::shouldUpdate() const
{
QVariant var = settings()->get("ShouldUpdate");
@@ -382,11 +262,6 @@ bool LegacyInstance::shouldUpdate() const
return true;
}
-void LegacyInstance::setShouldUpdate(bool val)
-{
- settings()->set("ShouldUpdate", val);
-}
-
QString LegacyInstance::defaultBaseJar() const
{
return "versions/" + intendedVersionId() + "/" + intendedVersionId() + ".jar";
@@ -397,9 +272,13 @@ QString LegacyInstance::defaultCustomBaseJar() const
return FS::PathCombine(binRoot(), "mcbackup.jar");
}
-QString LegacyInstance::lwjglFolder() const
+std::shared_ptr<WorldList> LegacyInstance::worldList() const
{
- return m_lwjglFolderSetting->get().toString();
+ if (!m_world_list)
+ {
+ m_world_list.reset(new WorldList(savesDir()));
+ }
+ return m_world_list;
}
QString LegacyInstance::typeName() const
@@ -407,6 +286,11 @@ QString LegacyInstance::typeName() const
return tr("Legacy");
}
+QString LegacyInstance::getStatusbarDescription()
+{
+ return tr("Instance from previous versions.");
+}
+
QStringList LegacyInstance::verboseDescription(AuthSessionPtr session)
{
QStringList out;
@@ -422,48 +306,6 @@ QStringList LegacyInstance::verboseDescription(AuthSessionPtr session)
out << "";
}
- if(loaderModList()->size())
- {
- out << "Mods:";
- for(auto & mod: loaderModList()->allMods())
- {
- if(!mod.enabled())
- continue;
- if(mod.type() == Mod::MOD_FOLDER)
- continue;
- // TODO: proper implementation would need to descend into folders.
-
- out << " " + mod.filename().completeBaseName();
- }
- out << "";
- }
-
- if(coreModList()->size())
- {
- out << "Core Mods:";
- for(auto & coremod: coreModList()->allMods())
- {
- if(!coremod.enabled())
- continue;
- if(coremod.type() == Mod::MOD_FOLDER)
- continue;
- // TODO: proper implementation would need to descend into folders.
-
- out << " " + coremod.filename().completeBaseName();
- }
- out << "";
- }
-
- if(jarModList()->size())
- {
- out << "Jar Mods:";
- for(auto & jarmod: jarModList()->allMods())
- {
- out << " " + jarmod.name() + " (" + jarmod.filename().filePath() + ")";
- }
- out << "";
- }
-
QString windowParams;
if (settings()->get("LaunchMaximized").toBool())
{
@@ -478,40 +320,3 @@ QStringList LegacyInstance::verboseDescription(AuthSessionPtr session)
out << "";
return out;
}
-
-QStringList LegacyInstance::getClassPath() const
-{
- QString launchScript;
- QString lwjgl = getNativePath();
- QStringList out =
- {
- "bin/minecraft.jar",
- lwjgl + "/lwjgl.jar",
- lwjgl + "/lwjgl_util.jar",
- lwjgl + "/jinput.jar"
- };
- return out;
-}
-
-QString LegacyInstance::getMainClass() const
-{
- return "net.minecraft.client.Minecraft";
-}
-
-QString LegacyInstance::getNativePath() const
-{
- return QDir(m_lwjglFolderSetting->get().toString() + "/" + lwjglVersion()).absolutePath();
-}
-
-QStringList LegacyInstance::getNativeJars() const
-{
- return {};
-}
-
-QStringList LegacyInstance::processMinecraftArgs(AuthSessionPtr account) const
-{
- QStringList out;
- out.append(account->player_name);
- out.append(account->session);
- return out;
-}
diff --git a/api/logic/minecraft/legacy/LegacyInstance.h b/api/logic/minecraft/legacy/LegacyInstance.h
index 15d1383f..4a8bc436 100644
--- a/api/logic/minecraft/legacy/LegacyInstance.h
+++ b/api/logic/minecraft/legacy/LegacyInstance.h
@@ -1,4 +1,4 @@
-/* Copyright 2013-2017 MultiMC Contributors
+/* Copyright 2013-2018 MultiMC Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -15,22 +15,27 @@
#pragma once
-#include "minecraft/MinecraftInstance.h"
+#include "BaseInstance.h"
+#include "minecraft/Mod.h"
#include "multimc_logic_export.h"
class ModList;
class LegacyModList;
+class WorldList;
class Task;
-
-class MULTIMC_LOGIC_EXPORT LegacyInstance : public MinecraftInstance
+/*
+ * WHY: Legacy instances - from MultiMC 3 and 4 - are here only to provide a way to upgrade them to the current format.
+ */
+class MULTIMC_LOGIC_EXPORT LegacyInstance : public BaseInstance
{
Q_OBJECT
public:
explicit LegacyInstance(SettingsObjectPtr globalSettings, SettingsObjectPtr settings, const QString &rootDir);
- virtual void init() override {};
+ virtual void init() override {}
+ virtual void saveNow() override {}
/// Path to the instance's minecraft.jar
QString runnableJar() const;
@@ -38,20 +43,6 @@ public:
//! Path to the instance's modlist file.
QString modListFile() const;
- /*
- ////// Edit Instance Dialog stuff //////
- virtual QList<BasePage *> getPages();
- virtual QString dialogTitle();
- */
-
- ////// Mod Lists //////
- std::shared_ptr<LegacyModList> jarModList() const ;
- virtual QList< Mod > getJarMods() const override;
- std::shared_ptr<ModList> coreModList() const;
- std::shared_ptr<ModList> loaderModList() const;
- std::shared_ptr<ModList> texturePackList() const override;
- std::shared_ptr<WorldList> worldList() const override;
-
////// Directories //////
QString libDir() const;
QString savesDir() const;
@@ -61,8 +52,10 @@ public:
QString coreModsDir() const;
QString resourceDir() const;
virtual QString instanceConfigFolder() const override;
+ QString minecraftRoot() const; // Path to the instance's minecraft directory.
+ QString binRoot() const; // Path to the instance's minecraft bin directory.
- /// Get the curent base jar of this instance. By default, it's the
+ /// Get the curent base jar of this instance. By default, it's the
/// versions/$version/$version.jar
QString baseJar() const;
@@ -75,13 +68,15 @@ public:
* Whether or not custom base jar is used
*/
bool shouldUseCustomBaseJar() const;
- void setShouldUseCustomBaseJar(bool val);
/*!
* The value of the custom base jar
*/
QString customBaseJar() const;
- void setCustomBaseJar(QString val);
+
+ std::shared_ptr<LegacyModList> jarModList() const;
+ QList<Mod> getJarMods() const;
+ std::shared_ptr<WorldList> worldList() const;
/*!
* Whether or not the instance's minecraft.jar needs to be rebuilt.
@@ -89,67 +84,57 @@ public:
* re-added to a fresh minecraft.jar file.
*/
bool shouldRebuild() const;
- void setShouldRebuild(bool val);
-
- virtual QString currentVersionId() const override;
-
- //! The version of LWJGL that this instance uses.
- QString lwjglVersion() const;
- //! Where the lwjgl versions foor this instance can be found... HACK HACK HACK
- QString lwjglFolder() const;
+ QString currentVersionId() const;
+ QString intendedVersionId() const;
- /// st the version of LWJGL libs this instance will use
- void setLWJGLVersion(QString val);
-
- virtual QString intendedVersionId() const override;
- virtual bool setIntendedVersionId(QString version) override;
-
- virtual QSet<QString> traits() override
+ QSet<QString> traits() const override
{
return {"legacy-instance", "texturepacks"};
};
- virtual bool shouldUpdate() const override;
- virtual void setShouldUpdate(bool val) override;
- virtual shared_qobject_ptr<Task> createUpdateTask() override;
- virtual std::shared_ptr<Task> createJarModdingTask() override;
- virtual QString createLaunchScript(AuthSessionPtr session) override;
+ virtual bool shouldUpdate() const;
+ virtual shared_qobject_ptr<Task> createUpdateTask(Net::Mode mode) override;
virtual QString typeName() const override;
- bool canExport() const override
+ bool canLaunch() const override
+ {
+ return false;
+ }
+ bool canEdit() const override
{
return true;
}
-
- QStringList getClassPath() const override;
- QString getMainClass() const override;
-
- QStringList getNativeJars() const override;
- QString getNativePath() const override;
-
- QString getLocalLibraryPath() const override
+ bool canExport() const override
+ {
+ return false;
+ }
+ std::shared_ptr<LaunchTask> createLaunchTask(AuthSessionPtr account) override
+ {
+ return nullptr;
+ }
+ IPathMatcher::Ptr getLogFileMatcher() override
+ {
+ return nullptr;
+ }
+ QString getLogFileRoot() override
{
- return QString();
+ return minecraftRoot();
}
- QStringList processMinecraftArgs(AuthSessionPtr account) const override;
+ QString getStatusbarDescription() override;
QStringList verboseDescription(AuthSessionPtr session) override;
-protected:
- std::shared_ptr<LaunchStep> createMainLaunchStep(LaunchTask *parent, AuthSessionPtr session) override;
- QStringList validLaunchMethods() override;
- QString launchMethod() override;
-
+ QProcessEnvironment createEnvironment() override
+ {
+ return QProcessEnvironment();
+ }
+ QMap<QString, QString> getVariables() const override
+ {
+ return {};
+ }
protected:
mutable std::shared_ptr<LegacyModList> jar_mod_list;
- mutable std::shared_ptr<ModList> core_mod_list;
- mutable std::shared_ptr<ModList> loader_mod_list;
- mutable std::shared_ptr<ModList> texture_pack_list;
mutable std::shared_ptr<WorldList> m_world_list;
- std::shared_ptr<Setting> m_lwjglFolderSetting;
-protected
-slots:
- virtual void jarModsChanged();
};
diff --git a/api/logic/minecraft/legacy/LegacyModList.cpp b/api/logic/minecraft/legacy/LegacyModList.cpp
index 052f75fd..638b2e21 100644
--- a/api/logic/minecraft/legacy/LegacyModList.cpp
+++ b/api/logic/minecraft/legacy/LegacyModList.cpp
@@ -1,4 +1,4 @@
-/* Copyright 2013-2017 MultiMC Contributors
+/* Copyright 2013-2018 MultiMC Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -15,55 +15,26 @@
#include "LegacyModList.h"
#include <FileSystem.h>
-#include <QMimeData>
-#include <QUrl>
-#include <QUuid>
#include <QString>
-#include <QFileSystemWatcher>
#include <QDebug>
LegacyModList::LegacyModList(const QString &dir, const QString &list_file)
- : QAbstractListModel(), m_dir(dir), m_list_file(list_file)
+ : m_dir(dir), m_list_file(list_file)
{
FS::ensureFolderPathExists(m_dir.absolutePath());
m_dir.setFilter(QDir::Readable | QDir::NoDotAndDotDot | QDir::Files | QDir::Dirs |
QDir::NoSymLinks);
m_dir.setSorting(QDir::Name | QDir::IgnoreCase | QDir::LocaleAware);
- m_list_id = QUuid::createUuid().toString();
- m_watcher = new QFileSystemWatcher(this);
- is_watching = false;
- connect(m_watcher, SIGNAL(directoryChanged(QString)), this,
- SLOT(directoryChanged(QString)));
}
-void LegacyModList::startWatching()
-{
- update();
- is_watching = m_watcher->addPath(m_dir.absolutePath());
- if (is_watching)
- {
- qDebug() << "Started watching " << m_dir.absolutePath();
- }
- else
- {
- qDebug() << "Failed to start watching " << m_dir.absolutePath();
- }
-}
-
-void LegacyModList::stopWatching()
-{
- is_watching = !m_watcher->removePath(m_dir.absolutePath());
- if (!is_watching)
+ struct OrderItem
{
- qDebug() << "Stopped watching " << m_dir.absolutePath();
- }
- else
- {
- qDebug() << "Failed to stop watching " << m_dir.absolutePath();
- }
-}
+ QString id;
+ bool enabled = false;
+ };
+ typedef QList<OrderItem> OrderList;
-void LegacyModList::internalSort(QList<Mod> &what)
+static void internalSort(QList<Mod> &what)
{
auto predicate = [](const Mod &left, const Mod &right)
{
@@ -76,9 +47,43 @@ void LegacyModList::internalSort(QList<Mod> &what)
std::sort(what.begin(), what.end(), predicate);
}
+static OrderList readListFile(const QString &m_list_file)
+{
+ OrderList itemList;
+ if (m_list_file.isNull() || m_list_file.isEmpty())
+ return itemList;
+
+ QFile textFile(m_list_file);
+ if (!textFile.open(QIODevice::ReadOnly | QIODevice::Text))
+ return OrderList();
+
+ QTextStream textStream;
+ textStream.setAutoDetectUnicode(true);
+ textStream.setDevice(&textFile);
+ while (true)
+ {
+ QString line = textStream.readLine();
+ if (line.isNull() || line.isEmpty())
+ break;
+ else
+ {
+ OrderItem it;
+ it.enabled = !line.endsWith(".disabled");
+ if (!it.enabled)
+ {
+ line.chop(9);
+ }
+ it.id = line;
+ itemList.append(it);
+ }
+ }
+ textFile.close();
+ return itemList;
+}
+
bool LegacyModList::update()
{
- if (!isValid())
+ if (!m_dir.exists() || !m_dir.isReadable())
return false;
QList<Mod> orderedMods;
@@ -88,7 +93,7 @@ bool LegacyModList::update()
bool orderOrStateChanged = false;
// first, process the ordered items (if any)
- OrderList listOrder = readListFile();
+ OrderList listOrder = readListFile(m_list_file);
for (auto item : listOrder)
{
QFileInfo infoEnabled(m_dir.filePath(item.id));
@@ -157,460 +162,10 @@ bool LegacyModList::update()
}
}
}
- beginResetModel();
mods.swap(orderedMods);
- endResetModel();
if (orderOrStateChanged && !m_list_file.isEmpty())
{
qDebug() << "Mod list " << m_list_file << " changed!";
- saveListFile();
- emit changed();
- }
- return true;
-}
-
-void LegacyModList::directoryChanged(QString path)
-{
- update();
-}
-
-LegacyModList::OrderList LegacyModList::readListFile()
-{
- OrderList itemList;
- if (m_list_file.isNull() || m_list_file.isEmpty())
- return itemList;
-
- QFile textFile(m_list_file);
- if (!textFile.open(QIODevice::ReadOnly | QIODevice::Text))
- return OrderList();
-
- QTextStream textStream;
- textStream.setAutoDetectUnicode(true);
- textStream.setDevice(&textFile);
- while (true)
- {
- QString line = textStream.readLine();
- if (line.isNull() || line.isEmpty())
- break;
- else
- {
- OrderItem it;
- it.enabled = !line.endsWith(".disabled");
- if (!it.enabled)
- {
- line.chop(9);
- }
- it.id = line;
- itemList.append(it);
- }
- }
- textFile.close();
- return itemList;
-}
-
-bool LegacyModList::saveListFile()
-{
- if (m_list_file.isNull() || m_list_file.isEmpty())
- return false;
- QFile textFile(m_list_file);
- if (!textFile.open(QIODevice::WriteOnly | QIODevice::Text | QIODevice::Truncate))
- return false;
- QTextStream textStream;
- textStream.setGenerateByteOrderMark(true);
- textStream.setCodec("UTF-8");
- textStream.setDevice(&textFile);
- for (auto mod : mods)
- {
- textStream << mod.mmc_id();
- if (!mod.enabled())
- textStream << ".disabled";
- textStream << endl;
- }
- textFile.close();
- return false;
-}
-
-bool LegacyModList::isValid()
-{
- return m_dir.exists() && m_dir.isReadable();
-}
-
-bool LegacyModList::installMod(const QString &filename, int index)
-{
- // NOTE: fix for GH-1178: remove trailing slash to avoid issues with using the empty result of QFileInfo::fileName
- QFileInfo fileinfo(FS::NormalizePath(filename));
-
- qDebug() << "installing: " << fileinfo.absoluteFilePath();
-
- if (!fileinfo.exists() || !fileinfo.isReadable() || index < 0)
- {
- return false;
- }
- Mod m(fileinfo);
- if (!m.valid())
- return false;
-
- // if it's already there, replace the original mod (in place)
- int idx = mods.indexOf(m);
- if (idx != -1)
- {
- int idx2 = mods.indexOf(m, idx + 1);
- if (idx2 != -1)
- return false;
- if (mods[idx].replace(m))
- {
-
- auto left = this->index(index);
- auto right = this->index(index, columnCount(QModelIndex()) - 1);
- emit dataChanged(left, right);
- saveListFile();
- update();
- return true;
- }
- return false;
- }
-
- auto type = m.type();
- if (type == Mod::MOD_UNKNOWN)
- return false;
- if (type == Mod::MOD_SINGLEFILE || type == Mod::MOD_ZIPFILE || type == Mod::MOD_LITEMOD)
- {
- QString newpath = FS::PathCombine(m_dir.path(), fileinfo.fileName());
- if (!QFile::copy(fileinfo.filePath(), newpath))
- return false;
- m.repath(newpath);
- beginInsertRows(QModelIndex(), index, index);
- mods.insert(index, m);
- endInsertRows();
- saveListFile();
- update();
- return true;
- }
- else if (type == Mod::MOD_FOLDER)
- {
-
- QString from = fileinfo.filePath();
- QString to = FS::PathCombine(m_dir.path(), fileinfo.fileName());
- if (!FS::copy(from, to)())
- return false;
- m.repath(to);
- beginInsertRows(QModelIndex(), index, index);
- mods.insert(index, m);
- endInsertRows();
- saveListFile();
- update();
- return true;
}
- return false;
-}
-
-bool LegacyModList::deleteMod(int index)
-{
- if (index >= mods.size() || index < 0)
- return false;
- Mod &m = mods[index];
- if (m.destroy())
- {
- beginRemoveRows(QModelIndex(), index, index);
- mods.removeAt(index);
- endRemoveRows();
- saveListFile();
- emit changed();
- return true;
- }
- return false;
-}
-
-bool LegacyModList::deleteMods(int first, int last)
-{
- for (int i = first; i <= last; i++)
- {
- Mod &m = mods[i];
- m.destroy();
- }
- beginRemoveRows(QModelIndex(), first, last);
- mods.erase(mods.begin() + first, mods.begin() + last + 1);
- endRemoveRows();
- saveListFile();
- emit changed();
- return true;
-}
-
-bool LegacyModList::moveModTo(int from, int to)
-{
- if (from < 0 || from >= mods.size())
- return false;
- if (to >= rowCount())
- to = rowCount() - 1;
- if (to == -1)
- to = rowCount() - 1;
- if (from == to)
- return false;
- int togap = to > from ? to + 1 : to;
- beginMoveRows(QModelIndex(), from, from, QModelIndex(), togap);
- mods.move(from, to);
- endMoveRows();
- saveListFile();
- emit changed();
- return true;
-}
-
-bool LegacyModList::moveModUp(int from)
-{
- if (from > 0)
- return moveModTo(from, from - 1);
- return false;
-}
-
-bool LegacyModList::moveModsUp(int first, int last)
-{
- if (first == 0)
- return false;
-
- beginMoveRows(QModelIndex(), first, last, QModelIndex(), first - 1);
- mods.move(first - 1, last);
- endMoveRows();
- saveListFile();
- emit changed();
return true;
}
-
-bool LegacyModList::moveModDown(int from)
-{
- if (from < 0)
- return false;
- if (from < mods.size() - 1)
- return moveModTo(from, from + 1);
- return false;
-}
-
-bool LegacyModList::moveModsDown(int first, int last)
-{
- if (last == mods.size() - 1)
- return false;
-
- beginMoveRows(QModelIndex(), first, last, QModelIndex(), last + 2);
- mods.move(last + 1, first);
- endMoveRows();
- saveListFile();
- emit changed();
- return true;
-}
-
-int LegacyModList::columnCount(const QModelIndex &parent) const
-{
- return 3;
-}
-
-QVariant LegacyModList::data(const QModelIndex &index, int role) const
-{
- if (!index.isValid())
- return QVariant();
-
- int row = index.row();
- int column = index.column();
-
- if (row < 0 || row >= mods.size())
- return QVariant();
-
- switch (role)
- {
- case Qt::DisplayRole:
- switch (column)
- {
- case NameColumn:
- return mods[row].name();
- case VersionColumn:
- return mods[row].version();
-
- default:
- return QVariant();
- }
-
- case Qt::ToolTipRole:
- return mods[row].mmc_id();
-
- case Qt::CheckStateRole:
- switch (column)
- {
- case ActiveColumn:
- return mods[row].enabled() ? Qt::Checked : Qt::Unchecked;
- default:
- return QVariant();
- }
- default:
- return QVariant();
- }
-}
-
-bool LegacyModList::setData(const QModelIndex &index, const QVariant &value, int role)
-{
- if (index.row() < 0 || index.row() >= rowCount(index) || !index.isValid())
- {
- return false;
- }
-
- if (role == Qt::CheckStateRole)
- {
- auto &mod = mods[index.row()];
- if (mod.enable(!mod.enabled()))
- {
- emit dataChanged(index, index);
- return true;
- }
- }
- return false;
-}
-
-QVariant LegacyModList::headerData(int section, Qt::Orientation orientation, int role) const
-{
- switch (role)
- {
- case Qt::DisplayRole:
- switch (section)
- {
- case ActiveColumn:
- return QString();
- case NameColumn:
- return tr("Name");
- case VersionColumn:
- return tr("Version");
- default:
- return QVariant();
- }
-
- case Qt::ToolTipRole:
- switch (section)
- {
- case ActiveColumn:
- return tr("Is the mod enabled?");
- case NameColumn:
- return tr("The name of the mod.");
- case VersionColumn:
- return tr("The version of the mod.");
- default:
- return QVariant();
- }
- default:
- return QVariant();
- }
- return QVariant();
-}
-
-Qt::ItemFlags LegacyModList::flags(const QModelIndex &index) const
-{
- Qt::ItemFlags defaultFlags = QAbstractListModel::flags(index);
- if (index.isValid())
- return Qt::ItemIsUserCheckable | Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled |
- defaultFlags;
- else
- return Qt::ItemIsDropEnabled | defaultFlags;
-}
-
-QStringList LegacyModList::mimeTypes() const
-{
- QStringList types;
- types << "text/uri-list";
- types << "text/plain";
- return types;
-}
-
-Qt::DropActions LegacyModList::supportedDropActions() const
-{
- // copy from outside, move from within and other mod lists
- return Qt::CopyAction | Qt::MoveAction;
-}
-
-Qt::DropActions LegacyModList::supportedDragActions() const
-{
- // move to other mod lists or VOID
- return Qt::MoveAction;
-}
-
-QMimeData *LegacyModList::mimeData(const QModelIndexList &indexes) const
-{
- QMimeData *data = new QMimeData();
-
- if (indexes.size() == 0)
- return data;
-
- auto idx = indexes[0];
- int row = idx.row();
- if (row < 0 || row >= mods.size())
- return data;
-
- QStringList params;
- params << m_list_id << QString::number(row);
- data->setText(params.join('|'));
- return data;
-}
-
-bool LegacyModList::dropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column,
- const QModelIndex &parent)
-{
- if (action == Qt::IgnoreAction)
- return true;
- // check if the action is supported
- if (!data || !(action & supportedDropActions()))
- return false;
- if (parent.isValid())
- {
- row = parent.row();
- column = parent.column();
- }
-
- if (row > rowCount())
- row = rowCount();
- if (row == -1)
- row = rowCount();
- if (column == -1)
- column = 0;
- qDebug() << "Drop row: " << row << " column: " << column;
-
- // files dropped from outside?
- if (data->hasUrls())
- {
- bool was_watching = is_watching;
- if (was_watching)
- stopWatching();
- auto urls = data->urls();
- for (auto url : urls)
- {
- // only local files may be dropped...
- if (!url.isLocalFile())
- continue;
- QString filename = url.toLocalFile();
- installMod(filename, row);
- // if there is no ordering, re-sort the list
- if (m_list_file.isEmpty())
- {
- beginResetModel();
- internalSort(mods);
- endResetModel();
- }
- }
- if (was_watching)
- startWatching();
- return true;
- }
- else if (data->hasText())
- {
- QString sourcestr = data->text();
- auto list = sourcestr.split('|');
- if (list.size() != 2)
- return false;
- QString remoteId = list[0];
- int remoteIndex = list[1].toInt();
- qDebug() << "move: " << sourcestr;
- // no moving of things between two lists
- if (remoteId != m_list_id)
- return false;
- // no point moving to the same place...
- if (row == remoteIndex)
- return false;
- // otherwise, move the mod :D
- moveModTo(remoteIndex, row);
- return true;
- }
- return false;
-}
diff --git a/api/logic/minecraft/legacy/LegacyModList.h b/api/logic/minecraft/legacy/LegacyModList.h
index d1bd0e8b..19b191a7 100644
--- a/api/logic/minecraft/legacy/LegacyModList.h
+++ b/api/logic/minecraft/legacy/LegacyModList.h
@@ -1,4 +1,4 @@
-/* Copyright 2013-2017 MultiMC Contributors
+/* Copyright 2013-2018 MultiMC Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -18,7 +18,6 @@
#include <QList>
#include <QString>
#include <QDir>
-#include <QAbstractListModel>
#include "minecraft/Mod.h"
@@ -26,102 +25,19 @@
class LegacyInstance;
class BaseInstance;
-class QFileSystemWatcher;
/**
* A legacy mod list.
* Backed by a folder.
*/
-class MULTIMC_LOGIC_EXPORT LegacyModList : public QAbstractListModel
+class MULTIMC_LOGIC_EXPORT LegacyModList
{
- Q_OBJECT
public:
- enum Columns
- {
- ActiveColumn = 0,
- NameColumn,
- VersionColumn
- };
- LegacyModList(const QString &dir, const QString &list_file = QString());
- virtual QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const;
- virtual bool setData(const QModelIndex &index, const QVariant &value,
- int role = Qt::EditRole);
-
- virtual int rowCount(const QModelIndex &parent = QModelIndex()) const
- {
- return size();
- }
- ;
- virtual QVariant headerData(int section, Qt::Orientation orientation,
- int role = Qt::DisplayRole) const;
- virtual int columnCount(const QModelIndex &parent) const;
-
- size_t size() const
- {
- return mods.size();
- }
- ;
- bool empty() const
- {
- return size() == 0;
- }
- Mod &operator[](size_t index)
- {
- return mods[index];
- }
+ LegacyModList(const QString &dir, const QString &list_file = QString());
/// Reloads the mod list and returns true if the list changed.
- virtual bool update();
-
- /**
- * Adds the given mod to the list at the given index - if the list supports custom ordering
- */
- virtual bool installMod(const QString & filename, int index = 0);
-
- /// Deletes the mod at the given index.
- virtual bool deleteMod(int index);
-
- /// Deletes all the selected mods
- virtual bool deleteMods(int first, int last);
-
- /**
- * move the mod at index to the position N
- * 0 is the beginning of the list, length() is the end of the list.
- */
- virtual bool moveModTo(int from, int to);
-
- /**
- * move the mod at index one position upwards
- */
- virtual bool moveModUp(int from);
- virtual bool moveModsUp(int first, int last);
-
- /**
- * move the mod at index one position downwards
- */
- virtual bool moveModDown(int from);
- virtual bool moveModsDown(int first, int last);
-
- /// flags, mostly to support drag&drop
- virtual Qt::ItemFlags flags(const QModelIndex &index) const;
- /// get data for drag action
- virtual QMimeData *mimeData(const QModelIndexList &indexes) const;
- /// get the supported mime types
- virtual QStringList mimeTypes() const;
- /// process data from drop action
- virtual bool dropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column,
- const QModelIndex &parent);
- /// what drag actions do we support?
- virtual Qt::DropActions supportedDragActions() const;
-
- /// what drop actions do we support?
- virtual Qt::DropActions supportedDropActions() const;
-
- void startWatching();
- void stopWatching();
-
- virtual bool isValid();
+ bool update();
QDir dir()
{
@@ -133,28 +49,8 @@ public:
return mods;
}
-private:
- void internalSort(QList<Mod> & what);
- struct OrderItem
- {
- QString id;
- bool enabled = false;
- };
- typedef QList<OrderItem> OrderList;
- OrderList readListFile();
- bool saveListFile();
-private
-slots:
- void directoryChanged(QString path);
-
-signals:
- void changed();
-
protected:
- QFileSystemWatcher *m_watcher;
- bool is_watching;
QDir m_dir;
QString m_list_file;
- QString m_list_id;
QList<Mod> mods;
};
diff --git a/api/logic/minecraft/legacy/LegacyUpdate.cpp b/api/logic/minecraft/legacy/LegacyUpdate.cpp
deleted file mode 100644
index e263d0de..00000000
--- a/api/logic/minecraft/legacy/LegacyUpdate.cpp
+++ /dev/null
@@ -1,399 +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 <QStringList>
-#include <quazip.h>
-#include <quazipfile.h>
-#include <QDebug>
-
-#include "Env.h"
-#include "BaseInstance.h"
-#include "net/URLConstants.h"
-#include "MMCZip.h"
-
-#include "LegacyUpdate.h"
-#include "LegacyModList.h"
-
-#include "LwjglVersionList.h"
-#include "LegacyInstance.h"
-#include <FileSystem.h>
-
-LegacyUpdate::LegacyUpdate(BaseInstance *inst, QObject *parent) : Task(parent), m_inst(inst)
-{
-}
-
-void LegacyUpdate::executeTask()
-{
- fmllibsStart();
-}
-
-void LegacyUpdate::fmllibsStart()
-{
- // Get the mod list
- LegacyInstance *inst = (LegacyInstance *)m_inst;
- auto modList = inst->jarModList();
-
- bool forge_present = false;
-
- QString version = inst->intendedVersionId();
- auto & fmlLibsMapping = g_VersionFilterData.fmlLibsMapping;
- if (!fmlLibsMapping.contains(version))
- {
- lwjglStart();
- return;
- }
-
- auto &libList = fmlLibsMapping[version];
-
- // determine if we need some libs for FML or forge
- setStatus(tr("Checking for FML libraries..."));
- for (unsigned i = 0; i < modList->size(); i++)
- {
- auto &mod = modList->operator[](i);
-
- // do not use disabled mods.
- if (!mod.enabled())
- continue;
-
- if (mod.type() != Mod::MOD_ZIPFILE)
- continue;
-
- if (mod.mmc_id().contains("forge", Qt::CaseInsensitive))
- {
- forge_present = true;
- break;
- }
- if (mod.mmc_id().contains("fml", Qt::CaseInsensitive))
- {
- forge_present = true;
- break;
- }
- }
- // we don't...
- if (!forge_present)
- {
- lwjglStart();
- return;
- }
-
- // now check the lib folder inside the instance for files.
- for (auto &lib : libList)
- {
- QFileInfo libInfo(FS::PathCombine(inst->libDir(), lib.filename));
- if (libInfo.exists())
- continue;
- fmlLibsToProcess.append(lib);
- }
-
- // if everything is in place, there's nothing to do here...
- if (fmlLibsToProcess.isEmpty())
- {
- lwjglStart();
- return;
- }
-
- // download missing libs to our place
- setStatus(tr("Dowloading FML libraries..."));
- auto dljob = new NetJob("FML libraries");
- auto metacache = ENV.metacache();
- for (auto &lib : fmlLibsToProcess)
- {
- auto entry = metacache->resolveEntry("fmllibs", lib.filename);
- QString urlString = lib.ours ? URLConstants::FMLLIBS_OUR_BASE_URL + lib.filename
- : URLConstants::FMLLIBS_FORGE_BASE_URL + lib.filename;
- dljob->addNetAction(Net::Download::makeCached(QUrl(urlString), entry));
- }
-
- connect(dljob, &NetJob::succeeded, this, &LegacyUpdate::fmllibsFinished);
- connect(dljob, &NetJob::failed, this, &LegacyUpdate::fmllibsFailed);
- connect(dljob, &NetJob::progress, this, &LegacyUpdate::progress);
- legacyDownloadJob.reset(dljob);
- legacyDownloadJob->start();
-}
-
-void LegacyUpdate::fmllibsFinished()
-{
- legacyDownloadJob.reset();
- if(!fmlLibsToProcess.isEmpty())
- {
- setStatus(tr("Copying FML libraries into the instance..."));
- LegacyInstance *inst = (LegacyInstance *)m_inst;
- auto metacache = ENV.metacache();
- int index = 0;
- for (auto &lib : fmlLibsToProcess)
- {
- progress(index, fmlLibsToProcess.size());
- auto entry = metacache->resolveEntry("fmllibs", lib.filename);
- auto path = FS::PathCombine(inst->libDir(), lib.filename);
- if(!FS::ensureFilePathExists(path))
- {
- emitFailed(tr("Failed creating FML library folder inside the instance."));
- return;
- }
- if (!QFile::copy(entry->getFullPath(), FS::PathCombine(inst->libDir(), lib.filename)))
- {
- emitFailed(tr("Failed copying Forge/FML library: %1.").arg(lib.filename));
- return;
- }
- index++;
- }
- progress(index, fmlLibsToProcess.size());
- }
- lwjglStart();
-}
-
-void LegacyUpdate::fmllibsFailed(QString reason)
-{
- emitFailed(tr("Game update failed: it was impossible to fetch the required FML libraries. Reason: %1").arg(reason));
- return;
-}
-
-void LegacyUpdate::lwjglStart()
-{
- LegacyInstance *inst = (LegacyInstance *)m_inst;
-
- auto list = std::dynamic_pointer_cast<LWJGLVersionList>(ENV.getVersionList("org.lwjgl.legacy"));
- if (!list->isLoaded())
- {
- setStatus(tr("Checking the LWJGL version list..."));
- list->loadList();
- auto task = list->getLoadTask();
- connect(task.get(), &Task::succeeded, this, &LegacyUpdate::lwjglStart);
- connect(task.get(), &Task::failed, this, [&](const QString & error)
- {
- emitFailed(tr("Failed to refresh LWJGL list: %1.").arg(error));
- });
- return;
- }
-
- lwjglVersion = inst->lwjglVersion();
- lwjglTargetPath = FS::PathCombine(inst->lwjglFolder(), lwjglVersion);
- lwjglNativesPath = FS::PathCombine(lwjglTargetPath, "natives");
-
- // if the 'done' file exists, we don't have to download this again
- QFileInfo doneFile(FS::PathCombine(lwjglTargetPath, "done"));
- if (doneFile.exists())
- {
- jarStart();
- return;
- }
-
- setStatus(tr("Downloading new LWJGL..."));
- auto version = std::dynamic_pointer_cast<LWJGLVersion>(list->findVersion(lwjglVersion));
- if (!version)
- {
- emitFailed(QString("Game update failed: the selected LWJGL version is invalid: %1").arg(lwjglVersion));
- return;
- }
-
- QString url = version->url();
- QUrl realUrl(url);
- QString hostname = realUrl.host();
- auto worker = &ENV.qnam();
- QNetworkRequest req(realUrl);
- req.setRawHeader("Host", hostname.toLatin1());
- req.setHeader(QNetworkRequest::UserAgentHeader, "MultiMC/5.0 (Cached)");
- QNetworkReply *rep = worker->get(req);
-
- m_reply = std::shared_ptr<QNetworkReply>(rep);
- connect(rep, &QNetworkReply::downloadProgress, this, &LegacyUpdate::progress);
- connect(worker, &QNetworkAccessManager::finished, this, &LegacyUpdate::lwjglFinished);
-}
-
-void LegacyUpdate::lwjglFinished(QNetworkReply *reply)
-{
- if (m_reply.get() != reply)
- {
- return;
- }
- if (reply->error() != QNetworkReply::NoError)
- {
- emitFailed("Failed to download: " + reply->errorString() +
- "\nSometimes you have to wait a bit if you download many LWJGL versions in "
- "a row. YMMV");
- return;
- }
- auto worker = &ENV.qnam();
- // Here i check if there is a cookie for me in the reply and extract it
- QList<QNetworkCookie> cookies =
- qvariant_cast<QList<QNetworkCookie>>(reply->header(QNetworkRequest::SetCookieHeader));
- if (cookies.count() != 0)
- {
- // you must tell which cookie goes with which url
- worker->cookieJar()->setCookiesFromUrl(cookies, QUrl("sourceforge.net"));
- }
-
- // here you can check for the 302 or whatever other header i need
- QVariant newLoc = reply->header(QNetworkRequest::LocationHeader);
- if (newLoc.isValid())
- {
- QString redirectedTo = reply->header(QNetworkRequest::LocationHeader).toString();
- QUrl realUrl(redirectedTo);
- QString hostname = realUrl.host();
- QNetworkRequest req(redirectedTo);
- req.setRawHeader("Host", hostname.toLatin1());
- req.setHeader(QNetworkRequest::UserAgentHeader, "MultiMC/5.0 (Cached)");
- QNetworkReply *rep = worker->get(req);
- connect(rep, &QNetworkReply::downloadProgress, this, &LegacyUpdate::progress);
- m_reply = std::shared_ptr<QNetworkReply>(rep);
- return;
- }
- QFile saveMe("lwjgl.zip");
- saveMe.open(QIODevice::WriteOnly);
- saveMe.write(m_reply->readAll());
- saveMe.close();
- setStatus(tr("Installing new LWJGL..."));
- extractLwjgl();
- jarStart();
-}
-void LegacyUpdate::extractLwjgl()
-{
- // make sure the directories are there
-
- bool success = FS::ensureFolderPathExists(lwjglNativesPath);
-
- if (!success)
- {
- emitFailed("Failed to extract the lwjgl libs - error when creating required folders.");
- return;
- }
-
- QuaZip zip("lwjgl.zip");
- if (!zip.open(QuaZip::mdUnzip))
- {
- emitFailed("Failed to extract the lwjgl libs - not a valid archive.");
- return;
- }
-
- // and now we are going to access files inside it
- QuaZipFile file(&zip);
- const QString jarNames[] = {"jinput.jar", "lwjgl_util.jar", "lwjgl.jar"};
- for (bool more = zip.goToFirstFile(); more; more = zip.goToNextFile())
- {
- if (!file.open(QIODevice::ReadOnly))
- {
- zip.close();
- emitFailed("Failed to extract the lwjgl libs - error while reading archive.");
- return;
- }
- QuaZipFileInfo info;
- QString name = file.getActualFileName();
- if (name.endsWith('/'))
- {
- file.close();
- continue;
- }
- QString destFileName;
- // Look for the jars
- for (int i = 0; i < 3; i++)
- {
- if (name.endsWith(jarNames[i]))
- {
- destFileName = FS::PathCombine(lwjglTargetPath, jarNames[i]);
- }
- }
- // Not found? look for the natives
- if (destFileName.isEmpty())
- {
-#ifdef Q_OS_WIN32
- QString nativesDir = "windows";
-#else
-#ifdef Q_OS_MAC
- QString nativesDir = "macosx";
-#else
- QString nativesDir = "linux";
-#endif
-#endif
- if (name.contains(nativesDir))
- {
- int lastSlash = name.lastIndexOf('/');
- int lastBackSlash = name.lastIndexOf('\\');
- if (lastSlash != -1)
- name = name.mid(lastSlash + 1);
- else if (lastBackSlash != -1)
- name = name.mid(lastBackSlash + 1);
- destFileName = FS::PathCombine(lwjglNativesPath, name);
- }
- }
- // Now if destFileName is still empty, go to the next file.
- if (!destFileName.isEmpty())
- {
- setStatus(tr("Installing new LWJGL - extracting ") + name + "...");
- QFile output(destFileName);
- output.open(QIODevice::WriteOnly);
- output.write(file.readAll());
- output.close();
- }
- file.close(); // do not forget to close!
- }
- zip.close();
- m_reply.reset();
- QFile doneFile(FS::PathCombine(lwjglTargetPath, "done"));
- doneFile.open(QIODevice::WriteOnly);
- doneFile.write("done.");
- doneFile.close();
-}
-
-void LegacyUpdate::lwjglFailed(QString reason)
-{
- emitFailed(tr("Bad stuff happened while trying to get the lwjgl libs: %1").arg(reason));
-}
-
-void LegacyUpdate::jarStart()
-{
- LegacyInstance *inst = (LegacyInstance *)m_inst;
- if (!inst->shouldUpdate() || inst->shouldUseCustomBaseJar())
- {
- emitSucceeded();
- return;
- }
-
- setStatus(tr("Checking for jar updates..."));
- // Make directories
- QDir binDir(inst->binRoot());
- if (!binDir.exists() && !binDir.mkpath("."))
- {
- emitFailed("Failed to create bin folder.");
- return;
- }
-
- // Build a list of URLs that will need to be downloaded.
- setStatus(tr("Downloading new minecraft.jar ..."));
-
- QString version_id = inst->intendedVersionId();
-
- auto dljob = new NetJob("Minecraft.jar for version " + version_id);
-
- auto metacache = ENV.metacache();
- auto entry = metacache->resolveEntry("versions", URLConstants::getJarPath(version_id));
- dljob->addNetAction(Net::Download::makeCached(QUrl(URLConstants::getLegacyJarUrl(version_id)), entry));
- connect(dljob, SIGNAL(succeeded()), SLOT(jarFinished()));
- connect(dljob, SIGNAL(failed(QString)), SLOT(jarFailed(QString)));
- connect(dljob, SIGNAL(progress(qint64, qint64)), SIGNAL(progress(qint64, qint64)));
- legacyDownloadJob.reset(dljob);
- legacyDownloadJob->start();
-}
-
-void LegacyUpdate::jarFinished()
-{
- // process the jar
- emitSucceeded();
-}
-
-void LegacyUpdate::jarFailed(QString reason)
-{
- // bad, bad
- emitFailed(tr("Failed to download the minecraft jar: %1.").arg(reason));
-}
diff --git a/api/logic/minecraft/legacy/LegacyUpdate.h b/api/logic/minecraft/legacy/LegacyUpdate.h
deleted file mode 100644
index caab978e..00000000
--- a/api/logic/minecraft/legacy/LegacyUpdate.h
+++ /dev/null
@@ -1,70 +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 <QUrl>
-
-#include "net/NetJob.h"
-#include "tasks/Task.h"
-#include "minecraft/VersionFilterData.h"
-
-class MinecraftVersion;
-class BaseInstance;
-class QuaZip;
-class Mod;
-
-class LegacyUpdate : public Task
-{
- Q_OBJECT
-public:
- explicit LegacyUpdate(BaseInstance *inst, QObject *parent = 0);
- virtual void executeTask();
-
-private
-slots:
- void lwjglStart();
- void lwjglFinished(QNetworkReply *);
- void lwjglFailed(QString reason);
-
- void jarStart();
- void jarFinished();
- void jarFailed(QString reason);
-
- void fmllibsStart();
- void fmllibsFinished();
- void fmllibsFailed(QString reason);
-
- void extractLwjgl();
-
-private:
-
- std::shared_ptr<QNetworkReply> m_reply;
-
- // target version, determined during this task
- // MinecraftVersion *targetVersion;
- QString lwjglURL;
- QString lwjglVersion;
-
- QString lwjglTargetPath;
- QString lwjglNativesPath;
-
-private:
- NetJobPtr legacyDownloadJob;
- BaseInstance *m_inst = nullptr;
- QList<FMLlib> fmlLibsToProcess;
-};
diff --git a/api/logic/minecraft/legacy/LegacyUpgradeTask.cpp b/api/logic/minecraft/legacy/LegacyUpgradeTask.cpp
new file mode 100644
index 00000000..6cda3e4d
--- /dev/null
+++ b/api/logic/minecraft/legacy/LegacyUpgradeTask.cpp
@@ -0,0 +1,142 @@
+#include "LegacyUpgradeTask.h"
+#include "BaseInstanceProvider.h"
+#include "settings/INISettingsObject.h"
+#include "FileSystem.h"
+#include "NullInstance.h"
+#include "pathmatcher/RegexpMatcher.h"
+#include <QtConcurrentRun>
+#include "LegacyInstance.h"
+#include "minecraft/MinecraftInstance.h"
+#include "minecraft/ComponentList.h"
+#include "classparser.h"
+
+LegacyUpgradeTask::LegacyUpgradeTask(SettingsObjectPtr settings, const QString & stagingPath, InstancePtr origInstance, const QString & newName)
+{
+ m_globalSettings = settings;
+ m_stagingPath = stagingPath;
+ m_origInstance = origInstance;
+ m_newName = newName;
+}
+
+void LegacyUpgradeTask::executeTask()
+{
+ setStatus(tr("Copying instance %1").arg(m_origInstance->name()));
+
+ FS::copy folderCopy(m_origInstance->instanceRoot(), m_stagingPath);
+ folderCopy.followSymlinks(true);
+
+ m_copyFuture = QtConcurrent::run(QThreadPool::globalInstance(), folderCopy);
+ connect(&m_copyFutureWatcher, &QFutureWatcher<bool>::finished, this, &LegacyUpgradeTask::copyFinished);
+ connect(&m_copyFutureWatcher, &QFutureWatcher<bool>::canceled, this, &LegacyUpgradeTask::copyAborted);
+ m_copyFutureWatcher.setFuture(m_copyFuture);
+}
+
+static QString decideVersion(const QString& currentVersion, const QString& intendedVersion)
+{
+ if(intendedVersion != currentVersion)
+ {
+ if(!intendedVersion.isEmpty())
+ {
+ return intendedVersion;
+ }
+ else if(!currentVersion.isEmpty())
+ {
+ return currentVersion;
+ }
+ }
+ else
+ {
+ if(!intendedVersion.isEmpty())
+ {
+ return intendedVersion;
+ }
+ }
+ return QString();
+}
+
+void LegacyUpgradeTask::copyFinished()
+{
+ auto successful = m_copyFuture.result();
+ if(!successful)
+ {
+ emitFailed(tr("Instance folder copy failed."));
+ return;
+ }
+ auto legacyInst = std::dynamic_pointer_cast<LegacyInstance>(m_origInstance);
+
+ auto instanceSettings = std::make_shared<INISettingsObject>(FS::PathCombine(m_stagingPath, "instance.cfg"));
+ instanceSettings->registerSetting("InstanceType", "Legacy");
+ instanceSettings->set("InstanceType", "OneSix");
+ // NOTE: this scope ensures the instance is fully saved before we emitSucceeded
+ {
+ MinecraftInstance inst(m_globalSettings, instanceSettings, m_stagingPath);
+ inst.setName(m_newName);
+ inst.init();
+
+ QString preferredVersionNumber = decideVersion(legacyInst->currentVersionId(), legacyInst->intendedVersionId());
+ if(preferredVersionNumber.isNull())
+ {
+ // try to decide version based on the jar(s?)
+ preferredVersionNumber = classparser::GetMinecraftJarVersion(legacyInst->baseJar());
+ if(preferredVersionNumber.isNull())
+ {
+ preferredVersionNumber = classparser::GetMinecraftJarVersion(legacyInst->runnableJar());
+ if(preferredVersionNumber.isNull())
+ {
+ emitFailed(tr("Could not decide Minecraft version."));
+ return;
+ }
+ }
+ }
+ auto components = inst.getComponentList();
+ components->buildingFromScratch();
+ components->setComponentVersion("net.minecraft", preferredVersionNumber, true);
+
+ if(legacyInst->shouldUseCustomBaseJar())
+ {
+ QString jarPath = legacyInst->customBaseJar();
+ qDebug() << "Base jar is custom! : " << jarPath;
+ // FIXME: handle case when the jar is unreadable?
+ // TODO: check the hash, if it's the same as the upstream jar, do not do this
+ components->installCustomJar(jarPath);
+ }
+
+ auto jarMods = legacyInst->getJarMods();
+ for(auto & jarMod: jarMods)
+ {
+ QString modPath = jarMod.filename().absoluteFilePath();
+ qDebug() << "jarMod: " << modPath;
+ components->installJarMods({modPath});
+ }
+
+ // remove all the extra garbage we no longer need
+ auto removeAll = [&](const QString &root, const QStringList &things)
+ {
+ for(auto &thing : things)
+ {
+ auto removePath = FS::PathCombine(root, thing);
+ QFileInfo stat(removePath);
+ if(stat.isDir())
+ {
+ FS::deletePath(removePath);
+ }
+ else
+ {
+ QFile::remove(removePath);
+ }
+ }
+ };
+ QStringList rootRemovables = {"modlist", "version", "instMods"};
+ QStringList mcRemovables = {"bin", "MultiMCLauncher.jar", "icon.png"};
+ removeAll(inst.instanceRoot(), rootRemovables);
+ removeAll(inst.minecraftRoot(), mcRemovables);
+ }
+ emitSucceeded();
+}
+
+void LegacyUpgradeTask::copyAborted()
+{
+ emitFailed(tr("Instance folder copy has been aborted."));
+ return;
+}
+
diff --git a/api/logic/minecraft/legacy/LegacyUpgradeTask.h b/api/logic/minecraft/legacy/LegacyUpgradeTask.h
new file mode 100644
index 00000000..56896385
--- /dev/null
+++ b/api/logic/minecraft/legacy/LegacyUpgradeTask.h
@@ -0,0 +1,38 @@
+#pragma once
+
+#include "tasks/Task.h"
+#include "multimc_logic_export.h"
+#include "net/NetJob.h"
+#include <QUrl>
+#include <QFuture>
+#include <QFutureWatcher>
+#include "settings/SettingsObject.h"
+#include "BaseVersion.h"
+#include "BaseInstance.h"
+
+
+class BaseInstanceProvider;
+
+class MULTIMC_LOGIC_EXPORT LegacyUpgradeTask : public Task
+{
+ Q_OBJECT
+public:
+ explicit LegacyUpgradeTask(SettingsObjectPtr settings, const QString & stagingPath, InstancePtr origInstance, const QString & newName);
+
+protected:
+ //! Entry point for tasks.
+ virtual void executeTask() override;
+ void copyFinished();
+ void copyAborted();
+
+private: /* data */
+ SettingsObjectPtr m_globalSettings;
+ InstancePtr m_origInstance;
+ QString m_stagingPath;
+ QString m_newName;
+ QFuture<bool> m_copyFuture;
+ QFutureWatcher<bool> m_copyFutureWatcher;
+};
+
+
+
diff --git a/api/logic/minecraft/legacy/LwjglVersionList.cpp b/api/logic/minecraft/legacy/LwjglVersionList.cpp
deleted file mode 100644
index 3d7ad2d4..00000000
--- a/api/logic/minecraft/legacy/LwjglVersionList.cpp
+++ /dev/null
@@ -1,169 +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 "LwjglVersionList.h"
-#include "Env.h"
-
-#include <QtNetwork>
-#include <QtXml>
-#include <QRegExp>
-
-#include <QDebug>
-
-#define RSS_URL "https://sourceforge.net/projects/java-game-lib/rss"
-
-LWJGLVersionList::LWJGLVersionList(QObject *parent) : BaseVersionList(parent)
-{
-}
-
-QVariant LWJGLVersionList::data(const QModelIndex &index, int role) const
-{
- if (!index.isValid())
- return QVariant();
-
- if (index.row() > count())
- return QVariant();
-
- const PtrLWJGLVersion version = m_vlist.at(index.row());
-
- switch (role)
- {
- case Qt::DisplayRole:
- return version->name();
-
- case Qt::ToolTipRole:
- return version->url();
-
- default:
- return QVariant();
- }
-}
-
-QVariant LWJGLVersionList::headerData(int section, Qt::Orientation orientation, int role) const
-{
- switch (role)
- {
- case Qt::DisplayRole:
- return tr("Version");
-
- case Qt::ToolTipRole:
- return tr("LWJGL version name.");
-
- default:
- return QVariant();
- }
-}
-
-int LWJGLVersionList::columnCount(const QModelIndex &parent) const
-{
- return 1;
-}
-
-void LWJGLVersionList::loadList()
-{
- if(m_loading)
- {
- return;
- }
- m_loading = true;
-
- qDebug() << "Downloading LWJGL RSS...";
- m_rssDLJob.reset(new NetJob("LWJGL RSS"));
- m_rssDL = Net::Download::makeByteArray(QUrl(RSS_URL), &m_rssData);
- m_rssDLJob->addNetAction(m_rssDL);
- connect(m_rssDLJob.get(), &NetJob::failed, this, &LWJGLVersionList::rssFailed);
- connect(m_rssDLJob.get(), &NetJob::succeeded, this, &LWJGLVersionList::rssSucceeded);
- m_rssDLJob->start();
-}
-
-inline QDomElement getDomElementByTagName(QDomElement parent, QString tagname)
-{
- QDomNodeList elementList = parent.elementsByTagName(tagname);
- if (elementList.count())
- return elementList.at(0).toElement();
- else
- return QDomElement();
-}
-
-void LWJGLVersionList::rssFailed(const QString& reason)
-{
- m_rssDLJob.reset();
- m_loading = false;
- qWarning() << "Failed to load LWJGL list. Network error: " + reason;
-}
-
-void LWJGLVersionList::rssSucceeded()
-{
- QRegExp lwjglRegex("lwjgl-(([0-9]\\.?)+)\\.zip");
- Q_ASSERT_X(lwjglRegex.isValid(), "load LWJGL list", "LWJGL regex is invalid");
-
- QDomDocument doc;
-
- QString xmlErrorMsg;
- int errorLine;
-
- if (!doc.setContent(m_rssData, false, &xmlErrorMsg, &errorLine))
- {
- qWarning() << "Failed to load LWJGL list. XML error: " + xmlErrorMsg + " at line " + QString::number(errorLine);
- m_rssDLJob.reset();
- m_rssData.clear();
- m_loading = false;
- return;
- }
- m_rssData.clear();
-
- QDomNodeList items = doc.elementsByTagName("item");
-
- QList<PtrLWJGLVersion> tempList;
-
- for (int i = 0; i < items.length(); i++)
- {
- Q_ASSERT_X(items.at(i).isElement(), "load LWJGL list", "XML element isn't an element... wat?");
-
- QDomElement linkElement = getDomElementByTagName(items.at(i).toElement(), "link");
- if (linkElement.isNull())
- {
- qDebug() << "Link element" << i << "in RSS feed doesn't exist! Skipping.";
- continue;
- }
-
- QString link = linkElement.text();
-
- // Make sure it's a download link.
- if (link.endsWith("/download") && link.contains(lwjglRegex))
- {
- QString name = link.mid(lwjglRegex.indexIn(link) + 6);
- // Subtract 4 here to remove the .zip file extension.
- name = name.left(lwjglRegex.matchedLength() - 10);
-
- QUrl url(link);
- if (!url.isValid())
- {
- qWarning() << "LWJGL version URL isn't valid:" << link << "Skipping.";
- continue;
- }
- qDebug() << "Discovered LWGL version" << name << "at" << link;
- tempList.append(std::make_shared<LWJGLVersion>(name, link));
- }
- }
-
- beginResetModel();
- m_vlist.swap(tempList);
- endResetModel();
-
- qDebug() << "Loaded LWJGL list.";
- m_rssDLJob.reset();
- m_loading = false;
-}
diff --git a/api/logic/minecraft/legacy/LwjglVersionList.h b/api/logic/minecraft/legacy/LwjglVersionList.h
deleted file mode 100644
index f5312e2c..00000000
--- a/api/logic/minecraft/legacy/LwjglVersionList.h
+++ /dev/null
@@ -1,116 +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 <QAbstractListModel>
-#include <QUrl>
-#include <QNetworkReply>
-#include <memory>
-
-#include "BaseVersion.h"
-#include "BaseVersionList.h"
-
-#include "multimc_logic_export.h"
-#include <net/NetJob.h>
-
-class LWJGLVersion;
-typedef std::shared_ptr<LWJGLVersion> PtrLWJGLVersion;
-
-class MULTIMC_LOGIC_EXPORT LWJGLVersion : public BaseVersion
-{
-public:
- LWJGLVersion(const QString &name, const QString &url)
- : m_name(name), m_url(url)
- {
- }
-
- virtual QString descriptor()
- {
- return m_name;
- }
-
- virtual QString name()
- {
- return m_name;
- }
-
- virtual QString typeString() const
- {
- return QObject::tr("Upstream");
- }
-
- QString url() const
- {
- return m_url;
- }
-
-protected:
- QString m_name;
- QString m_url;
-};
-
-class MULTIMC_LOGIC_EXPORT LWJGLVersionList : public BaseVersionList
-{
- Q_OBJECT
-public:
- explicit LWJGLVersionList(QObject *parent = 0);
-
- bool isLoaded() override
- {
- return m_vlist.length() > 0;
- }
- virtual const BaseVersionPtr at(int i) const override
- {
- return m_vlist[i];
- }
-
- virtual shared_qobject_ptr<Task> getLoadTask() override
- {
- return m_rssDLJob;
- }
-
- virtual void sortVersions() override {};
-
- virtual void updateListData(QList< BaseVersionPtr > versions) override {};
-
- int count() const override
- {
- return m_vlist.length();
- }
-
- virtual QVariant data(const QModelIndex &index, int role) const override;
- virtual QVariant headerData(int section, Qt::Orientation orientation, int role) const override;
- virtual int rowCount(const QModelIndex &parent) const override
- {
- return count();
- }
- virtual int columnCount(const QModelIndex &parent) const override;
-
-public slots:
- virtual void loadList();
-
-private slots:
- void rssFailed(const QString & reason);
- void rssSucceeded();
-
-private:
- QList<PtrLWJGLVersion> m_vlist;
- Net::Download::Ptr m_rssDL;
- NetJobPtr m_rssDLJob;
- QByteArray m_rssData;
- bool m_loading = false;
-};