Merge branch 'integration_derpstances_groupview' into develop

This commit is contained in:
Petr Mrázek
2014-02-09 20:49:48 +01:00
51 changed files with 3769 additions and 3741 deletions

66
logic/BaseInstaller.cpp Normal file
View File

@ -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/");
}

39
logic/BaseInstaller.h Normal file
View File

@ -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;
};

View File

@ -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;
}

View File

@ -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;
};

View File

@ -24,6 +24,7 @@
#include "OneSixInstance.h"
#include "OneSixFTBInstance.h"
#include "NostalgiaInstance.h"
#include "OneSixInstance.h"
#include "BaseVersion.h"
#include "MinecraftVersion.h"
@ -50,14 +51,14 @@ 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")
{
inst = new LegacyInstance(instDir, m_settings, this);
}
else if (inst_type == "OneSix")
if (inst_type == "OneSix")
{
inst = new OneSixInstance(instDir, m_settings, this);
}
else if (inst_type == "Legacy")
{
inst = new LegacyInstance(instDir, m_settings, this);
}
else if (inst_type == "Nostalgia")
{
inst = new NostalgiaInstance(instDir, m_settings, this);
@ -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());

View File

@ -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);
}
void LiteLoaderInstaller::applyLiteLoader(std::shared_ptr<OneSixVersion> to)
{
QMutableListIterator<std::shared_ptr<OneSixLibrary>> it(to->libraries);
while (it.hasNext())
// liteloader
{
it.next();
if (it.value()->rawName().startsWith("com.mumfrey:liteloader:"))
{
it.remove();
}
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);
}
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);
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))
{
QLOG_ERROR() << "Error opening" << file.fileName() << "for reading:" << file.errorString();
return false;
}
file.write(QJsonDocument(obj).toJson());
file.close();
return true;
}

View File

@ -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;
};

View File

@ -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;

View File

@ -13,32 +13,37 @@
* limitations under the License.
*/
#include "MultiMC.h"
#include "OneSixInstance.h"
#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 "logger/QsLog.h"
#include "logic/assets/AssetsUtils.h"
#include <QIcon>
OneSixInstance::OneSixInstance(const QString &rootDir, SettingsObject *setting_obj,
QObject *parent)
: BaseInstance(new OneSixInstancePrivate(), rootDir, setting_obj, parent)
#include "OneSixInstance_p.h"
#include "OneSixUpdate.h"
#include "OneSixVersion.h"
#include "pathutils.h"
#include "logger/QsLog.h"
#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 *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()
{
if (!versionIsCustom())
{
auto pathCustom = PathCombine(instanceRoot(), "custom.json");
auto pathOrig = PathCombine(instanceRoot(), "version.json");
QFile::copy(pathOrig, pathCustom);
return reloadFullVersion();
}
else
return true;
}
bool OneSixInstance::revertCustomVersion()
{
if (versionIsCustom())
{
auto path = PathCombine(instanceRoot(), "custom.json");
QFile::remove(path);
return reloadFullVersion();
}
else
return true;
}
bool OneSixInstance::reloadFullVersion()
bool OneSixInstance::reloadVersion(QWidget *widgetParent)
{
I_D(OneSixInstance);
QString verpath = PathCombine(instanceRoot(), "version.json");
bool ret = d->version->reload(widgetParent);
if (ret)
{
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;
ret = d->vanillaVersion->reload(widgetParent, true);
}
emit versionReloaded();
return ret;
}
std::shared_ptr<OneSixVersion> OneSixInstance::getFullVersion()
void OneSixInstance::clearVersion()
{
I_D(OneSixInstance);
d->version->clear();
d->vanillaVersion->clear();
emit versionReloaded();
}
std::shared_ptr<OneSixVersion> OneSixInstance::getFullVersion() const
{
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)";

View File

@ -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);

View File

@ -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;
};
};

View File

@ -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;

View File

@ -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();

View File

@ -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;
}
}

View File

