NOISSUE Add back Legacy for migration purposes

This commit is contained in:
Petr Mrázek
2017-09-16 23:09:05 +02:00
parent b2b0487600
commit 9a6c2b0e2c
14 changed files with 821 additions and 4 deletions

View File

@ -24,6 +24,7 @@
#include "multimc_logic_export.h"
class LegacyInstance;
class BaseInstance;
class QFileSystemWatcher;

View File

@ -0,0 +1,313 @@
/* Copyright 2013-2017 MultiMC Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <QFileInfo>
#include <minecraft/launch/LauncherPartLaunch.h>
#include <QDir>
#include <settings/Setting.h>
#include "LegacyInstance.h"
#include "minecraft/legacy/LegacyModList.h"
#include "minecraft/ModList.h"
#include "minecraft/WorldList.h"
#include <MMCZip.h>
#include <FileSystem.h>
LegacyInstance::LegacyInstance(SettingsObjectPtr globalSettings, SettingsObjectPtr settings, const QString &rootDir)
: BaseInstance(globalSettings, settings, rootDir)
{
settings->registerSetting("NeedsRebuild", true);
settings->registerSetting("ShouldUpdate", false);
settings->registerSetting("JarVersion", "Unknown");
settings->registerSetting("IntendedJarVersion", "");
/*
* custom base jar has no default. it is determined in code... see the accessor methods for
*it
*
* for instances that DO NOT have the CustomBaseJar setting (legacy instances),
* [.]minecraft/bin/mcbackup.jar is the default base jar
*/
settings->registerSetting("UseCustomBaseJar", true);
settings->registerSetting("CustomBaseJar", "");
}
QString LegacyInstance::baseJar() const
{
bool customJar = m_settings->get("UseCustomBaseJar").toBool();
if (customJar)
{
return customBaseJar();
}
else
return defaultBaseJar();
}
QString LegacyInstance::customBaseJar() const
{
QString value = m_settings->get("CustomBaseJar").toString();
if (value.isNull() || value.isEmpty())
{
return defaultCustomBaseJar();
}
return value;
}
bool LegacyInstance::shouldUseCustomBaseJar() const
{
return m_settings->get("UseCustomBaseJar").toBool();
}
shared_qobject_ptr<Task> LegacyInstance::createUpdateTask()
{
return nullptr;
}
/*
class LegacyJarModTask : public Task
{
//Q_OBJECT
public:
explicit LegacyJarModTask(std::shared_ptr<LegacyInstance> inst) : Task(nullptr), m_inst(inst)
{
}
virtual void executeTask()
{
if (!m_inst->shouldRebuild())
{
emitSucceeded();
return;
}
// Get the mod list
auto modList = m_inst->getJarMods();
QFileInfo runnableJar(m_inst->runnableJar());
QFileInfo baseJar(m_inst->baseJar());
bool base_is_custom = m_inst->shouldUseCustomBaseJar();
// Nothing to do if there are no jar mods to install, no backup and just the mc jar
if (base_is_custom)
{
// yes, this can happen if the instance only has the runnable jar and not the base jar
// it *could* be assumed that such an instance is vanilla, but that wouldn't be safe
// because that's not something mmc4 guarantees
if (runnableJar.isFile() && !baseJar.exists() && modList.empty())
{
m_inst->setShouldRebuild(false);
emitSucceeded();
return;
}
setStatus(tr("Installing mods: Backing up minecraft.jar ..."));
if (!baseJar.exists() && !QFile::copy(runnableJar.filePath(), baseJar.filePath()))
{
emitFailed("It seems both the active and base jar are gone. A fresh base jar will "
"be used on next run.");
m_inst->setShouldRebuild(true);
m_inst->setShouldUpdate(true);
m_inst->setShouldUseCustomBaseJar(false);
return;
}
}
if (!baseJar.exists())
{
emitFailed("The base jar " + baseJar.filePath() + " does not exist");
return;
}
if (runnableJar.exists() && !QFile::remove(runnableJar.filePath()))
{
emitFailed("Failed to delete old minecraft.jar");
return;
}
setStatus(tr("Installing mods: Opening minecraft.jar ..."));
QString outputJarPath = runnableJar.filePath();
QString inputJarPath = baseJar.filePath();
if(!MMCZip::createModdedJar(inputJarPath, outputJarPath, modList))
{
emitFailed(tr("Failed to create the custom Minecraft jar file."));
return;
}
m_inst->setShouldRebuild(false);
// inst->UpdateVersion(true);
emitSucceeded();
return;
}
std::shared_ptr<LegacyInstance> m_inst;
};
*/
std::shared_ptr<LegacyModList> LegacyInstance::jarModList() const
{
if (!jar_mod_list)
{
auto list = new LegacyModList(jarModsDir(), modListFile());
jar_mod_list.reset(list);
}
jar_mod_list->update();
return jar_mod_list;
}
QList<Mod> LegacyInstance::getJarMods() const
{
return jarModList()->allMods();
}
QString LegacyInstance::minecraftRoot() const
{
QFileInfo mcDir(FS::PathCombine(instanceRoot(), "minecraft"));
QFileInfo dotMCDir(FS::PathCombine(instanceRoot(), ".minecraft"));
if (dotMCDir.exists() && !mcDir.exists())
return dotMCDir.filePath();
else
return mcDir.filePath();
}
QString LegacyInstance::binRoot() const
{
return FS::PathCombine(minecraftRoot(), "bin");
}
QString LegacyInstance::jarModsDir() const
{
return FS::PathCombine(instanceRoot(), "instMods");
}
QString LegacyInstance::libDir() const
{
return FS::PathCombine(minecraftRoot(), "lib");
}
QString LegacyInstance::savesDir() const
{
return FS::PathCombine(minecraftRoot(), "saves");
}
QString LegacyInstance::loaderModsDir() const
{
return FS::PathCombine(minecraftRoot(), "mods");
}
QString LegacyInstance::coreModsDir() const
{
return FS::PathCombine(minecraftRoot(), "coremods");
}
QString LegacyInstance::resourceDir() const
{
return FS::PathCombine(minecraftRoot(), "resources");
}
QString LegacyInstance::texturePacksDir() const
{
return FS::PathCombine(minecraftRoot(), "texturepacks");
}
QString LegacyInstance::runnableJar() const
{
return FS::PathCombine(binRoot(), "minecraft.jar");
}
QString LegacyInstance::modListFile() const
{
return FS::PathCombine(instanceRoot(), "modlist");
}
QString LegacyInstance::instanceConfigFolder() const
{
return FS::PathCombine(minecraftRoot(), "config");
}
bool LegacyInstance::shouldRebuild() const
{
return m_settings->get("NeedsRebuild").toBool();
}
QString LegacyInstance::currentVersionId() const
{
return m_settings->get("JarVersion").toString();
}
QString LegacyInstance::intendedVersionId() const
{
return m_settings->get("IntendedJarVersion").toString();
}
bool LegacyInstance::shouldUpdate() const
{
QVariant var = settings()->get("ShouldUpdate");
if (!var.isValid() || var.toBool() == false)
{
return intendedVersionId() != currentVersionId();
}
return true;
}
QString LegacyInstance::defaultBaseJar() const
{
return "versions/" + intendedVersionId() + "/" + intendedVersionId() + ".jar";
}
QString LegacyInstance::defaultCustomBaseJar() const
{
return FS::PathCombine(binRoot(), "mcbackup.jar");
}
QString LegacyInstance::typeName() const
{
return tr("Legacy");
}
QString LegacyInstance::getStatusbarDescription()
{
return tr("Instance from previous versions.");
}
QStringList LegacyInstance::verboseDescription(AuthSessionPtr session)
{
QStringList out;
auto alltraits = traits();
if(alltraits.size())
{
out << "Traits:";
for (auto trait : alltraits)
{
out << " " + trait;
}
out << "";
}
QString windowParams;
if (settings()->get("LaunchMaximized").toBool())
{
out << "Window size: max (if available)";
}
else
{
auto width = settings()->get("MinecraftWinWidth").toInt();
auto height = settings()->get("MinecraftWinHeight").toInt();
out << "Window size: " + QString::number(width) + " x " + QString::number(height);
}
out << "";
return out;
}

