summaryrefslogtreecommitdiffstats
path: root/logic
diff options
context:
space:
mode:
authorPetr Mrázek <peterix@gmail.com>2014-02-09 20:49:48 +0100
committerPetr Mrázek <peterix@gmail.com>2014-02-09 20:49:48 +0100
commit1f6a484cb2368a5704cdb4820ac06194ea6d7e1a (patch)
treef4ebfd97c25387b3e26d4a55c5c85d67782df25d /logic
parentf8df07c3272c0e02f31f46fda8a429292c7a446a (diff)
parent18f532b0d7d873280ec17218196db15fa64175a2 (diff)
downloadMultiMC-1f6a484cb2368a5704cdb4820ac06194ea6d7e1a.tar
MultiMC-1f6a484cb2368a5704cdb4820ac06194ea6d7e1a.tar.gz
MultiMC-1f6a484cb2368a5704cdb4820ac06194ea6d7e1a.tar.lz
MultiMC-1f6a484cb2368a5704cdb4820ac06194ea6d7e1a.tar.xz
MultiMC-1f6a484cb2368a5704cdb4820ac06194ea6d7e1a.zip
Merge branch 'integration_derpstances_groupview' into develop
Diffstat (limited to 'logic')
-rw-r--r--logic/BaseInstaller.cpp66
-rw-r--r--logic/BaseInstaller.h39
-rw-r--r--logic/ForgeInstaller.cpp95
-rw-r--r--logic/ForgeInstaller.h10
-rw-r--r--logic/InstanceFactory.cpp10
-rw-r--r--logic/LiteLoaderInstaller.cpp101
-rw-r--r--logic/LiteLoaderInstaller.h20
-rw-r--r--logic/OneSixFTBInstance.cpp6
-rw-r--r--logic/OneSixInstance.cpp118
-rw-r--r--logic/OneSixInstance.h27
-rw-r--r--logic/OneSixInstance_p.h12
-rw-r--r--logic/OneSixLibrary.cpp38
-rw-r--r--logic/OneSixLibrary.h41
-rw-r--r--logic/OneSixRule.cpp4
-rw-r--r--logic/OneSixRule.h2
-rw-r--r--logic/OneSixUpdate.cpp4
-rw-r--r--logic/OneSixVersion.cpp355
-rw-r--r--logic/OneSixVersion.h63
-rw-r--r--logic/OneSixVersionBuilder.cpp1077
-rw-r--r--logic/OneSixVersionBuilder.h47
-rw-r--r--logic/lists/InstanceList.cpp116
-rw-r--r--logic/lists/InstanceList.h20
-rw-r--r--logic/lists/MinecraftVersionList.cpp10
-rw-r--r--logic/lists/MinecraftVersionList.h2
24 files changed, 1759 insertions, 524 deletions
diff --git a/logic/BaseInstaller.cpp b/logic/BaseInstaller.cpp
new file mode 100644
index 00000000..92aa0c92
--- /dev/null
+++ b/logic/BaseInstaller.cpp
@@ -0,0 +1,66 @@
+/* Copyright 2013 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 "BaseInstaller.h"
+
+#include <QFile>
+
+#include "OneSixVersion.h"
+#include "OneSixLibrary.h"
+#include "OneSixInstance.h"
+
+#include "cmdutils.h"
+
+BaseInstaller::BaseInstaller()
+{
+
+}
+
+bool BaseInstaller::isApplied(OneSixInstance *on)
+{
+ return QFile::exists(filename(on->instanceRoot()));
+}
+
+bool BaseInstaller::add(OneSixInstance *to)
+{
+ if (!patchesDir(to->instanceRoot()).exists())
+ {
+ QDir(to->instanceRoot()).mkdir("patches");
+ }
+
+ if (isApplied(to))
+ {
+ if (!remove(to))
+ {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+bool BaseInstaller::remove(OneSixInstance *from)
+{
+ return QFile::remove(filename(from->instanceRoot()));
+}
+
+QString BaseInstaller::filename(const QString &root) const
+{
+ return patchesDir(root).absoluteFilePath(id() + ".json");
+}
+QDir BaseInstaller::patchesDir(const QString &root) const
+{
+ return QDir(root + "/patches/");
+}
diff --git a/logic/BaseInstaller.h b/logic/BaseInstaller.h
new file mode 100644
index 00000000..df7eab89
--- /dev/null
+++ b/logic/BaseInstaller.h
@@ -0,0 +1,39 @@
+/* Copyright 2013 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 <memory>
+
+class OneSixInstance;
+class QDir;
+class QString;
+
+class BaseInstaller
+{
+public:
+ BaseInstaller();
+
+ virtual bool canApply(OneSixInstance *instance) const { return true; }
+ bool isApplied(OneSixInstance *on);
+
+ virtual bool add(OneSixInstance *to);
+ virtual bool remove(OneSixInstance *from);
+
+protected:
+ virtual QString id() const = 0;
+ QString filename(const QString &root) const;
+ QDir patchesDir(const QString &root) const;
+};
diff --git a/logic/ForgeInstaller.cpp b/logic/ForgeInstaller.cpp
index 8d4c5b41..3e18d17f 100644
--- a/logic/ForgeInstaller.cpp
+++ b/logic/ForgeInstaller.cpp
@@ -21,7 +21,15 @@
#include <quazipfile.h>
#include <pathutils.h>
#include <QStringList>
+#include <QRegularExpression>
+#include <QRegularExpressionMatch>
#include "MultiMC.h"
+#include "OneSixInstance.h"
+
+#include <QJsonDocument>
+#include <QJsonArray>
+#include <QSaveFile>
+#include <QCryptographicHash>
ForgeInstaller::ForgeInstaller(QString filename, QString universal_url)
{
@@ -66,6 +74,7 @@ ForgeInstaller::ForgeInstaller(QString filename, QString universal_url)
QJsonObject installObj = installVal.toObject();
QString libraryName = installObj.value("path").toString();
internalPath = installObj.value("filePath").toString();
+ m_forgeVersionString = installObj.value("version").toString().remove("Forge").trimmed();
// where do we put the library? decode the mojang path
OneSixLibrary lib(libraryName);
@@ -103,13 +112,22 @@ ForgeInstaller::ForgeInstaller(QString filename, QString universal_url)
realVersionId = m_forge_version->id = installObj.value("minecraft").toString();
}
-bool ForgeInstaller::apply(std::shared_ptr<OneSixVersion> to)
+bool ForgeInstaller::add(OneSixInstance *to)
{
+ if (!BaseInstaller::add(to))
+ {
+ return false;
+ }
+
+ QJsonObject obj;
+ obj.insert("order", 5);
+
if (!m_forge_version)
return false;
- to->externalUpdateStart();
int sliding_insert_window = 0;
{
+ QJsonArray librariesPlus;
+
// for each library in the version we are adding (except for the blacklisted)
QSet<QString> blacklist{"lwjgl", "lwjgl_util", "lwjgl-platform"};
for (auto lib : m_forge_version->libraries)
@@ -128,28 +146,83 @@ bool ForgeInstaller::apply(std::shared_ptr<OneSixVersion> to)
if (blacklist.contains(libName))
continue;
- // find an entry that matches this one
+ QJsonObject libObj = lib->toJson();
+
bool found = false;
- for (auto tolib : to->libraries)
+ bool equals = false;
+ // find an entry that matches this one
+ for (auto tolib : to->getVanillaVersion()->libraries)
{
if (tolib->name() != libName)
continue;
found = true;
+ if (tolib->toJson() == libObj)
+ {
+ equals = true;
+ }
// replace lib
- tolib = lib;
+ libObj.insert("insert", QString("replace"));
break;
}
+ if (equals)
+ {
+ continue;
+ }
if (!found)
{
// add lib
- to->libraries.insert(sliding_insert_window, lib);
+ libObj.insert("insert", QString("prepend"));
+ if (lib->name() == "minecraftforge")
+ {
+ libObj.insert("MMC-depend", QString("hard"));
+ }
sliding_insert_window++;
}
+ librariesPlus.prepend(libObj);
+ }
+ obj.insert("+libraries", librariesPlus);
+ obj.insert("mainClass", m_forge_version->mainClass);
+ QString args = m_forge_version->minecraftArguments;
+ QStringList tweakers;
+ {
+ QRegularExpression expression("--tweakClass ([a-zA-Z0-9\\.]*)");
+ QRegularExpressionMatch match = expression.match(args);
+ while (match.hasMatch())
+ {
+ tweakers.append(match.captured(1));
+ args.remove(match.capturedStart(), match.capturedLength());
+ match = expression.match(args);
+ }
+ }
+ if (!args.isEmpty() && args != to->getVanillaVersion()->minecraftArguments)
+ {
+ obj.insert("minecraftArguments", args);
+ }
+ if (!tweakers.isEmpty())
+ {
+ obj.insert("+tweakers", QJsonArray::fromStringList(tweakers));
+ }
+ if (!m_forge_version->processArguments.isEmpty() &&
+ m_forge_version->processArguments != to->getVanillaVersion()->processArguments)
+ {
+ obj.insert("processArguments", m_forge_version->processArguments);
}
- to->mainClass = m_forge_version->mainClass;
- to->minecraftArguments = m_forge_version->minecraftArguments;
- to->processArguments = m_forge_version->processArguments;
}
- to->externalUpdateFinish();
- return to->toOriginalFile();
+
+ obj.insert("name", QString("Forge"));
+ obj.insert("fileId", id());
+ obj.insert("version", m_forgeVersionString);
+ obj.insert("mcVersion", to->intendedVersionId());
+
+ QFile file(filename(to->instanceRoot()));
+ if (!file.open(QFile::WriteOnly))
+ {
+ QLOG_ERROR() << "Error opening" << file.fileName()
+ << "for reading:" << file.errorString();
+ return false;
+ }
+ file.write(QJsonDocument(obj).toJson());
+ file.close();
+
+ return true;
}
diff --git a/logic/ForgeInstaller.h b/logic/ForgeInstaller.h
index 0b9f9c77..c5052092 100644
--- a/logic/ForgeInstaller.h
+++ b/logic/ForgeInstaller.h
@@ -14,17 +14,22 @@
*/
#pragma once
+
+#include "BaseInstaller.h"
+
#include <QString>
#include <memory>
class OneSixVersion;
-class ForgeInstaller
+class ForgeInstaller : public BaseInstaller
{
public:
ForgeInstaller(QString filename, QString universal_url);
- bool apply(std::shared_ptr<OneSixVersion> to);
+ bool add(OneSixInstance *to) override;
+
+ QString id() const override { return "net.minecraftforge"; }
private:
// the version, read from the installer
@@ -32,5 +37,6 @@ private:
QString internalPath;
QString finalPath;
QString realVersionId;
+ QString m_forgeVersionString;
QString m_universal_url;
};
diff --git a/logic/InstanceFactory.cpp b/logic/InstanceFactory.cpp
index 1f1a5879..807bccd0 100644
--- a/logic/InstanceFactory.cpp
+++ b/logic/InstanceFactory.cpp
@@ -24,6 +24,7 @@
#include "OneSixInstance.h"
#include "OneSixFTBInstance.h"
#include "NostalgiaInstance.h"
+#include "OneSixInstance.h"
#include "BaseVersion.h"
#include "MinecraftVersion.h"
@@ -50,13 +51,13 @@ InstanceFactory::InstLoadError InstanceFactory::loadInstance(BaseInstance *&inst
QString inst_type = m_settings->get("InstanceType").toString();
// FIXME: replace with a map lookup, where instance classes register their types
- if (inst_type == "Legacy")
+ if (inst_type == "OneSix")
{
- inst = new LegacyInstance(instDir, m_settings, this);
+ inst = new OneSixInstance(instDir, m_settings, this);
}
- else if (inst_type == "OneSix")
+ else if (inst_type == "Legacy")
{
- inst = new OneSixInstance(instDir, m_settings, this);
+ inst = new LegacyInstance(instDir, m_settings, this);
}
else if (inst_type == "Nostalgia")
{
@@ -101,6 +102,7 @@ InstanceFactory::InstCreateError InstanceFactory::createInstance(BaseInstance *&
switch (mcVer->type)
{
case MinecraftVersion::Legacy:
+ // TODO new instance type
m_settings->set("InstanceType", "Legacy");
inst = new LegacyInstance(instDir, m_settings, this);
inst->setIntendedVersionId(version->descriptor());
diff --git a/logic/LiteLoaderInstaller.cpp b/logic/LiteLoaderInstaller.cpp
index 07fffff3..c363cad6 100644
--- a/logic/LiteLoaderInstaller.cpp
+++ b/logic/LiteLoaderInstaller.cpp
@@ -15,12 +15,19 @@
#include "LiteLoaderInstaller.h"
+#include <QJsonArray>
+#include <QJsonDocument>
+
+#include "logger/QsLog.h"
+
#include "OneSixVersion.h"
#include "OneSixLibrary.h"
+#include "OneSixInstance.h"
QMap<QString, QString> LiteLoaderInstaller::m_launcherWrapperVersionMapping;
-LiteLoaderInstaller::LiteLoaderInstaller(const QString &mcVersion) : m_mcVersion(mcVersion)
+LiteLoaderInstaller::LiteLoaderInstaller()
+ : BaseInstaller()
{
if (m_launcherWrapperVersionMapping.isEmpty())
{
@@ -31,72 +38,60 @@ LiteLoaderInstaller::LiteLoaderInstaller(const QString &mcVersion) : m_mcVersion
}
}
-bool LiteLoaderInstaller::canApply() const
+bool LiteLoaderInstaller::canApply(OneSixInstance *instance) const
{
- return m_launcherWrapperVersionMapping.contains(m_mcVersion);
+ return m_launcherWrapperVersionMapping.contains(instance->intendedVersionId());
}
-bool LiteLoaderInstaller::apply(std::shared_ptr<OneSixVersion> to)
+bool LiteLoaderInstaller::add(OneSixInstance *to)
{
- to->externalUpdateStart();
-
- applyLaunchwrapper(to);
- applyLiteLoader(to);
-
- to->mainClass = "net.minecraft.launchwrapper.Launch";
- if (!to->minecraftArguments.contains(
- " --tweakClass com.mumfrey.liteloader.launch.LiteLoaderTweaker"))
+ if (!BaseInstaller::add(to))
{
- to->minecraftArguments.append(
- " --tweakClass com.mumfrey.liteloader.launch.LiteLoaderTweaker");
+ return false;
}
- to->externalUpdateFinish();
- return to->toOriginalFile();
-}
+ QJsonObject obj;
-void LiteLoaderInstaller::applyLaunchwrapper(std::shared_ptr<OneSixVersion> to)
-{
- const QString intendedVersion = m_launcherWrapperVersionMapping[m_mcVersion];
+ obj.insert("mainClass", QString("net.minecraft.launchwrapper.Launch"));
+ obj.insert("+tweakers", QJsonArray::fromStringList(QStringList() << "com.mumfrey.liteloader.launch.LiteLoaderTweaker"));
+ obj.insert("order", 10);
- QMutableListIterator<std::shared_ptr<OneSixLibrary>> it(to->libraries);
- while (it.hasNext())
+ QJsonArray libraries;
+
+ // launchwrapper
{
- it.next();
- if (it.value()->rawName().startsWith("net.minecraft:launchwrapper:"))
- {
- if (it.value()->version() >= intendedVersion)
- {
- return;
- }
- else
- {
- it.remove();
- }
- }
+ OneSixLibrary launchwrapperLib("net.minecraft:launchwrapper:" + m_launcherWrapperVersionMapping[to->intendedVersionId()]);
+ launchwrapperLib.finalize();
+ QJsonObject lwLibObj = launchwrapperLib.toJson();
+ lwLibObj.insert("insert", QString("prepend"));
+ libraries.append(lwLibObj);
}
- std::shared_ptr<OneSixLibrary> lib(new OneSixLibrary(
- "net.minecraft:launchwrapper:" + m_launcherWrapperVersionMapping[m_mcVersion]));
- lib->finalize();
- to->libraries.prepend(lib);
-}
+ // liteloader
+ {
+ OneSixLibrary liteloaderLib("com.mumfrey:liteloader:" + to->intendedVersionId());
+ liteloaderLib.setBaseUrl("http://dl.liteloader.com/versions/");
+ liteloaderLib.finalize();
+ QJsonObject llLibObj = liteloaderLib.toJson();
+ llLibObj.insert("insert", QString("prepend"));
+ llLibObj.insert("MMC-depend", QString("hard"));
+ libraries.append(llLibObj);
+ }
-void LiteLoaderInstaller::applyLiteLoader(std::shared_ptr<OneSixVersion> to)
-{
- QMutableListIterator<std::shared_ptr<OneSixLibrary>> it(to->libraries);
- while (it.hasNext())
+ obj.insert("+libraries", libraries);
+ obj.insert("name", QString("LiteLoader"));
+ obj.insert("fileId", id());
+ obj.insert("version", to->intendedVersionId());
+ obj.insert("mcVersion", to->intendedVersionId());
+
+ QFile file(filename(to->instanceRoot()));
+ if (!file.open(QFile::WriteOnly))
{
- it.next();
- if (it.value()->rawName().startsWith("com.mumfrey:liteloader:"))
- {
- it.remove();
- }
+ QLOG_ERROR() << "Error opening" << file.fileName() << "for reading:" << file.errorString();
+ return false;
}
+ file.write(QJsonDocument(obj).toJson());
+ file.close();
- std::shared_ptr<OneSixLibrary> lib(
- new OneSixLibrary("com.mumfrey:liteloader:" + m_mcVersion));
- lib->setBaseUrl("http://dl.liteloader.com/versions/");
- lib->finalize();
- to->libraries.prepend(lib);
+ return true;
}
diff --git a/logic/LiteLoaderInstaller.h b/logic/LiteLoaderInstaller.h
index 44b306d6..5e01b16c 100644
--- a/logic/LiteLoaderInstaller.h
+++ b/logic/LiteLoaderInstaller.h
@@ -14,26 +14,22 @@
*/
#pragma once
+
+#include "BaseInstaller.h"
+
#include <QString>
#include <QMap>
-#include <memory>
-
-class OneSixVersion;
-class LiteLoaderInstaller
+class LiteLoaderInstaller : public BaseInstaller
{
public:
- LiteLoaderInstaller(const QString &mcVersion);
+ LiteLoaderInstaller();
- bool canApply() const;
-
- bool apply(std::shared_ptr<OneSixVersion> to);
+ bool canApply(OneSixInstance *instance) const override;
+ bool add(OneSixInstance *to) override;
private:
- QString m_mcVersion;
-
- void applyLaunchwrapper(std::shared_ptr<OneSixVersion> to);
- void applyLiteLoader(std::shared_ptr<OneSixVersion> to);
+ virtual QString id() const override { return "com.mumfrey.liteloader"; }
static QMap<QString, QString> m_launcherWrapperVersionMapping;
};
diff --git a/logic/OneSixFTBInstance.cpp b/logic/OneSixFTBInstance.cpp
index f8e695b9..ca88142a 100644
--- a/logic/OneSixFTBInstance.cpp
+++ b/logic/OneSixFTBInstance.cpp
@@ -55,15 +55,13 @@ slots:
setStatus(tr("Installing Forge..."));
QString forgePath = entry->getFullPath();
ForgeInstaller forge(forgePath, forgeVersion->universal_url);
- if (!instance->reloadFullVersion())
+ if (!instance->reloadVersion())
{
emitFailed(tr("Couldn't load the version config"));
return;
}
- instance->revertCustomVersion();
- instance->customizeVersion();
auto version = instance->getFullVersion();
- if (!forge.apply(version))
+ if (!forge.add(instance))
{
emitFailed(tr("Couldn't install Forge"));
return;
diff --git a/logic/OneSixInstance.cpp b/logic/OneSixInstance.cpp
index 67649f77..ae172f21 100644
--- a/logic/OneSixInstance.cpp
+++ b/logic/OneSixInstance.cpp
@@ -13,32 +13,37 @@
* limitations under the License.
*/
-#include "MultiMC.h"
#include "OneSixInstance.h"
+
+#include <QIcon>
+
#include "OneSixInstance_p.h"
#include "OneSixUpdate.h"
-#include "MinecraftProcess.h"
#include "OneSixVersion.h"
-#include "JavaChecker.h"
-#include "logic/icons/IconList.h"
-
-#include <setting.h>
-#include <pathutils.h>
-#include <cmdutils.h>
-#include <JlCompress.h>
-#include "gui/dialogs/OneSixModEditDialog.h"
+#include "pathutils.h"
#include "logger/QsLog.h"
-#include "logic/assets/AssetsUtils.h"
-#include <QIcon>
+#include "assets/AssetsUtils.h"
+#include "MultiMC.h"
+#include "icons/IconList.h"
+#include "MinecraftProcess.h"
+#include "gui/dialogs/OneSixModEditDialog.h"
-OneSixInstance::OneSixInstance(const QString &rootDir, SettingsObject *setting_obj,
- QObject *parent)
- : BaseInstance(new OneSixInstancePrivate(), rootDir, setting_obj, parent)
+OneSixInstance::OneSixInstance(const QString &rootDir, SettingsObject *settings, QObject *parent)
+ : BaseInstance(new OneSixInstancePrivate(), rootDir, settings, parent)
{
I_D(OneSixInstance);
d->m_settings->registerSetting("IntendedVersion", "");
d->m_settings->registerSetting("ShouldUpdate", false);
- reloadFullVersion();
+ d->version.reset(new OneSixVersion(this, this));
+ d->vanillaVersion.reset(new OneSixVersion(this, this));
+ if (QDir(instanceRoot()).exists("version.json"))
+ {
+ reloadVersion();
+ }
+ else
+ {
+ clearVersion();
+ }
}
std::shared_ptr<Task> OneSixInstance::doUpdate()
@@ -135,6 +140,10 @@ QStringList OneSixInstance::processMinecraftArgs(AuthSessionPtr session)
I_D(OneSixInstance);
auto version = d->version;
QString args_pattern = version->minecraftArguments;
+ for (auto tweaker : version->tweakers)
+ {
+ args_pattern += " --tweakClass " + tweaker;
+ }
QMap<QString, QString> token_mapping;
// yggdrasil!
@@ -267,11 +276,8 @@ bool OneSixInstance::setIntendedVersionId(QString version)
{
settings().set("IntendedVersion", version);
setShouldUpdate(true);
- auto pathCustom = PathCombine(instanceRoot(), "custom.json");
- auto pathOrig = PathCombine(instanceRoot(), "version.json");
- QFile::remove(pathCustom);
- QFile::remove(pathOrig);
- reloadFullVersion();
+ QFile::remove(PathCombine(instanceRoot(), "version.json"));
+ clearVersion();
return true;
}
@@ -297,9 +303,10 @@ bool OneSixInstance::shouldUpdate() const
bool OneSixInstance::versionIsCustom()
{
- QString verpath_custom = PathCombine(instanceRoot(), "custom.json");
- QFile versionfile(verpath_custom);
- return versionfile.exists();
+ QDir patches(PathCombine(instanceRoot(), "patches/"));
+ return (patches.exists() && patches.count() >= 0)
+ || QFile::exists(PathCombine(instanceRoot(), "custom.json"))
+ || QFile::exists(PathCombine(instanceRoot(), "user.json"));
}
QString OneSixInstance::currentVersionId() const
@@ -307,62 +314,39 @@ QString OneSixInstance::currentVersionId() const
return intendedVersionId();
}
-bool OneSixInstance::customizeVersion()
+bool OneSixInstance::reloadVersion(QWidget *widgetParent)
{
- if (!versionIsCustom())
- {
- auto pathCustom = PathCombine(instanceRoot(), "custom.json");
- auto pathOrig = PathCombine(instanceRoot(), "version.json");
- QFile::copy(pathOrig, pathCustom);
- return reloadFullVersion();
- }
- else
- return true;
-}
+ I_D(OneSixInstance);
-bool OneSixInstance::revertCustomVersion()
-{
- if (versionIsCustom())
+ bool ret = d->version->reload(widgetParent);
+ if (ret)
{
- auto path = PathCombine(instanceRoot(), "custom.json");
- QFile::remove(path);
- return reloadFullVersion();
+ ret = d->vanillaVersion->reload(widgetParent, true);
}
- else
- return true;
+ emit versionReloaded();
+ return ret;
}
-bool OneSixInstance::reloadFullVersion()
+void OneSixInstance::clearVersion()
{
I_D(OneSixInstance);
-
- QString verpath = PathCombine(instanceRoot(), "version.json");
- {
- QString verpath_custom = PathCombine(instanceRoot(), "custom.json");
- QFile versionfile(verpath_custom);
- if (versionfile.exists())
- verpath = verpath_custom;
- }
-
- auto version = OneSixVersion::fromFile(verpath);
- if (version)
- {
- d->version = version;
- return true;
- }
- else
- {
- d->version.reset();
- return false;
- }
+ d->version->clear();
+ d->vanillaVersion->clear();
+ emit versionReloaded();
}
-std::shared_ptr<OneSixVersion> OneSixInstance::getFullVersion()
+std::shared_ptr<OneSixVersion> OneSixInstance::getFullVersion() const
{
- I_D(OneSixInstance);
+ I_D(const OneSixInstance);
return d->version;
}
+std::shared_ptr<OneSixVersion> OneSixInstance::getVanillaVersion() const
+{
+ I_D(const OneSixInstance);
+ return d->vanillaVersion;
+}
+
QString OneSixInstance::defaultBaseJar() const
{
return "versions/" + intendedVersionId() + "/" + intendedVersionId() + ".jar";
@@ -382,7 +366,7 @@ bool OneSixInstance::menuActionEnabled(QString action_name) const
QString OneSixInstance::getStatusbarDescription()
{
- QString descr = "One Six : " + intendedVersionId();
+ QString descr = "OneSix : " + intendedVersionId();
if (versionIsCustom())
{
descr + " (custom)";
diff --git a/logic/OneSixInstance.h b/logic/OneSixInstance.h
index c159723b..ae95eab1 100644
--- a/logic/OneSixInstance.h
+++ b/logic/OneSixInstance.h
@@ -15,21 +15,17 @@
#pragma once
-#include <QStringList>
-#include <QDir>
-
#include "BaseInstance.h"
-class OneSixVersion;
-class Task;
-class ModList;
+#include "OneSixVersion.h"
+#include "ModList.h"
class OneSixInstance : public BaseInstance
{
Q_OBJECT
public:
explicit OneSixInstance(const QString &rootDir, SettingsObject *settings,
- QObject *parent = 0);
+ QObject *parent = 0);
////// Mod Lists //////
std::shared_ptr<ModList> loaderModList();
@@ -55,14 +51,14 @@ public:
virtual QDialog *createModEditDialog(QWidget *parent) override;
- /// reload the full version json file. return true on success!
- bool reloadFullVersion();
+ /// reload the full version json files. return true on success!
+ bool reloadVersion(QWidget *widgetParent = 0);
+ /// clears all version information in preparation for an update
+ void clearVersion();
/// get the current full version info
- std::shared_ptr<OneSixVersion> getFullVersion();
- /// revert the current custom version back to base
- bool revertCustomVersion();
- /// customize the current base version
- bool customizeVersion();
+ std::shared_ptr<OneSixVersion> getFullVersion() const;
+ /// gets the current version info, but only for version.json
+ std::shared_ptr<OneSixVersion> getVanillaVersion() const;
/// is the current version original, or custom?
virtual bool versionIsCustom() override;
@@ -72,6 +68,9 @@ public:
virtual bool menuActionEnabled(QString action_name) const override;
virtual QString getStatusbarDescription() override;
+signals:
+ void versionReloaded();
+
private:
QStringList processMinecraftArgs(AuthSessionPtr account);
QDir reconstructAssets(std::shared_ptr<OneSixVersion> version);
diff --git a/logic/OneSixInstance_p.h b/logic/OneSixInstance_p.h
index 6b7ea431..0cc46f33 100644
--- a/logic/OneSixInstance_p.h
+++ b/logic/OneSixInstance_p.h
@@ -15,16 +15,14 @@
#pragma once
-#include <memory>
-
-#include "logic/BaseInstance_p.h"
-#include "logic/OneSixVersion.h"
-#include "logic/OneSixLibrary.h"
-#include "logic/ModList.h"
+#include "BaseInstance_p.h"
+#include "OneSixVersion.h"
+#include "ModList.h"
struct OneSixInstancePrivate : public BaseInstancePrivate
{
std::shared_ptr<OneSixVersion> version;
+ std::shared_ptr<OneSixVersion> vanillaVersion;
std::shared_ptr<ModList> loader_mod_list;
std::shared_ptr<ModList> resource_pack_list;
-}; \ No newline at end of file
+};
diff --git a/logic/OneSixLibrary.cpp b/logic/OneSixLibrary.cpp
index 7b80d5e7..c78679d1 100644
--- a/logic/OneSixLibrary.cpp
+++ b/logic/OneSixLibrary.cpp
@@ -46,7 +46,7 @@ void OneSixLibrary::finalize()
}
m_decentname = parts[1];
- m_decentversion = parts[2];
+ m_decentversion = minVersion = parts[2];
m_storage_path = relative;
m_download_url = m_base_url + relative;
@@ -76,11 +76,11 @@ void OneSixLibrary::finalize()
}
}
-void OneSixLibrary::setName(QString name)
+void OneSixLibrary::setName(const QString &name)
{
m_name = name;
}
-void OneSixLibrary::setBaseUrl(QString base_url)
+void OneSixLibrary::setBaseUrl(const QString &base_url)
{
m_base_url = base_url;
}
@@ -88,50 +88,54 @@ void OneSixLibrary::setIsNative()
{
m_is_native = true;
}
-void OneSixLibrary::addNative(OpSys os, QString suffix)
+void OneSixLibrary::addNative(OpSys os, const QString &suffix)
{
m_is_native = true;
m_native_suffixes[os] = suffix;
}
+void OneSixLibrary::clearSuffixes()
+{
+ m_native_suffixes.clear();
+}
void OneSixLibrary::setRules(QList<std::shared_ptr<Rule>> rules)
{
m_rules = rules;
}
-bool OneSixLibrary::isActive()
+bool OneSixLibrary::isActive() const
{
return m_is_active;
}
-bool OneSixLibrary::isNative()
+bool OneSixLibrary::isNative() const
{
return m_is_native;
}
-QString OneSixLibrary::downloadUrl()
+QString OneSixLibrary::downloadUrl() const
{
if (m_absolute_url.size())
return m_absolute_url;
return m_download_url;
}
-QString OneSixLibrary::storagePath()
+QString OneSixLibrary::storagePath() const
{
return m_storage_path;
}
-void OneSixLibrary::setAbsoluteUrl(QString absolute_url)
+void OneSixLibrary::setAbsoluteUrl(const QString &absolute_url)
{
m_absolute_url = absolute_url;
}
-QString OneSixLibrary::absoluteUrl()
+QString OneSixLibrary::absoluteUrl() const
{
return m_absolute_url;
}
-void OneSixLibrary::setHint(QString hint)
+void OneSixLibrary::setHint(const QString &hint)
{
m_hint = hint;
}
-QString OneSixLibrary::hint()
+QString OneSixLibrary::hint() const
{
return m_hint;
}
@@ -176,7 +180,7 @@ bool OneSixLibrary::extractTo(QString target_dir)
cooked_storage.replace("${arch}", "32");
QString origin = PathCombine("libraries", cooked_storage);
QString target_dir_cooked = PathCombine(target_dir, "32");
- if(!ensureFolderPathExists(target_dir_cooked))
+ if (!ensureFolderPathExists(target_dir_cooked))
{
QLOG_ERROR() << "Couldn't create folder " + target_dir_cooked;
return false;
@@ -191,7 +195,7 @@ bool OneSixLibrary::extractTo(QString target_dir)
cooked_storage.replace("${arch}", "64");
origin = PathCombine("libraries", cooked_storage);
target_dir_cooked = PathCombine(target_dir, "64");
- if(!ensureFolderPathExists(target_dir_cooked))
+ if (!ensureFolderPathExists(target_dir_cooked))
{
QLOG_ERROR() << "Couldn't create folder " + target_dir_cooked;
return false;
@@ -205,7 +209,7 @@ bool OneSixLibrary::extractTo(QString target_dir)
}
else
{
- if(!ensureFolderPathExists(target_dir))
+ if (!ensureFolderPathExists(target_dir))
{
QLOG_ERROR() << "Couldn't create folder " + target_dir;
return false;
@@ -230,8 +234,10 @@ QJsonObject OneSixLibrary::toJson()
libRoot.insert("MMC-hint", m_hint);
if (m_base_url != "http://" + URLConstants::AWS_DOWNLOAD_LIBRARIES &&
m_base_url != "https://" + URLConstants::AWS_DOWNLOAD_LIBRARIES &&
- m_base_url != "https://" + URLConstants::LIBRARY_BASE)
+ m_base_url != "https://" + URLConstants::LIBRARY_BASE && !m_base_url.isEmpty())
+ {
libRoot.insert("url", m_base_url);
+ }
if (isNative() && m_native_suffixes.size())
{
QJsonObject nativeList;
diff --git a/logic/OneSixLibrary.h b/logic/OneSixLibrary.h
index 227cdbef..371ca6f4 100644
--- a/logic/OneSixLibrary.h
+++ b/logic/OneSixLibrary.h
@@ -60,12 +60,21 @@ private:
public:
QStringList extract_excludes;
+ QString minVersion;
+
+ enum DependType
+ {
+ Soft,
+ Hard
+ };
+ DependType dependType;
public:
/// Constructor
- OneSixLibrary(QString name)
+ OneSixLibrary(const QString &name, const DependType type = Soft)
{
m_name = name;
+ dependType = type;
}
/// Returns the raw name field
@@ -84,48 +93,50 @@ public:
void finalize();
/// Set the library composite name
- void setName(QString name);
+ void setName(const QString &name);
/// get a decent-looking name
- QString name()
+ QString name() const
{
return m_decentname;
}
/// get a decent-looking version
- QString version()
+ QString version() const
{
return m_decentversion;
}
/// what kind of library is it? (for display)
- QString type()
+ QString type() const
{
return m_decenttype;
}
/// Set the url base for downloads
- void setBaseUrl(QString base_url);
+ void setBaseUrl(const QString &base_url);
/// Call this to mark the library as 'native' (it's a zip archive with DLLs)
void setIsNative();
/// Attach a name suffix to the specified OS native
- void addNative(OpSys os, QString suffix);
+ void addNative(OpSys os, const QString &suffix);
+ /// Clears all suffixes
+ void clearSuffixes();
/// Set the load rules
void setRules(QList<std::shared_ptr<Rule>> rules);
/// Returns true if the library should be loaded (or extracted, in case of natives)
- bool isActive();
+ bool isActive() const;
/// Returns true if the library is native
- bool isNative();
+ bool isNative() const;
/// Get the URL to download the library from
- QString downloadUrl();
+ QString downloadUrl() const;
/// Get the relative path where the library should be saved
- QString storagePath();
+ QString storagePath() const;
/// set an absolute URL for the library. This is an MMC extension.
- void setAbsoluteUrl(QString absolute_url);
- QString absoluteUrl();
+ void setAbsoluteUrl(const QString &absolute_url);
+ QString absoluteUrl() const;
/// set a hint about how to treat the library. This is an MMC extension.
- void setHint(QString hint);
- QString hint();
+ void setHint(const QString &hint);
+ QString hint() const;
bool extractTo(QString target_dir);
bool filesExist();
diff --git a/logic/OneSixRule.cpp b/logic/OneSixRule.cpp
index 392b1dd1..d8d13b50 100644
--- a/logic/OneSixRule.cpp
+++ b/logic/OneSixRule.cpp
@@ -18,7 +18,7 @@
#include "OneSixRule.h"
-QList<std::shared_ptr<Rule>> rulesFromJsonV4(QJsonObject &objectWithRules)
+QList<std::shared_ptr<Rule>> rulesFromJsonV4(const QJsonObject &objectWithRules)
{
QList<std::shared_ptr<Rule>> rules;
auto rulesVal = objectWithRules.value("rules");
@@ -86,4 +86,4 @@ RuleAction RuleAction_fromString(QString name)
if (name == "disallow")
return Disallow;
return Defer;
-} \ No newline at end of file
+}
diff --git a/logic/OneSixRule.h b/logic/OneSixRule.h
index 5a13cbd9..426e2886 100644
--- a/logic/OneSixRule.h
+++ b/logic/OneSixRule.h
@@ -27,7 +27,7 @@ enum RuleAction
};
RuleAction RuleAction_fromString(QString);
-QList<std::shared_ptr<Rule>> rulesFromJsonV4(QJsonObject &objectWithRules);
+QList<std::shared_ptr<Rule>> rulesFromJsonV4(const QJsonObject &objectWithRules);
class Rule
{
diff --git a/logic/OneSixUpdate.cpp b/logic/OneSixUpdate.cpp
index 7685952c..d3ac80c2 100644
--- a/logic/OneSixUpdate.cpp
+++ b/logic/OneSixUpdate.cpp
@@ -131,7 +131,7 @@ void OneSixUpdate::versionFileFinished()
{
finfo.remove();
}
- inst->reloadFullVersion();
+ inst->reloadVersion();
jarlibStart();
}
@@ -229,7 +229,7 @@ void OneSixUpdate::jarlibStart()
setStatus(tr("Getting the library files from Mojang..."));
QLOG_INFO() << m_inst->name() << ": downloading libraries";
OneSixInstance *inst = (OneSixInstance *)m_inst;
- bool successful = inst->reloadFullVersion();
+ bool successful = inst->reloadVersion();
if (!successful)
{
emitFailed("Failed to load the version description file. It might be "
diff --git a/logic/OneSixVersion.cpp b/logic/OneSixVersion.cpp
index 8ae685f0..fb32f3a8 100644
--- a/logic/OneSixVersion.cpp
+++ b/logic/OneSixVersion.cpp
@@ -13,228 +13,95 @@
* limitations under the License.
*/
-#include "logic/OneSixVersion.h"
-#include "logic/OneSixLibrary.h"
-#include "logic/OneSixRule.h"
+#include "OneSixVersion.h"
-#include "logger/QsLog.h"
+#include <QDebug>
+#include <QFile>
-std::shared_ptr<OneSixVersion> fromJsonV4(QJsonObject root,
- std::shared_ptr<OneSixVersion> fullVersion)
-{
- fullVersion->id = root.value("id").toString();
-
- fullVersion->mainClass = root.value("mainClass").toString();
- auto procArgsValue = root.value("processArguments");
- if (procArgsValue.isString())
- {
- fullVersion->processArguments = procArgsValue.toString();
- QString toCompare = fullVersion->processArguments.toLower();
- if (toCompare == "legacy")
- {
- fullVersion->minecraftArguments = " ${auth_player_name} ${auth_session}";
- }
- else if (toCompare == "username_session")
- {
- fullVersion->minecraftArguments =
- "--username ${auth_player_name} --session ${auth_session}";
- }
- else if (toCompare == "username_session_version")
- {
- fullVersion->minecraftArguments = "--username ${auth_player_name} "
- "--session ${auth_session} "
- "--version ${profile_name}";
- }
- }
-
- auto minecraftArgsValue = root.value("minecraftArguments");
- if (minecraftArgsValue.isString())
- {
- fullVersion->minecraftArguments = minecraftArgsValue.toString();
- }
+#include "OneSixVersionBuilder.h"
- auto minecraftTypeValue = root.value("type");
- if (minecraftTypeValue.isString())
- {
- fullVersion->type = minecraftTypeValue.toString();
- }
-
- fullVersion->releaseTime = root.value("releaseTime").toString();
- fullVersion->time = root.value("time").toString();
-
- auto assetsID = root.value("assets");
- if (assetsID.isString())
- {
- fullVersion->assets = assetsID.toString();
- }
- else
- {
- fullVersion->assets = "legacy";
- }
-
- QLOG_DEBUG() << "Assets version:" << fullVersion->assets;
-
- // Iterate through the list, if it's a list.
- auto librariesValue = root.value("libraries");
- if (!librariesValue.isArray())
- return fullVersion;
-
- QJsonArray libList = root.value("libraries").toArray();
- for (auto libVal : libList)
- {
- if (!libVal.isObject())
- {
- continue;
- }
-
- QJsonObject libObj = libVal.toObject();
-
- // Library name
- auto nameVal = libObj.value("name");
- if (!nameVal.isString())
- continue;
- std::shared_ptr<OneSixLibrary> library(new OneSixLibrary(nameVal.toString()));
-
- auto urlVal = libObj.value("url");
- if (urlVal.isString())
- {
- library->setBaseUrl(urlVal.toString());
- }
- auto hintVal = libObj.value("MMC-hint");
- if (hintVal.isString())
- {
- library->setHint(hintVal.toString());
- }
- auto urlAbsVal = libObj.value("MMC-absoluteUrl");
- auto urlAbsuVal = libObj.value("MMC-absulute_url"); // compatibility
- if (urlAbsVal.isString())
- {
- library->setAbsoluteUrl(urlAbsVal.toString());
- }
- else if (urlAbsuVal.isString())
- {
- library->setAbsoluteUrl(urlAbsuVal.toString());
- }
- // Extract excludes (if any)
- auto extractVal = libObj.value("extract");
- if (extractVal.isObject())
- {
- QStringList excludes;
- auto extractObj = extractVal.toObject();
- auto excludesVal = extractObj.value("exclude");
- if (excludesVal.isArray())
- {
- auto excludesList = excludesVal.toArray();
- for (auto excludeVal : excludesList)
- {
- if (excludeVal.isString())
- excludes.append(excludeVal.toString());
- }
- library->extract_excludes = excludes;
- }
- }
-
- auto nativesVal = libObj.value("natives");
- if (nativesVal.isObject())
- {
- library->setIsNative();
- auto nativesObj = nativesVal.toObject();
- auto iter = nativesObj.begin();
- while (iter != nativesObj.end())
- {
- auto osType = OpSys_fromString(iter.key());
- if (osType == Os_Other)
- continue;
- if (!iter.value().isString())
- continue;
- library->addNative(osType, iter.value().toString());
- iter++;
- }
- }
- library->setRules(rulesFromJsonV4(libObj));
- library->finalize();
- fullVersion->libraries.append(library);
- }
- return fullVersion;
+OneSixVersion::OneSixVersion(OneSixInstance *instance, QObject *parent)
+ : QAbstractListModel(parent), m_instance(instance)
+{
+ clear();
}
-std::shared_ptr<OneSixVersion> OneSixVersion::fromJson(QJsonObject root)
+bool OneSixVersion::reload(QWidget *widgetParent, const bool onlyVanilla)
{
- std::shared_ptr<OneSixVersion> readVersion(new OneSixVersion());
- int launcher_ver = readVersion->minimumLauncherVersion =
- root.value("minimumLauncherVersion").toDouble();
+ beginResetModel();
+ bool ret = OneSixVersionBuilder::build(this, m_instance, widgetParent, onlyVanilla);
+ endResetModel();
+ return ret;
+}
- // ADD MORE HERE :D
- if (launcher_ver > 0 && launcher_ver <= 13)
- return fromJsonV4(root, readVersion);
- else
- {
- return std::shared_ptr<OneSixVersion>();
- }
+void OneSixVersion::clear()
+{
+ beginResetModel();
+ id.clear();
+ time.clear();
+ releaseTime.clear();
+ type.clear();
+ assets.clear();
+ processArguments.clear();
+ minecraftArguments.clear();
+ minimumLauncherVersion = 0xDEADBEAF;
+ mainClass.clear();
+ libraries.clear();
+ tweakers.clear();
+ versionFiles.clear();
+ endResetModel();
}
-std::shared_ptr<OneSixVersion> OneSixVersion::fromFile(QString filepath)
+void OneSixVersion::dump() const
{
- QFile file(filepath);
- if (!file.open(QIODevice::ReadOnly))
+ qDebug().nospace() << "OneSixVersion("
+ << "\n\tid=" << id
+ << "\n\ttime=" << time
+ << "\n\treleaseTime=" << releaseTime
+ << "\n\ttype=" << type
+ << "\n\tassets=" << assets
+ << "\n\tprocessArguments=" << processArguments
+ << "\n\tminecraftArguments=" << minecraftArguments
+ << "\n\tminimumLauncherVersion=" << minimumLauncherVersion
+ << "\n\tmainClass=" << mainClass
+ << "\n\tlibraries=";
+ for (auto lib : libraries)
{
- return std::shared_ptr<OneSixVersion>();
+ qDebug().nospace() << "\n\t\t" << lib.get();
}
+ qDebug().nospace() << "\n)";
+}
- auto data = file.readAll();
- QJsonParseError jsonError;
- QJsonDocument jsonDoc = QJsonDocument::fromJson(data, &jsonError);
-
- if (jsonError.error != QJsonParseError::NoError)
+bool OneSixVersion::canRemove(const int index) const
+{
+ if (index < versionFiles.size())
{
- return std::shared_ptr<OneSixVersion>();
+ return versionFiles.at(index).id != "org.multimc.version.json";
}
+ return false;
+}
- if (!jsonDoc.isObject())
+QString OneSixVersion::versionFileId(const int index) const
+{
+ if (index < 0 || index >= versionFiles.size())
{
- return std::shared_ptr<OneSixVersion>();
+ return QString();
}
- QJsonObject root = jsonDoc.object();
- auto version = fromJson(root);
- if (version)
- version->original_file = filepath;
- return version;
+ return versionFiles.at(index).id;
}
-bool OneSixVersion::toOriginalFile()
+bool OneSixVersion::remove(const int index)
{
- if (original_file.isEmpty())
- return false;
- QSaveFile file(original_file);
- if (!file.open(QIODevice::WriteOnly))
- {
- return false;
- }
- // serialize base attributes (those we care about anyway)
- QJsonObject root;
- root.insert("minecraftArguments", minecraftArguments);
- root.insert("mainClass", mainClass);
- root.insert("minimumLauncherVersion", minimumLauncherVersion);
- root.insert("time", time);
- root.insert("id", id);
- root.insert("type", type);
- // screw processArguments
- root.insert("releaseTime", releaseTime);
- QJsonArray libarray;
- for (const auto &lib : libraries)
+ if (canRemove(index))
{
- libarray.append(lib->toJson());
+ return QFile::remove(versionFiles.at(index).filename);
}
- if (libarray.count())
- root.insert("libraries", libarray);
- QJsonDocument doc(root);
- file.write(doc.toJson());
- return file.commit();
+ return false;
}
-QList<std::shared_ptr<OneSixLibrary>> OneSixVersion::getActiveNormalLibs()
+QList<std::shared_ptr<OneSixLibrary> > OneSixVersion::getActiveNormalLibs()
{
- QList<std::shared_ptr<OneSixLibrary>> output;
+ QList<std::shared_ptr<OneSixLibrary> > output;
for (auto lib : libraries)
{
if (lib->isActive() && !lib->isNative())
@@ -245,9 +112,9 @@ QList<std::shared_ptr<OneSixLibrary>> OneSixVersion::getActiveNormalLibs()
return output;
}
-QList<std::shared_ptr<OneSixLibrary>> OneSixVersion::getActiveNativeLibs()
+QList<std::shared_ptr<OneSixLibrary> > OneSixVersion::getActiveNativeLibs()
{
- QList<std::shared_ptr<OneSixLibrary>> output;
+ QList<std::shared_ptr<OneSixLibrary> > output;
for (auto lib : libraries)
{
if (lib->isActive() && lib->isNative())
@@ -258,14 +125,14 @@ QList<std::shared_ptr<OneSixLibrary>> OneSixVersion::getActiveNativeLibs()
return output;
}
-void OneSixVersion::externalUpdateStart()
-{
- beginResetModel();
-}
-
-void OneSixVersion::externalUpdateFinish()
+std::shared_ptr<OneSixVersion> OneSixVersion::fromJson(const QJsonObject &obj)
{
- endResetModel();
+ std::shared_ptr<OneSixVersion> version(new OneSixVersion(0));
+ if (OneSixVersionBuilder::read(version.get(), obj))
+ {
+ return version;
+ }
+ return 0;
}
QVariant OneSixVersion::data(const QModelIndex &index, int role) const
@@ -276,7 +143,7 @@ QVariant OneSixVersion::data(const QModelIndex &index, int role) const
int row = index.row();
int column = index.column();
- if (row < 0 || row >= libraries.size())
+ if (row < 0 || row >= versionFiles.size())
return QVariant();
if (role == Qt::DisplayRole)
@@ -284,11 +151,9 @@ QVariant OneSixVersion::data(const QModelIndex &index, int role) const
switch (column)
{
case 0:
- return libraries[row]->name();
+ return versionFiles.at(row).name;
case 1:
- return libraries[row]->type();
- case 2:
- return libraries[row]->version();
+ return versionFiles.at(row).version;
default:
return QVariant();
}
@@ -296,45 +161,61 @@ QVariant OneSixVersion::data(const QModelIndex &index, int role) const
return QVariant();
}
-Qt::ItemFlags OneSixVersion::flags(const QModelIndex &index) const
+QVariant OneSixVersion::headerData(int section, Qt::Orientation orientation, int role) const
{
- if (!index.isValid())
- return Qt::NoItemFlags;
- int row = index.row();
- if (libraries[row]->isActive())
- {
- return Qt::ItemIsSelectable | Qt::ItemIsEnabled | Qt::ItemNeverHasChildren;
- }
- else
+ if (orientation == Qt::Horizontal)
{
- return Qt::ItemNeverHasChildren;
+ if (role == Qt::DisplayRole)
+ {
+ switch (section)
+ {
+ case 0:
+ return tr("Name");
+ case 1:
+ return tr("Version");
+ default:
+ return QVariant();
+ }
+ }
}
- // return QAbstractListModel::flags(index);
+ return QVariant();
}
-QVariant OneSixVersion::headerData(int section, Qt::Orientation orientation, int role) const
+Qt::ItemFlags OneSixVersion::flags(const QModelIndex &index) const
{
- if (role != Qt::DisplayRole || orientation != Qt::Horizontal)
- return QVariant();
- switch (section)
- {
- case 0:
- return QString("Name");
- case 1:
- return QString("Type");
- case 2:
- return QString("Version");
- default:
- return QString();
- }
+ if (!index.isValid())
+ return Qt::NoItemFlags;
+ return Qt::ItemIsSelectable | Qt::ItemIsEnabled;
}
int OneSixVersion::rowCount(const QModelIndex &parent) const
{
- return libraries.size();
+ return versionFiles.size();
}
int OneSixVersion::columnCount(const QModelIndex &parent) const
{
- return 3;
+ return 2;
+}
+
+QDebug operator<<(QDebug &dbg, const OneSixVersion *version)
+{
+ version->dump();
+ return dbg.maybeSpace();
+}
+QDebug operator<<(QDebug &dbg, const OneSixLibrary *library)
+{
+ dbg.nospace() << "OneSixLibrary("
+ << "\n\t\t\trawName=" << library->rawName()
+ << "\n\t\t\tname=" << library->name()
+ << "\n\t\t\tversion=" << library->version()
+ << "\n\t\t\ttype=" << library->type()
+ << "\n\t\t\tisActive=" << library->isActive()
+ << "\n\t\t\tisNative=" << library->isNative()
+ << "\n\t\t\tdownloadUrl=" << library->downloadUrl()
+ << "\n\t\t\tstoragePath=" << library->storagePath()
+ << "\n\t\t\tabsolutePath=" << library->absoluteUrl()
+ << "\n\t\t\thint=" << library->hint();
+ dbg.nospace() << "\n\t\t)";
+ return dbg.maybeSpace();
}
diff --git a/logic/OneSixVersion.h b/logic/OneSixVersion.h
index 036f3d53..ba7695d5 100644
--- a/logic/OneSixVersion.h
+++ b/logic/OneSixVersion.h
@@ -14,40 +14,50 @@
*/
#pragma once
-#include <QtCore>
+
+#include <QAbstractListModel>
+
+#include <QString>
+#include <QList>
#include <memory>
-class OneSixLibrary;
+#include "OneSixLibrary.h"
+
+class OneSixInstance;
class OneSixVersion : public QAbstractListModel
{
- // Things required to implement the Qt list model
+ Q_OBJECT
public:
+ explicit OneSixVersion(OneSixInstance *instance, QObject *parent = 0);
+
virtual QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const;
+ virtual QVariant headerData(int section, Qt::Orientation orientation, int role) const;
virtual int rowCount(const QModelIndex &parent = QModelIndex()) const;
- virtual QVariant headerData(int section, Qt::Orientation orientation,
- int role = Qt::DisplayRole) const;
virtual int columnCount(const QModelIndex &parent) const;
virtual Qt::ItemFlags flags(const QModelIndex &index) const;
- // serialization/deserialization
-public:
- bool toOriginalFile();
- static std::shared_ptr<OneSixVersion> fromJson(QJsonObject root);
- static std::shared_ptr<OneSixVersion> fromFile(QString filepath);
+ bool reload(QWidget *widgetParent, const bool onlyVanilla = false);
+ void clear();
+
+ void dump() const;
+
+ bool canRemove(const int index) const;
+
+ QString versionFileId(const int index) const;
+
+public
+slots:
+ bool remove(const int index);
public:
QList<std::shared_ptr<OneSixLibrary>> getActiveNormalLibs();
QList<std::shared_ptr<OneSixLibrary>> getActiveNativeLibs();
- // called when something starts/stops messing with the object
- // FIXME: these are ugly in every possible way.
- void externalUpdateStart();
- void externalUpdateFinish();
+
+ static std::shared_ptr<OneSixVersion> fromJson(const QJsonObject &obj);
// data members
public:
- /// file this was read from. blank, if none
- QString original_file;
/// the ID - determines which jar to use! ACTUALLY IMPORTANT!
QString id;
/// Last updated time - as a string
@@ -76,6 +86,10 @@ public:
*/
int minimumLauncherVersion = 0xDEADBEEF;
/**
+ * A list of all tweaker classes
+ */
+ QStringList tweakers;
+ /**
* The main class to load first
*/
QString mainClass;
@@ -103,4 +117,21 @@ public:
}
*/
// QList<Rule> rules;
+
+ struct VersionFile
+ {
+ QString name;
+ QString id;
+ QString version;
+ QString mcVersion;
+ QString filename;
+ int order;
+ };
+ QList<VersionFile> versionFiles;
+
+private:
+ OneSixInstance *m_instance;
};
+
+QDebug operator<<(QDebug &dbg, const OneSixVersion *version);
+QDebug operator<<(QDebug &dbg, const OneSixLibrary *library);
diff --git a/logic/OneSixVersionBuilder.cpp b/logic/OneSixVersionBuilder.cpp
new file mode 100644
index 00000000..bbd33ddc
--- /dev/null
+++ b/logic/OneSixVersionBuilder.cpp
@@ -0,0 +1,1077 @@
+/* Copyright 2013 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 "OneSixVersionBuilder.h"
+
+#include <QList>
+#include <QJsonObject>
+#include <QJsonArray>
+#include <QJsonDocument>
+#include <QFile>
+#include <QFileInfo>
+#include <QMessageBox>
+#include <QObject>
+#include <QDir>
+#include <QDebug>
+
+#include "OneSixVersion.h"
+#include "OneSixInstance.h"
+#include "OneSixRule.h"
+#include "modutils.h"
+#include "logger/QsLog.h"
+
+struct VersionFile
+{
+ int order;
+ QString name;
+ QString fileId;
+ QString version;
+ // TODO use the mcVersion to determine if a version file should be removed on update
+ QString mcVersion;
+ QString filename;
+ // TODO requirements
+ // QMap<QString, QString> requirements;
+ QString id;
+ QString mainClass;
+ QString overwriteMinecraftArguments;
+ QString addMinecraftArguments;
+ QString removeMinecraftArguments;
+ QString processArguments;
+ QString type;
+ QString releaseTime;
+ QString time;
+ QString assets;
+ int minimumLauncherVersion = -1;
+
+ bool shouldOverwriteTweakers = false;
+ QStringList overwriteTweakers;
+ QStringList addTweakers;
+ QStringList removeTweakers;
+
+ struct Library
+ {
+ QString name;
+ QString url;
+ QString hint;
+ QString absoluteUrl;
+ bool applyExcludes = false;
+ QStringList excludes;
+ bool applyNatives = false;
+ QList<QPair<OpSys, QString>> natives;
+ bool applyRules = false;
+ QList<std::shared_ptr<Rule>> rules;
+
+ // user for '+' libraries
+ enum InsertType
+ {
+ Apply,
+ Append,
+ Prepend,
+ Replace
+ };
+ InsertType insertType = Append;
+ QString insertData;
+ enum DependType
+ {
+ Soft,
+ Hard
+ };
+ DependType dependType = Soft;
+ };
+ bool shouldOverwriteLibs = false;
+ QList<Library> overwriteLibs;
+ QList<Library> addLibs;
+ QList<QString> removeLibs;
+
+ static Library fromLibraryJson(const QJsonObject &libObj, const QString &filename,
+ bool &isError)
+ {
+ isError = true;
+ Library out;
+ if (!libObj.contains("name"))
+ {
+ QLOG_ERROR() << filename << "contains a library that doesn't have a 'name' field";
+ return out;
+ }
+ out.name = libObj.value("name").toString();
+
+ auto readString = [libObj, filename](const QString &key, QString &variable)
+ {
+ if (libObj.contains(key))
+ {
+ QJsonValue val = libObj.value(key);
+ if (!val.isString())
+ {
+ QLOG_WARN() << key << "is not a string in" << filename << "(skipping)";
+ }
+ else
+ {
+ variable = val.toString();
+ }
+ }
+ };
+
+ readString("url", out.url);
+ readString("MMC-hint", out.hint);
+ readString("MMC-absulute_url", out.absoluteUrl);
+ readString("MMC-absoluteUrl", out.absoluteUrl);
+ if (libObj.contains("extract"))
+ {
+ if (!libObj.value("extract").isObject())
+ {
+ QLOG_ERROR()
+ << filename
+ << "contains a library with an 'extract' field that's not an object";
+ return out;
+ }
+ QJsonObject extractObj = libObj.value("extract").toObject();
+ if (!extractObj.contains("exclude") || !extractObj.value("exclude").isArray())
+ {
+ QLOG_ERROR() << filename
+ << "contains a library with an invalid 'extract' field";
+ return out;
+ }
+ out.applyExcludes = true;
+ QJsonArray excludeArray = extractObj.value("exclude").toArray();
+ for (auto excludeVal : excludeArray)
+ {
+ if (!excludeVal.isString())
+ {
+ QLOG_WARN() << filename << "contains a library that contains an 'extract' "
+ "field that contains an invalid 'exclude' entry "
+ "(skipping)";
+ }
+ else
+ {
+ out.excludes.append(excludeVal.toString());
+ }
+ }
+ }
+ if (libObj.contains("natives"))
+ {
+ if (!libObj.value("natives").isObject())
+ {
+ QLOG_ERROR()
+ << filename
+ << "contains a library with a 'natives' field that's not an object";
+ return out;
+ }
+ out.applyNatives = true;
+ QJsonObject nativesObj = libObj.value("natives").toObject();
+ for (auto it = nativesObj.begin(); it != nativesObj.end(); ++it)
+ {
+ if (!it.value().isString())
+ {
+ QLOG_WARN() << filename << "contains an invalid native (skipping)";
+ }
+ OpSys opSys = OpSys_fromString(it.key());
+ if (opSys != Os_Other)
+ {
+ out.natives.append(qMakePair(opSys, it.value().toString()));
+ }
+ }
+ }
+ if (libObj.contains("rules"))
+ {
+ out.applyRules = true;
+ out.rules = rulesFromJsonV4(libObj);
+ }
+ isError = false;
+ return out;
+ }
+ static VersionFile fromJson(const QJsonDocument &doc, const QString &filename,
+ const bool requireOrder, bool &isError)
+ {
+ VersionFile out;
+ isError = true;
+ if (doc.isEmpty() || doc.isNull())
+ {
+ QLOG_ERROR() << filename << "is empty or null";
+ return out;
+ }
+ if (!doc.isObject())
+ {
+ QLOG_ERROR() << "The root of" << filename << "is not an object";
+ return out;
+ }
+
+ QJsonObject root = doc.object();
+
+ if (requireOrder)
+ {
+ if (root.contains("order"))
+ {
+ if (root.value("order").isDouble())
+ {
+ out.order = root.value("order").toDouble();
+ }
+ else
+ {
+ QLOG_ERROR() << "'order' field contains an invalid value in" << filename;
+ return out;
+ }
+ }
+ else
+ {
+ QLOG_ERROR() << filename << "doesn't contain an order field";
+ }
+ }
+
+ out.name = root.value("name").toString();
+ out.fileId = root.value("fileId").toString();
+ out.version = root.value("version").toString();
+ out.mcVersion = root.value("mcVersion").toString();
+ out.filename = filename;
+
+ auto readString = [root, filename](const QString &key, QString &variable)
+ {
+ if (root.contains(key))
+ {
+ QJsonValue val = root.value(key);
+ if (!val.isString())
+ {
+ QLOG_WARN() << key << "is not a string in" << filename << "(skipping)";
+ }
+ else
+ {
+ variable = val.toString();
+ }
+ }
+ };
+
+ readString("id", out.id);
+ readString("mainClass", out.mainClass);
+ readString("processArguments", out.processArguments);
+ readString("minecraftArguments", out.overwriteMinecraftArguments);
+ readString("+minecraftArguments", out.addMinecraftArguments);
+ readString("-minecraftArguments", out.removeMinecraftArguments);
+ readString("type", out.type);
+ readString("releaseTime", out.releaseTime);
+ readString("time", out.time);
+ readString("assets", out.assets);
+ if (root.contains("minimumLauncherVersion"))
+ {
+ QJsonValue val = root.value("minimumLauncherVersion");
+ if (!val.isDouble())
+ {
+ QLOG_WARN() << "minimumLauncherVersion is not an int in" << filename
+ << "(skipping)";
+ }
+ else
+ {
+ out.minimumLauncherVersion = val.toDouble();
+ }
+ }
+
+ if (root.contains("tweakers"))
+ {
+ QJsonValue tweakersVal = root.value("tweakers");
+ if (!tweakersVal.isArray())
+ {
+ QLOG_ERROR() << filename
+ << "contains a 'tweakers' field, but it's not an array";
+ return out;
+ }
+ out.shouldOverwriteTweakers = true;
+ QJsonArray tweakers = root.value("tweakers").toArray();
+ for (auto tweakerVal : tweakers)
+ {
+ if (!tweakerVal.isString())
+ {
+ QLOG_ERROR() << filename
+ << "contains a 'tweakers' field entry that's not a string";
+ return out;
+ }
+ out.overwriteTweakers.append(tweakerVal.toString());
+ }
+ }
+ if (root.contains("+tweakers"))
+ {
+ QJsonValue tweakersVal = root.value("+tweakers");
+ if (!tweakersVal.isArray())
+ {
+ QLOG_ERROR() << filename
+ << "contains a '+tweakers' field, but it's not an array";
+ return out;
+ }
+ QJsonArray tweakers = root.value("+tweakers").toArray();
+ for (auto tweakerVal : tweakers)
+ {
+ if (!tweakerVal.isString())
+ {
+ QLOG_ERROR() << filename
+ << "contains a '+tweakers' field entry that's not a string";
+ return out;
+ }
+ out.addTweakers.append(tweakerVal.toString());
+ }
+ }
+ if (root.contains("-tweakers"))
+ {
+ QJsonValue tweakersVal = root.value("-tweakers");
+ if (!tweakersVal.isArray())
+ {
+ QLOG_ERROR() << filename
+ << "contains a '-tweakers' field, but it's not an array";
+ return out;
+ }
+ out.shouldOverwriteTweakers = true;
+ QJsonArray tweakers = root.value("-tweakers").toArray();
+ for (auto tweakerVal : tweakers)
+ {
+ if (!tweakerVal.isString())
+ {
+ QLOG_ERROR() << filename
+ << "contains a '-tweakers' field entry that's not a string";
+ return out;
+ }
+ out.removeTweakers.append(tweakerVal.toString());
+ }
+ }
+
+ if (root.contains("libraries"))
+ {
+ out.shouldOverwriteLibs = true;
+ QJsonValue librariesVal = root.value("libraries");
+ if (!librariesVal.isArray())
+ {
+ QLOG_ERROR() << filename
+ << "contains a 'libraries' field, but its not an array";
+ return out;
+ }
+ QJsonArray librariesArray = librariesVal.toArray();
+ for (auto libVal : librariesArray)
+ {
+ if (!libVal.isObject())
+ {
+ QLOG_ERROR() << filename << "contains a library that's not an object";
+ return out;
+ }
+ QJsonObject libObj = libVal.toObject();
+ bool error;
+ Library lib = fromLibraryJson(libObj, filename, error);
+ if (error)
+ {
+ QLOG_ERROR() << "Error while reading a library entry in" << filename;
+ return out;
+ }
+ out.overwriteLibs.append(lib);
+ }
+ }
+ if (root.contains("+libraries"))
+ {
+ QJsonValue librariesVal = root.value("+libraries");
+ if (!librariesVal.isArray())
+ {
+ QLOG_ERROR() << filename
+ << "contains a '+libraries' field, but its not an array";
+ return out;
+ }
+ QJsonArray librariesArray = librariesVal.toArray();
+ for (auto libVal : librariesArray)
+ {
+ if (!libVal.isObject())
+ {
+ QLOG_ERROR() << filename << "contains a library that's not an object";
+ return out;
+ }
+ QJsonObject libObj = libVal.toObject();
+ bool error;
+ Library lib = fromLibraryJson(libObj, filename, error);
+ if (error)
+ {
+ QLOG_ERROR() << "Error while reading a library entry in" << filename;
+ return out;
+ }
+ if (!libObj.contains("insert"))
+ {
+ QLOG_ERROR() << "Missing 'insert' field in '+libraries' field in"
+ << filename;
+ return out;
+ }
+ QJsonValue insertVal = libObj.value("insert");
+ QString insertString;
+ {
+ if (insertVal.isString())
+ {
+ insertString = insertVal.toString();
+ }
+ else if (insertVal.isObject())
+ {
+ QJsonObject insertObj = insertVal.toObject();
+ if (insertObj.isEmpty())
+ {
+ QLOG_ERROR() << "One library has an empty insert object in"
+ << filename;
+ return out;
+ }
+ insertString = insertObj.keys().first();
+ lib.insertData = insertObj.value(insertString).toString();
+ }
+ }
+ if (insertString == "apply")
+ {
+ lib.insertType = Library::Apply;
+ }
+ else if (insertString == "prepend")
+ {
+ lib.insertType = Library::Prepend;
+ }
+ else if (insertString == "append")
+ {
+ lib.insertType = Library::Prepend;
+ }
+ else if (insertString == "replace")
+ {
+ lib.insertType = Library::Replace;
+ }
+ else
+ {
+ QLOG_ERROR() << "A '+' library in" << filename
+ << "contains an invalid insert type";
+ return out;
+ }
+ if (libObj.contains("MMC-depend") && libObj.value("MMC-depend").isString())
+ {
+ const QString dependString = libObj.value("MMC-depend").toString();
+ if (dependString == "hard")
+ {
+ lib.dependType = Library::Hard;
+ }
+ else if (dependString == "soft")
+ {
+ lib.dependType = Library::Soft;
+ }
+ else
+ {
+ QLOG_ERROR() << "A '+' library in" << filename
+ << "contains an invalid depend type";
+ return out;
+ }
+ }
+ out.addLibs.append(lib);
+ }
+ }
+ if (root.contains("-libraries"))
+ {
+ QJsonValue librariesVal = root.value("-libraries");
+ if (!librariesVal.isArray())
+ {
+ QLOG_ERROR() << filename
+ << "contains a '-libraries' field, but its not an array";
+ return out;
+ }
+ QJsonArray librariesArray = librariesVal.toArray();
+ for (auto libVal : librariesArray)
+ {
+ if (!libVal.isObject())
+ {
+ QLOG_ERROR() << filename << "contains a library that's not an object";
+ return out;
+ }
+ QJsonObject libObj = libVal.toObject();
+ if (!libObj.contains("name"))
+ {
+ QLOG_ERROR() << filename << "contains a library without a name";
+ return out;
+ }
+ if (!libObj.value("name").isString())
+ {
+ QLOG_ERROR() << filename
+ << "contains a library without a valid 'name' field";
+ return out;
+ }
+ out.removeLibs.append(libObj.value("name").toString());
+ }
+ }
+
+ isError = false;
+ return out;
+ }
+
+ static std::shared_ptr<OneSixLibrary> createLibrary(const Library &lib)
+ {
+ std::shared_ptr<OneSixLibrary> out(new OneSixLibrary(lib.name));
+ if (!lib.url.isEmpty())
+ {
+ out->setBaseUrl(lib.url);
+ }
+ out->setHint(lib.hint);
+ if (!lib.absoluteUrl.isEmpty())
+ {
+ out->setAbsoluteUrl(lib.absoluteUrl);
+ }
+ out->setAbsoluteUrl(lib.absoluteUrl);
+ out->extract_excludes = lib.excludes;
+ for (auto native : lib.natives)
+ {
+ out->addNative(native.first, native.second);
+ }
+ out->setRules(lib.rules);
+ out->finalize();
+ return out;
+ }
+ int findLibrary(QList<std::shared_ptr<OneSixLibrary>> haystack, const QString &needle)
+ {
+ for (int i = 0; i < haystack.size(); ++i)
+ {
+ if (QRegExp(needle, Qt::CaseSensitive, QRegExp::WildcardUnix)
+ .indexIn(haystack.at(i)->rawName()) != -1)
+ {
+ return i;
+ }
+ }
+ return -1;
+ }
+ void applyTo(OneSixVersion *version, bool &isError)
+ {
+ isError = true;
+ if (!version->id.isNull() && !mcVersion.isNull())
+ {
+ if (QRegExp(mcVersion, Qt::CaseInsensitive, QRegExp::Wildcard).indexIn(version->id) == -1)
+ {
+ QLOG_ERROR() << filename << "is for a different version of Minecraft";
+ return;
+ }
+ }
+
+ if (!id.isNull())
+ {
+ version->id = id;
+ }
+ if (!mainClass.isNull())
+ {
+ version->mainClass = mainClass;
+ }
+ if (!processArguments.isNull())
+ {
+ version->processArguments = processArguments;
+ }
+ if (!type.isNull())
+ {
+ version->type = type;
+ }
+ if (!releaseTime.isNull())
+ {
+ version->releaseTime = releaseTime;
+ }
+ if (!time.isNull())
+ {
+ version->time = time;
+ }
+ if (!assets.isNull())
+ {
+ version->assets = assets;
+ }
+ if (minimumLauncherVersion >= 0)
+ {
+ version->minimumLauncherVersion = minimumLauncherVersion;
+ }
+ if (!overwriteMinecraftArguments.isNull())
+ {
+ version->minecraftArguments = overwriteMinecraftArguments;
+ }
+ if (!addMinecraftArguments.isNull())
+ {
+ version->minecraftArguments += addMinecraftArguments;
+ }
+ if (!removeMinecraftArguments.isNull())
+ {
+ version->minecraftArguments.remove(removeMinecraftArguments);
+ }
+ if (shouldOverwriteTweakers)
+ {
+ version->tweakers = overwriteTweakers;
+ }
+ for (auto tweaker : addTweakers)
+ {
+ version->tweakers += tweaker;
+ }
+ for (auto tweaker : removeTweakers)
+ {
+ version->tweakers.removeAll(tweaker);
+ }
+ if (shouldOverwriteLibs)
+ {
+ version->libraries.clear();
+ for (auto lib : overwriteLibs)
+ {
+ version->libraries.append(createLibrary(lib));
+ }
+ }
+ for (auto lib : addLibs)
+ {
+ switch (lib.insertType)
+ {
+ case Library::Apply:
+ {
+
+ int index = findLibrary(version->libraries, lib.name);
+ if (index >= 0)
+ {
+ auto library = version->libraries[index];
+ if (!lib.url.isNull())
+ {
+ library->setBaseUrl(lib.url);
+ }
+ if (!lib.hint.isNull())
+ {
+ library->setHint(lib.hint);
+ }
+ if (!lib.absoluteUrl.isNull())
+ {
+ library->setAbsoluteUrl(lib.absoluteUrl);
+ }
+ if (lib.applyExcludes)
+ {
+ library->extract_excludes = lib.excludes;
+ }
+ if (lib.applyNatives)
+ {
+ library->clearSuffixes();
+ for (auto native : lib.natives)
+ {
+ library->addNative(native.first, native.second);
+ }
+ }
+ if (lib.applyRules)
+ {
+ library->setRules(lib.rules);
+ }
+ library->finalize();
+ }
+ else
+ {
+ QLOG_WARN() << "Couldn't find" << lib.insertData << "(skipping)";
+ }
+ break;
+ }
+ case Library::Append:
+ case Library::Prepend:
+ {
+
+ const int startOfVersion = lib.name.lastIndexOf(':') + 1;
+ const int index =
+ findLibrary(version->libraries,
+ QString(lib.name).replace(startOfVersion, INT_MAX, '*'));
+ if (index < 0)
+ {
+ if (lib.insertType == Library::Append)
+ {
+ version->libraries.append(createLibrary(lib));
+ }
+ else
+ {
+ version->libraries.prepend(createLibrary(lib));
+ }
+ }
+ else
+ {
+ auto otherLib = version->libraries.at(index);
+ const Util::Version ourVersion = lib.name.mid(startOfVersion, INT_MAX);
+ const Util::Version otherVersion = otherLib->version();
+ // if the existing version is a hard dependency we can either use it or
+ // fail, but we can't change it
+ if (otherLib->dependType == OneSixLibrary::Hard)
+ {
+ // we need a higher version, or we're hard to and the versions aren't
+ // equal
+ if (ourVersion > otherVersion ||
+ (lib.dependType == Library::Hard && ourVersion != otherVersion))
+ {
+ QLOG_ERROR() << "Error resolving library dependencies between"
+ << otherLib->rawName() << "and" << lib.name << "in"
+ << filename;
+ return;
+ }
+ else
+ {
+ // the library is already existing, so we don't have to do anything
+ }
+ }
+ else if (otherLib->dependType == OneSixLibrary::Soft)
+ {
+ // if we are higher it means we should update
+ if (ourVersion > otherVersion)
+ {
+ auto library = createLibrary(lib);
+ if (Util::Version(otherLib->minVersion) < ourVersion)
+ {
+ library->minVersion = ourVersion.toString();
+ }
+ version->libraries.replace(index, library);
+ }
+ else
+ {
+ // our version is smaller than the existing version, but we require
+ // it: fail
+ if (lib.dependType == Library::Hard)
+ {
+ QLOG_ERROR() << "Error resolving library dependencies between"
+ << otherLib->rawName() << "and" << lib.name << "in"
+ << filename;
+ return;
+ }
+ }
+ }
+ }
+ break;
+ }
+ case Library::Replace:
+ {
+ int index = findLibrary(version->libraries, lib.insertData);
+ if (index >= 0)
+ {
+ version->libraries.replace(index, createLibrary(lib));
+ }
+ else
+ {
+ QLOG_WARN() << "Couldn't find" << lib.insertData << "(skipping)";
+ }
+ break;
+ }
+ }
+ }
+ for (auto lib : removeLibs)
+ {
+ int index = findLibrary(version->libraries, lib);
+ if (index >= 0)
+ {
+ version->libraries.removeAt(index);
+ }
+ else
+ {
+ QLOG_WARN() << "Couldn't find" << lib << "(skipping)";
+ }
+ }
+
+ OneSixVersion::VersionFile versionFile;
+ versionFile.name = name;
+ versionFile.id = fileId;
+ versionFile.version = this->version;
+ versionFile.mcVersion = mcVersion;
+ versionFile.filename = filename;
+ versionFile.order = order;
+ version->versionFiles.append(versionFile);
+
+ isError = false;
+ }
+};
+
+OneSixVersionBuilder::OneSixVersionBuilder()
+{
+}
+
+bool OneSixVersionBuilder::build(OneSixVersion *version, OneSixInstance *instance,
+ QWidget *widgetParent, const bool onlyVanilla)
+{
+ OneSixVersionBuilder builder;
+ builder.m_version = version;
+ builder.m_instance = instance;
+ builder.m_widgetParent = widgetParent;
+ return builder.build(onlyVanilla);
+}
+
+bool OneSixVersionBuilder::read(OneSixVersion *version, const QJsonObject &obj)
+{
+ OneSixVersionBuilder builder;
+ builder.m_version = version;
+ builder.m_instance = 0;
+ builder.m_widgetParent = 0;
+ return builder.read(obj);
+}
+
+bool OneSixVersionBuilder::build(const bool onlyVanilla)
+{
+ m_version->clear();
+
+ QDir root(m_instance->instanceRoot());
+ QDir patches(root.absoluteFilePath("patches/"));
+
+ if (QFile::exists(root.absoluteFilePath("custom.json")))
+ {
+ QLOG_INFO() << "Reading custom.json";
+ VersionFile file;
+ if (!read(QFileInfo(root.absoluteFilePath("custom.json")), false, &file))
+ {
+ return false;
+ }
+ file.name = "custom.json";
+ file.filename = "custom.json";
+ file.fileId = "org.multimc.custom.json";
+ file.version = QString();
+ bool isError = false;
+ file.applyTo(m_version, isError);
+ if (isError)
+ {
+ QMessageBox::critical(
+ m_widgetParent, QObject::tr("Error"),
+ QObject::tr(
+ "Error while applying %1. Please check MultiMC-0.log for more info.")
+ .arg(root.absoluteFilePath("custom.json")));
+ return false;
+ }
+ }
+ else
+ {
+ // version.json -> patches/*.json -> user.json
+
+ // version.json
+ {
+ QLOG_INFO() << "Reading version.json";
+ VersionFile file;
+ if (!read(QFileInfo(root.absoluteFilePath("version.json")), false, &file))
+ {
+ return false;
+ }
+ file.name = "version.json";
+ file.fileId = "org.multimc.version.json";
+ file.version = m_instance->intendedVersionId();
+ file.mcVersion = m_instance->intendedVersionId();
+ bool isError = false;
+ file.applyTo(m_version, isError);
+ if (isError)
+ {
+ QMessageBox::critical(
+ m_widgetParent, QObject::tr("Error"),
+ QObject::tr(
+ "Error while applying %1. Please check MultiMC-0.log for more info.")
+ .arg(root.absoluteFilePath("version.json")));
+ return false;
+ }
+ }
+
+ if (!onlyVanilla)
+ {
+
+ // patches/
+ {
+ // load all, put into map for ordering, apply in the right order
+ QMap<QString, int> overrideOrder = readOverrideOrders(m_instance);
+
+ QMap<int, QPair<QString, VersionFile>> files;
+ for (auto info : patches.entryInfoList(QStringList() << "*.json", QDir::Files))
+ {
+ QLOG_INFO() << "Reading" << info.fileName();
+ VersionFile file;
+ if (!read(info, true, &file))
+ {
+ return false;
+ }
+ if (overrideOrder.contains(file.fileId))
+ {
+ file.order = overrideOrder.value(file.fileId);
+ }
+ if (files.contains(file.order))
+ {
+ QLOG_ERROR() << file.fileId << "has the same order as" << files[file.order].second.fileId;
+ return false;
+ }
+ files.insert(file.order, qMakePair(info.fileName(), file));
+ }
+ for (auto order : files.keys())
+ {
+ QLOG_DEBUG() << "Applying file with order" << order;
+ auto filePair = files[order];
+ bool isError = false;
+ filePair.second.applyTo(m_version, isError);
+ if (isError)
+ {
+ QMessageBox::critical(
+ m_widgetParent, QObject::tr("Error"),
+ QObject::tr("Error while applying %1. Please check MultiMC-0.log "
+ "for more info.").arg(filePair.first));
+ return false;
+ }
+ }
+ }
+
+#if 0
+ // user.json
+ {
+ if (QFile::exists(root.absoluteFilePath("user.json")))
+ {
+ QLOG_INFO() << "Reading user.json";
+ VersionFile file;
+ if (!read(QFileInfo(root.absoluteFilePath("user.json")), false, &file))
+ {
+ return false;
+ }
+ file.name = "user.json";
+ file.fileId = "org.multimc.user.json";
+ file.version = QString();
+ file.mcVersion = QString();
+ bool isError = false;
+ file.applyTo(m_version, isError);
+ if (isError)
+ {
+ QMessageBox::critical(
+ m_widgetParent, QObject::tr("Error"),
+ QObject::tr(
+ "Error while applying %1. Please check MultiMC-0.log for more info.")
+ .arg(root.absoluteFilePath("user.json")));
+ return false;
+ }
+ }
+ }
+#endif
+ }
+ }
+
+ // some final touches
+ {
+ if (m_version->assets.isEmpty())
+ {
+ m_version->assets = "legacy";
+ }
+ if (m_version->minecraftArguments.isEmpty())
+ {
+ QString toCompare = m_version->processArguments.toLower();
+ if (toCompare == "legacy")
+ {
+ m_version->minecraftArguments = " ${auth_player_name} ${auth_session}";
+ }
+ else if (toCompare == "username_session")
+ {
+ m_version->minecraftArguments =
+ "--username ${auth_player_name} --session ${auth_session}";
+ }
+ else if (toCompare == "username_session_version")
+ {
+ m_version->minecraftArguments = "--username ${auth_player_name} "
+ "--session ${auth_session} "
+ "--version ${profile_name}";
+ }
+ }
+ }
+
+ return true;
+}
+
+bool OneSixVersionBuilder::read(const QJsonObject &obj)
+{
+ m_version->clear();
+
+ bool isError = false;
+ VersionFile file = VersionFile::fromJson(QJsonDocument(obj), QString(), false, isError);
+ if (isError)
+ {
+ QMessageBox::critical(
+ m_widgetParent, QObject::tr("Error"),
+ QObject::tr("Error while reading. Please check MultiMC-0.log for more info."));
+ return false;
+ }
+ file.applyTo(m_version, isError);
+ if (isError)
+ {
+ QMessageBox::critical(
+ m_widgetParent, QObject::tr("Error"),
+ QObject::tr("Error while applying. Please check MultiMC-0.log for more info."));
+ return false;
+ }
+
+ return true;
+}
+
+bool OneSixVersionBuilder::read(const QFileInfo &fileInfo, const bool requireOrder,
+ VersionFile *out)
+{
+ QFile file(fileInfo.absoluteFilePath());
+ if (!file.open(QFile::ReadOnly))
+ {
+ QMessageBox::critical(
+ m_widgetParent, QObject::tr("Error"),
+ QObject::tr("Unable to open %1: %2").arg(file.fileName(), file.errorString()));
+ return false;
+ }
+ QJsonParseError error;
+ QJsonDocument doc = QJsonDocument::fromJson(file.readAll(), &error);
+ if (error.error != QJsonParseError::NoError)
+ {
+ QMessageBox::critical(m_widgetParent, QObject::tr("Error"),
+ QObject::tr("Unable to parse %1: %2 at %3")
+ .arg(file.fileName(), error.errorString())
+ .arg(error.offset));
+ return false;
+ }
+ bool isError = false;
+ *out = VersionFile::fromJson(doc, file.fileName(), requireOrder, isError);
+ if (isError)
+ {
+ QMessageBox::critical(
+ m_widgetParent, QObject::tr("Error"),
+ QObject::tr("Error while reading %1. Please check MultiMC-0.log for more info.")
+ .arg(file.fileName()));
+ ;
+ }
+ return true;
+}
+
+QMap<QString, int> OneSixVersionBuilder::readOverrideOrders(OneSixInstance *instance)
+{
+ QMap<QString, int> out;
+ if (QDir(instance->instanceRoot()).exists("order.json"))
+ {
+ QFile orderFile(instance->instanceRoot() + "/order.json");
+ if (!orderFile.open(QFile::ReadOnly))
+ {
+ QLOG_ERROR() << "Couldn't open" << orderFile.fileName() << " for reading:" << orderFile.errorString();
+ QLOG_WARN() << "Ignoring overriden order";
+ }
+ else
+ {
+ QJsonParseError error;
+ QJsonDocument doc = QJsonDocument::fromJson(orderFile.readAll(), &error);
+ if (error.error != QJsonParseError::NoError || !doc.isObject())
+ {
+ QLOG_ERROR() << "Couldn't parse" << orderFile.fileName() << ":" << error.errorString();
+ QLOG_WARN() << "Ignoring overriden order";
+ }
+ else
+ {
+ QJsonObject obj = doc.object();
+ for (auto it = obj.begin(); it != obj.end(); ++it)
+ {
+ if (it.key().startsWith("org.multimc."))
+ {
+ continue;
+ }
+ out.insert(it.key(), it.value().toDouble());
+ }
+ }
+ }
+ }
+ return out;
+}
+bool OneSixVersionBuilder::writeOverrideOrders(const QMap<QString, int> &order, OneSixInstance *instance)
+{
+ QJsonObject obj;
+ for (auto it = order.cbegin(); it != order.cend(); ++it)
+ {
+ if (it.key().startsWith("org.multimc."))
+ {
+ continue;
+ }
+ obj.insert(it.key(), it.value());
+ }
+ QFile orderFile(instance->instanceRoot() + "/order.json");
+ if (!orderFile.open(QFile::WriteOnly))
+ {
+ QLOG_ERROR() << "Couldn't open" << orderFile.fileName() << "for writing:" << orderFile.errorString();
+ return false;
+ }
+ orderFile.write(QJsonDocument(obj).toJson(QJsonDocument::Indented));
+ return true;
+}
diff --git a/logic/OneSixVersionBuilder.h b/logic/OneSixVersionBuilder.h
new file mode 100644
index 00000000..ab0966df
--- /dev/null
+++ b/logic/OneSixVersionBuilder.h
@@ -0,0 +1,47 @@
+/* Copyright 2013 MultiMC Contributors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <QString>
+#include <QMap>
+
+class OneSixVersion;
+class OneSixInstance;
+class QWidget;
+class QJsonObject;
+class QFileInfo;
+class VersionFile;
+
+class OneSixVersionBuilder
+{
+ OneSixVersionBuilder();
+public:
+ static bool build(OneSixVersion *version, OneSixInstance *instance, QWidget *widgetParent, const bool onlyVanilla);
+ static bool read(OneSixVersion *version, const QJsonObject &obj);
+ static QMap<QString, int> readOverrideOrders(OneSixInstance *instance);
+ static bool writeOverrideOrders(const QMap<QString, int> &order, OneSixInstance *instance);
+
+private:
+ OneSixVersion *m_version;
+ OneSixInstance *m_instance;
+ QWidget *m_widgetParent;
+
+ bool build(const bool onlyVanilla);
+ bool read(const QJsonObject &obj);
+
+ bool read(const QFileInfo &fileInfo, const bool requireOrder, VersionFile *out);
+
+};
diff --git a/logic/lists/InstanceList.cpp b/logic/lists/InstanceList.cpp
index 0d4eab95..cd59e6d6 100644
--- a/logic/lists/InstanceList.cpp
+++ b/logic/lists/InstanceList.cpp
@@ -33,6 +33,7 @@
#include "logic/BaseInstance.h"
#include "logic/InstanceFactory.h"
#include "logger/QsLog.h"
+#include <gui/groupview/GroupView.h>
const static int GROUP_FILE_FORMAT_VERSION = 1;
@@ -46,6 +47,13 @@ InstanceList::InstanceList(const QString &instDir, QObject *parent)
QDir::current().mkpath(m_instDir);
}
+ /*
+ * FIXME HACK: instances sometimes need to be created at launch. They need the versions for
+ * that.
+ *
+ * Remove this. it has no business of reloading the whole list. The instances which
+ * need it should track such events themselves and CHANGE THEIR DATA ONLY!
+ */
connect(MMC->minecraftlist().get(), &MinecraftVersionList::modelReset, this,
&InstanceList::loadList);
}
@@ -96,8 +104,7 @@ QVariant InstanceList::data(const QModelIndex &index, int role) const
return MMC->icons()->getIcon(key);
}
// for now.
- case KCategorizedSortFilterProxyModel::CategorySortRole:
- case KCategorizedSortFilterProxyModel::CategoryDisplayRole:
+ case GroupViewRoles::GroupRole:
{
return pdata->group();
}
@@ -282,16 +289,7 @@ void InstanceList::loadGroupList(QMap<QString, QString> &groupMap)
}
}
-struct FTBRecord
-{
- QString dir;
- QString name;
- QString logo;
- QString mcVersion;
- QString description;
-};
-
-void InstanceList::loadForgeInstances(QMap<QString, QString> groupMap)
+QList<FTBRecord> InstanceList::discoverFTBInstances()
{
QList<FTBRecord> records;
QDir dir = QDir(MMC->settings()->get("FTBLauncherRoot").toString());
@@ -300,18 +298,18 @@ void InstanceList::loadForgeInstances(QMap<QString, QString> groupMap)
{
QLOG_INFO() << "The FTB launcher directory specified does not exist. Please check your "
"settings.";
- return;
+ return records;
}
else if (!dataDir.exists())
{
QLOG_INFO() << "The FTB directory specified does not exist. Please check your settings";
- return;
+ return records;
}
dir.cd("ModPacks");
auto allFiles = dir.entryList(QDir::Readable | QDir::Files, QDir::Name);
- for(auto filename: allFiles)
+ for (auto filename : allFiles)
{
- if(!filename.endsWith(".xml"))
+ if (!filename.endsWith(".xml"))
continue;
auto fpath = dir.absoluteFilePath(filename);
QFile f(fpath);
@@ -331,11 +329,15 @@ void InstanceList::loadForgeInstances(QMap<QString, QString> groupMap)
{
QXmlStreamAttributes attrs = reader.attributes();
FTBRecord record;
- record.dir = attrs.value("dir").toString();
- QDir test(dataDir.absoluteFilePath(record.dir));
- if(!test.exists())
+ record.dirName = attrs.value("dir").toString();
+ record.instanceDir = dataDir.absoluteFilePath(record.dirName);
+ record.templateDir = dir.absoluteFilePath(record.dirName);
+ QDir test(record.instanceDir);
+ if (!test.exists())
continue;
record.name = attrs.value("name").toString();
+ if(record.name.contains("voxel", Qt::CaseInsensitive))
+ continue;
record.logo = attrs.value("logo").toString();
record.mcVersion = attrs.value("mcVersion").toString();
record.description = attrs.value("description").toString();
@@ -353,8 +355,14 @@ void InstanceList::loadForgeInstances(QMap<QString, QString> groupMap)
}
f.close();
}
+ return records;
+}
- if(!records.size())
+void InstanceList::loadFTBInstances(QMap<QString, QString> &groupMap,
+ QList<InstancePtr> &tempList)
+{
+ auto records = discoverFTBInstances();
+ if (!records.size())
{
QLOG_INFO() << "No FTB instances to load.";
return;
@@ -363,20 +371,13 @@ void InstanceList::loadForgeInstances(QMap<QString, QString> groupMap)
// process the records we acquired.
for (auto record : records)
{
- auto instanceDir = dataDir.absoluteFilePath(record.dir);
- QLOG_INFO() << "Loading FTB instance from " << instanceDir;
- auto templateDir = dir.absoluteFilePath(record.dir);
- if (!QFileInfo(instanceDir).exists())
- {
- continue;
- }
-
+ QLOG_INFO() << "Loading FTB instance from " << record.instanceDir;
QString iconKey = record.logo;
iconKey.remove(QRegularExpression("\\..*"));
- MMC->icons()->addIcon(iconKey, iconKey, PathCombine(templateDir, record.logo),
+ MMC->icons()->addIcon(iconKey, iconKey, PathCombine(record.templateDir, record.logo),
MMCIcon::Transient);
- if (!QFileInfo(PathCombine(instanceDir, "instance.cfg")).exists())
+ if (!QFileInfo(PathCombine(record.instanceDir, "instance.cfg")).exists())
{
QLOG_INFO() << "Converting " << record.name << " as new.";
BaseInstance *instPtr = NULL;
@@ -384,12 +385,12 @@ void InstanceList::loadForgeInstances(QMap<QString, QString> groupMap)
auto version = MMC->minecraftlist()->findVersion(record.mcVersion);
if (!version)
{
- QLOG_ERROR() << "Can't load instance " << instanceDir
+ QLOG_ERROR() << "Can't load instance " << record.instanceDir
<< " because minecraft version " << record.mcVersion
<< " can't be resolved.";
continue;
}
- auto error = factory.createInstance(instPtr, version, instanceDir,
+ auto error = factory.createInstance(instPtr, version, record.instanceDir,
InstanceFactory::FTBInstance);
if (!instPtr || error != InstanceFactory::NoCreateError)
@@ -400,13 +401,15 @@ void InstanceList::loadForgeInstances(QMap<QString, QString> groupMap)
instPtr->setIconKey(iconKey);
instPtr->setIntendedVersionId(record.mcVersion);
instPtr->setNotes(record.description);
- continueProcessInstance(instPtr, error, instanceDir, groupMap);
+ if(!continueProcessInstance(instPtr, error, record.instanceDir, groupMap))
+ continue;
+ tempList.append(InstancePtr(instPtr));
}
else
{
QLOG_INFO() << "Loading existing " << record.name;
BaseInstance *instPtr = NULL;
- auto error = InstanceFactory::get().loadInstance(instPtr, instanceDir);
+ auto error = InstanceFactory::get().loadInstance(instPtr, record.instanceDir);
if (!instPtr || error != InstanceFactory::NoCreateError)
continue;
instPtr->setGroupInitial("FTB");
@@ -415,7 +418,9 @@ void InstanceList::loadForgeInstances(QMap<QString, QString> groupMap)
if (instPtr->intendedVersionId() != record.mcVersion)
instPtr->setIntendedVersionId(record.mcVersion);
instPtr->setNotes(record.description);
- continueProcessInstance(instPtr, error, instanceDir, groupMap);
+ if(!continueProcessInstance(instPtr, error, record.instanceDir, groupMap))
+ continue;
+ tempList.append(InstancePtr(instPtr));
}
}
}
@@ -426,10 +431,7 @@ InstanceList::InstListError InstanceList::loadList()
QMap<QString, QString> groupMap;
loadGroupList(groupMap);
- beginResetModel();
-
- m_instances.clear();
-
+ QList<InstancePtr> tempList;
{
QDirIterator iter(m_instDir, QDir::Dirs | QDir::NoDot | QDir::NoDotDot | QDir::Readable,
QDirIterator::FollowSymlinks);
@@ -441,15 +443,28 @@ InstanceList::InstListError InstanceList::loadList()
QLOG_INFO() << "Loading MultiMC instance from " << subDir;
BaseInstance *instPtr = NULL;
auto error = InstanceFactory::get().loadInstance(instPtr, subDir);
- continueProcessInstance(instPtr, error, subDir, groupMap);
+ if(!continueProcessInstance(instPtr, error, subDir, groupMap))
+ continue;
+ tempList.append(InstancePtr(instPtr));
}
}
if (MMC->settings()->get("TrackFTBInstances").toBool())
{
- loadForgeInstances(groupMap);
+ loadFTBInstances(groupMap, tempList);
+ }
+ beginResetModel();
+ m_instances.clear();
+ for(auto inst: tempList)
+ {
+ inst->setParent(this);
+ connect(inst.get(), SIGNAL(propertiesChanged(BaseInstance *)), this,
+ SLOT(propertiesChanged(BaseInstance *)));
+ connect(inst.get(), SIGNAL(groupChanged()), this, SLOT(groupChanged()));
+ connect(inst.get(), SIGNAL(nuked(BaseInstance *)), this,
+ SLOT(instanceNuked(BaseInstance *)));
+ m_instances.append(inst);
}
-
endResetModel();
emit dataIsInvalid();
return NoError;
@@ -523,7 +538,7 @@ int InstanceList::getInstIndex(BaseInstance *inst) const
return -1;
}
-void InstanceList::continueProcessInstance(BaseInstance *instPtr, const int error,
+bool InstanceList::continueProcessInstance(BaseInstance *instPtr, const int error,
const QDir &dir, QMap<QString, QString> &groupMap)
{
if (error != InstanceFactory::NoLoadError && error != InstanceFactory::NotAnInstance)
@@ -539,12 +554,14 @@ void InstanceList::continueProcessInstance(BaseInstance *instPtr, const int erro
break;
}
QLOG_ERROR() << errorMsg.toUtf8();
+ return false;
}
else if (!instPtr)
{
QLOG_ERROR() << QString("Error loading instance %1. Instance loader returned null.")
.arg(QFileInfo(dir.absolutePath()).baseName())
.toUtf8();
+ return false;
}
else
{
@@ -554,13 +571,7 @@ void InstanceList::continueProcessInstance(BaseInstance *instPtr, const int erro
instPtr->setGroupInitial((*iter));
}
QLOG_INFO() << "Loaded instance " << instPtr->name() << " from " << dir.absolutePath();
- instPtr->setParent(this);
- m_instances.append(std::shared_ptr<BaseInstance>(instPtr));
- connect(instPtr, SIGNAL(propertiesChanged(BaseInstance *)), this,
- SLOT(propertiesChanged(BaseInstance *)));
- connect(instPtr, SIGNAL(groupChanged()), this, SLOT(groupChanged()));
- connect(instPtr, SIGNAL(nuked(BaseInstance *)), this,
- SLOT(instanceNuked(BaseInstance *)));
+ return true;
}
}
@@ -584,11 +595,8 @@ void InstanceList::propertiesChanged(BaseInstance *inst)
}
}
-InstanceProxyModel::InstanceProxyModel(QObject *parent)
- : KCategorizedSortFilterProxyModel(parent)
+InstanceProxyModel::InstanceProxyModel(QObject *parent) : GroupedProxyModel(parent)
{
- // disable since by default we are globally sorting by date:
- setCategorizedModel(true);
}
bool InstanceProxyModel::subSortLessThan(const QModelIndex &left,
diff --git a/logic/lists/InstanceList.h b/logic/lists/InstanceList.h
index 0ce808e5..ebe3e051 100644
--- a/logic/lists/InstanceList.h
+++ b/logic/lists/InstanceList.h
@@ -18,7 +18,7 @@
#include <QObject>
#include <QAbstractListModel>
#include <QSet>
-#include "categorizedsortfilterproxymodel.h"
+#include <gui/groupview/GroupedProxyModel.h>
#include <QIcon>
#include "logic/BaseInstance.h"
@@ -27,11 +27,24 @@ class BaseInstance;
class QDir;
+struct FTBRecord
+{
+ QString dirName;
+ QString name;
+ QString logo;
+ QString mcVersion;
+ QString description;
+ QString instanceDir;
+ QString templateDir;
+};
+
class InstanceList : public QAbstractListModel
{
Q_OBJECT
private:
void loadGroupList(QMap<QString, QString> &groupList);
+ QList<FTBRecord> discoverFTBInstances();
+ void loadFTBInstances(QMap<QString, QString> &groupMap, QList<InstancePtr> & tempList);
private
slots:
@@ -109,7 +122,6 @@ slots:
* \brief Loads the instance list. Triggers notifications.
*/
InstListError loadList();
- void loadForgeInstances(QMap<QString, QString> groupMap);
private
slots:
@@ -120,7 +132,7 @@ slots:
private:
int getInstIndex(BaseInstance *inst) const;
- void continueProcessInstance(BaseInstance *instPtr, const int error, const QDir &dir,
+ bool continueProcessInstance(BaseInstance *instPtr, const int error, const QDir &dir,
QMap<QString, QString> &groupMap);
protected:
@@ -129,7 +141,7 @@ protected:
QSet<QString> m_groups;
};
-class InstanceProxyModel : public KCategorizedSortFilterProxyModel
+class InstanceProxyModel : public GroupedProxyModel
{
public:
explicit InstanceProxyModel(QObject *parent = 0);
diff --git a/logic/lists/MinecraftVersionList.cpp b/logic/lists/MinecraftVersionList.cpp
index 91f86df0..ece31e3d 100644
--- a/logic/lists/MinecraftVersionList.cpp
+++ b/logic/lists/MinecraftVersionList.cpp
@@ -60,10 +60,15 @@ bool cmpVersions(BaseVersionPtr first, BaseVersionPtr second)
return left->timestamp > right->timestamp;
}
+void MinecraftVersionList::sortInternal()
+{
+ qSort(m_vlist.begin(), m_vlist.end(), cmpVersions);
+}
+
void MinecraftVersionList::sort()
{
beginResetModel();
- qSort(m_vlist.begin(), m_vlist.end(), cmpVersions);
+ sortInternal();
endResetModel();
}
@@ -85,9 +90,8 @@ void MinecraftVersionList::updateListData(QList<BaseVersionPtr> versions)
beginResetModel();
m_vlist = versions;
m_loaded = true;
+ sortInternal();
endResetModel();
- // NOW SORT!!
- sort();
}
inline QDomElement getDomElementByTagName(QDomElement parent, QString tagname)
diff --git a/logic/lists/MinecraftVersionList.h b/logic/lists/MinecraftVersionList.h
index 82af1009..167f4d11 100644
--- a/logic/lists/MinecraftVersionList.h
+++ b/logic/lists/MinecraftVersionList.h
@@ -29,6 +29,8 @@ class QNetworkReply;
class MinecraftVersionList : public BaseVersionList
{
Q_OBJECT
+private:
+ void sortInternal();
public:
friend class MCVListLoadTask;