@ -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
{

View File

@ -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 "

View File

@ -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)
#include "OneSixVersionBuilder.h"
OneSixVersion::OneSixVersion(OneSixInstance *instance, QObject *parent)
: QAbstractListModel(parent), m_instance(instance)
{
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();
}
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;
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();
// ADD MORE HERE :D
if (launcher_ver > 0 && launcher_ver <= 13)
return fromJsonV4(root, readVersion);
else
{
return std::shared_ptr<OneSixVersion>();
}
beginResetModel();
bool ret = OneSixVersionBuilder::build(this, m_instance, widgetParent, onlyVanilla);
endResetModel();
return ret;
}
std::shared_ptr<OneSixVersion> OneSixVersion::fromFile(QString filepath)
void OneSixVersion::clear()
{
QFile file(filepath);
if (!file.open(QIODevice::ReadOnly))
{
return std::shared_ptr<OneSixVersion>();
}
auto data = file.readAll();
QJsonParseError jsonError;
QJsonDocument jsonDoc = QJsonDocument::fromJson(data, &jsonError);
if (jsonError.error != QJsonParseError::NoError)
{
return std::shared_ptr<OneSixVersion>();
}
if (!jsonDoc.isObject())
{
return std::shared_ptr<OneSixVersion>();
}
QJsonObject root = jsonDoc.object();
auto version = fromJson(root);
if (version)
version->original_file = filepath;
return version;
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();
}
bool OneSixVersion::toOriginalFile()
void OneSixVersion::dump() const
{
if (original_file.isEmpty())
return false;
QSaveFile file(original_file);
if (!file.open(QIODevice::WriteOnly))
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 false;
qDebug().nospace() << "\n\t\t" << lib.get();
}
// 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)
{
libarray.append(lib->toJson());
}
if (libarray.count())
root.insert("libraries", libarray);
QJsonDocument doc(root);
file.write(doc.toJson());
return file.commit();
qDebug().nospace() << "\n)";
}
QList<std::shared_ptr<OneSixLibrary>> OneSixVersion::getActiveNormalLibs()
bool OneSixVersion::canRemove(const int index) const
{
QList<std::shared_ptr<OneSixLibrary>> output;
if (index < versionFiles.size())
{
return versionFiles.at(index).id != "org.multimc.version.json";
}
return false;
}
QString OneSixVersion::versionFileId(const int index) const
{
if (index < 0 || index >= versionFiles.size())
{
return QString();
}
return versionFiles.at(index).id;
}
bool OneSixVersion::remove(const int index)
{
if (canRemove(index))
{
return QFile::remove(versionFiles.at(index).filename);
}
return false;
}
QList<std::shared_ptr<OneSixLibrary> > OneSixVersion::getActiveNormalLibs()
{
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()
std::shared_ptr<OneSixVersion> OneSixVersion::fromJson(const QJsonObject &obj)
{
beginResetModel();
}
void OneSixVersion::externalUpdateFinish()
{
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();
}
QVariant OneSixVersion::headerData(int section, Qt::Orientation orientation, int role) const
{
if (orientation == Qt::Horizontal)
{
if (role == Qt::DisplayRole)
{
switch (section)
{
case 0:
return tr("Name");
case 1:
return tr("Version");
default:
return QVariant();
}
}
}
return QVariant();
}
Qt::ItemFlags OneSixVersion::flags(const QModelIndex &index) const
{
if (!index.isValid())
return Qt::NoItemFlags;
int row = index.row();
if (libraries[row]->isActive())
{
return Qt::ItemIsSelectable | Qt::ItemIsEnabled | Qt::ItemNeverHasChildren;
}
else
{
return Qt::ItemNeverHasChildren;
}
// return QAbstractListModel::flags(index);
}
QVariant OneSixVersion::headerData(int section, Qt::Orientation orientation, int role) 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();
}
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();
}

View File

@ -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
@ -75,6 +85,10 @@ public:
* writing)
*/
int minimumLauncherVersion = 0xDEADBEEF;
/**
* A list of all tweaker classes
*/
QStringList tweakers;
/**
* The main class to load first
*/
@ -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);

File diff suppressed because it is too large Load Diff

View File

@ -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);
};

View File

@ -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,

View File

@ -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);

View File

@ -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)

View File

@ -29,6 +29,8 @@ class QNetworkReply;
class MinecraftVersionList : public BaseVersionList
{
Q_OBJECT
private:
void sortInternal();
public:
friend class MCVListLoadTask;