View File

@ -0,0 +1,128 @@
/* Copyright 2013-2017 MultiMC Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#pragma once
#include "BaseInstance.h"
#include "minecraft/Mod.h"
#include "multimc_logic_export.h"
class ModList;
class LegacyModList;
class Task;
/*
* WHY: Legacy instances - from MultiMC 3 and 4 - are here only to provide a way to upgrade them to the current format.
*/
class MULTIMC_LOGIC_EXPORT LegacyInstance : public BaseInstance
{
Q_OBJECT
public:
explicit LegacyInstance(SettingsObjectPtr globalSettings, SettingsObjectPtr settings, const QString &rootDir);
virtual void init() override {};
/// Path to the instance's minecraft.jar
QString runnableJar() const;
//! Path to the instance's modlist file.
QString modListFile() const;
////// Directories //////
QString libDir() const;
QString savesDir() const;
QString texturePacksDir() const;
QString jarModsDir() const;
QString loaderModsDir() const;
QString coreModsDir() const;
QString resourceDir() const;
virtual QString instanceConfigFolder() const override;
QString minecraftRoot() const; // Path to the instance's minecraft directory.
QString binRoot() const; // Path to the instance's minecraft bin directory.
/// Get the curent base jar of this instance. By default, it's the
/// versions/$version/$version.jar
QString baseJar() const;
/// the default base jar of this instance
QString defaultBaseJar() const;
/// the default custom base jar of this instance
QString defaultCustomBaseJar() const;
/*!
* Whether or not custom base jar is used
*/
bool shouldUseCustomBaseJar() const;
/*!
* The value of the custom base jar
*/
QString customBaseJar() const;
std::shared_ptr<LegacyModList> jarModList() const;
QList<Mod> getJarMods() const;
/*!
* Whether or not the instance's minecraft.jar needs to be rebuilt.
* If this is true, when the instance launches, its jar mods will be
* re-added to a fresh minecraft.jar file.
*/
bool shouldRebuild() const;
QString currentVersionId() const;
QString intendedVersionId() const;
QSet<QString> traits() override
{
return {"legacy-instance", "texturepacks"};
};
virtual bool shouldUpdate() const;
virtual shared_qobject_ptr<Task> createUpdateTask() override;
virtual QString typeName() const override;
bool canExport() const override
{
return false;
}
std::shared_ptr<LaunchTask> createLaunchTask(AuthSessionPtr account) override
{
return nullptr;
}
IPathMatcher::Ptr getLogFileMatcher() override
{
return nullptr;
}
QString getLogFileRoot() override
{
return minecraftRoot();
}
QString getStatusbarDescription() override;
QStringList verboseDescription(AuthSessionPtr session) override;
QProcessEnvironment createEnvironment() override
{
return QProcessEnvironment();
}
QMap<QString, QString> getVariables() const override
{
return {};
}
protected:
mutable std::shared_ptr<LegacyModList> jar_mod_list;
};

View File

@ -0,0 +1,171 @@
/* Copyright 2013-2017 MultiMC Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "LegacyModList.h"
#include <FileSystem.h>
#include <QString>
#include <QDebug>
LegacyModList::LegacyModList(const QString &dir, const QString &list_file)
: m_dir(dir), m_list_file(list_file)
{
FS::ensureFolderPathExists(m_dir.absolutePath());
m_dir.setFilter(QDir::Readable | QDir::NoDotAndDotDot | QDir::Files | QDir::Dirs |
QDir::NoSymLinks);
m_dir.setSorting(QDir::Name | QDir::IgnoreCase | QDir::LocaleAware);
}
struct OrderItem
{
QString id;
bool enabled = false;
};
typedef QList<OrderItem> OrderList;
static void internalSort(QList<Mod> &what)
{
auto predicate = [](const Mod &left, const Mod &right)
{
if (left.name() == right.name())
{
return left.mmc_id().localeAwareCompare(right.mmc_id()) < 0;
}
return left.name().localeAwareCompare(right.name()) < 0;
};
std::sort(what.begin(), what.end(), predicate);
}
static OrderList readListFile(const QString &m_list_file)
{
OrderList itemList;
if (m_list_file.isNull() || m_list_file.isEmpty())
return itemList;
QFile textFile(m_list_file);
if (!textFile.open(QIODevice::ReadOnly | QIODevice::Text))
return OrderList();
QTextStream textStream;
textStream.setAutoDetectUnicode(true);
textStream.setDevice(&textFile);
while (true)
{
QString line = textStream.readLine();
if (line.isNull() || line.isEmpty())
break;
else
{
OrderItem it;
it.enabled = !line.endsWith(".disabled");
if (!it.enabled)
{
line.chop(9);
}
it.id = line;
itemList.append(it);
}
}
textFile.close();
return itemList;
}
bool LegacyModList::update()
{
if (!m_dir.exists() || !m_dir.isReadable())
return false;
QList<Mod> orderedMods;
QList<Mod> newMods;
m_dir.refresh();
auto folderContents = m_dir.entryInfoList();
bool orderOrStateChanged = false;
// first, process the ordered items (if any)
OrderList listOrder = readListFile(m_list_file);
for (auto item : listOrder)
{
QFileInfo infoEnabled(m_dir.filePath(item.id));
QFileInfo infoDisabled(m_dir.filePath(item.id + ".disabled"));
int idxEnabled = folderContents.indexOf(infoEnabled);
int idxDisabled = folderContents.indexOf(infoDisabled);
bool isEnabled;
// if both enabled and disabled versions are present, it's a special case...
if (idxEnabled >= 0 && idxDisabled >= 0)
{
// we only process the one we actually have in the order file.
// and exactly as we have it.
// THIS IS A CORNER CASE
isEnabled = item.enabled;
}
else
{
// only one is present.
// we pick the one that we found.
// we assume the mod was enabled/disabled by external means
isEnabled = idxEnabled >= 0;
}
int idx = isEnabled ? idxEnabled : idxDisabled;
QFileInfo &info = isEnabled ? infoEnabled : infoDisabled;
// if the file from the index file exists
if (idx != -1)
{
// remove from the actual folder contents list
folderContents.takeAt(idx);
// append the new mod
orderedMods.append(Mod(info));
if (isEnabled != item.enabled)
orderOrStateChanged = true;
}
else
{
orderOrStateChanged = true;
}
}
// if there are any untracked files...
if (folderContents.size())
{
// the order surely changed!
for (auto entry : folderContents)
{
newMods.append(Mod(entry));
}
internalSort(newMods);
orderedMods.append(newMods);
orderOrStateChanged = true;
}
// otherwise, if we were already tracking some mods
else if (mods.size())
{
// if the number doesn't match, order changed.
if (mods.size() != orderedMods.size())
orderOrStateChanged = true;
// if it does match, compare the mods themselves
else
for (int i = 0; i < mods.size(); i++)
{
if (!mods[i].strongCompare(orderedMods[i]))
{
orderOrStateChanged = true;
break;
}
}
}
mods.swap(orderedMods);
if (orderOrStateChanged && !m_list_file.isEmpty())
{
qDebug() << "Mod list " << m_list_file << " changed!";
}
return true;
}

View File

@ -0,0 +1,56 @@
/* Copyright 2013-2017 MultiMC Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#pragma once
#include <QList>
#include <QString>
#include <QDir>
#include "minecraft/Mod.h"
#include "multimc_logic_export.h"
class LegacyInstance;
class BaseInstance;
/**
* A legacy mod list.
* Backed by a folder.
*/
class MULTIMC_LOGIC_EXPORT LegacyModList
{
public:
LegacyModList(const QString &dir, const QString &list_file = QString());
/// Reloads the mod list and returns true if the list changed.
bool update();
QDir dir()
{
return m_dir;
}
const QList<Mod> & allMods()
{
return mods;
}
protected:
QDir m_dir;
QString m_list_file;
QList<Mod> mods;
};