Merge pull request #192 from Scrumplex/refactor-remove-legacy-instances

Drop legacy instances
This commit is contained in:
Ezekiel Smith 2022-02-26 01:54:15 +11:00 committed by GitHub
commit ccc27d1b7c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
24 changed files with 16 additions and 1253 deletions

View File

@ -39,6 +39,7 @@ BaseInstance::BaseInstance(SettingsObjectPtr globalSettings, SettingsObjectPtr s
m_settings->registerSetting("lastLaunchTime", 0);
m_settings->registerSetting("totalTimePlayed", 0);
m_settings->registerSetting("lastTimePlayed", 0);
m_settings->registerSetting("InstanceType", "OneSix");
// Custom Commands
auto commandSetting = m_settings->registerSetting({"OverrideCommands","OverrideLaunchCmd"}, false);

View File

@ -286,13 +286,6 @@ set(MINECRAFT_SOURCES
minecraft/launch/VerifyJavaInstall.cpp
minecraft/launch/VerifyJavaInstall.h
minecraft/legacy/LegacyModList.h
minecraft/legacy/LegacyModList.cpp
minecraft/legacy/LegacyInstance.h
minecraft/legacy/LegacyInstance.cpp
minecraft/legacy/LegacyUpgradeTask.h
minecraft/legacy/LegacyUpgradeTask.cpp
minecraft/GradleSpecifier.h
minecraft/MinecraftInstance.cpp
minecraft/MinecraftInstance.h
@ -701,8 +694,6 @@ SET(LAUNCHER_SOURCES
ui/pages/instance/OtherLogsPage.h
ui/pages/instance/ServersPage.cpp
ui/pages/instance/ServersPage.h
ui/pages/instance/LegacyUpgradePage.cpp
ui/pages/instance/LegacyUpgradePage.h
ui/pages/instance/WorldListPage.cpp
ui/pages/instance/WorldListPage.h
@ -884,7 +875,6 @@ qt5_wrap_ui(LAUNCHER_UI
ui/pages/instance/InstanceSettingsPage.ui
ui/pages/instance/VersionPage.ui
ui/pages/instance/WorldListPage.ui
ui/pages/instance/LegacyUpgradePage.ui
ui/pages/instance/ScreenshotsPage.ui
ui/pages/modplatform/atlauncher/AtlOptionalModDialog.ui
ui/pages/modplatform/atlauncher/AtlPage.ui

View File

@ -42,7 +42,6 @@ void InstanceCopyTask::copyFinished()
}
// FIXME: shouldn't this be able to report errors?
auto instanceSettings = std::make_shared<INISettingsObject>(FS::PathCombine(m_stagingPath, "instance.cfg"));
instanceSettings->registerSetting("InstanceType", "Legacy");
InstancePtr inst(new NullInstance(m_globalSettings, instanceSettings, m_stagingPath));
inst->setName(m_instName);

View File

@ -17,8 +17,6 @@ void InstanceCreationTask::executeTask()
{
auto instanceSettings = std::make_shared<INISettingsObject>(FS::PathCombine(m_stagingPath, "instance.cfg"));
instanceSettings->suspendSave();
instanceSettings->registerSetting("InstanceType", "Legacy");
instanceSettings->set("InstanceType", "OneSix");
MinecraftInstance inst(m_globalSettings, instanceSettings, m_stagingPath);
auto components = inst.getPackProfile();
components->buildingFromScratch();

View File

@ -261,8 +261,6 @@ void InstanceImportTask::processFlame()
QString configPath = FS::PathCombine(m_stagingPath, "instance.cfg");
auto instanceSettings = std::make_shared<INISettingsObject>(configPath);
instanceSettings->registerSetting("InstanceType", "Legacy");
instanceSettings->set("InstanceType", "OneSix");
MinecraftInstance instance(m_globalSettings, instanceSettings, m_stagingPath);
auto mcVersion = pack.minecraft.version;
// Hack to correct some 'special sauce'...
@ -422,7 +420,6 @@ void InstanceImportTask::processMultiMC()
{
QString configPath = FS::PathCombine(m_stagingPath, "instance.cfg");
auto instanceSettings = std::make_shared<INISettingsObject>(configPath);
instanceSettings->registerSetting("InstanceType", "Legacy");
NullInstance instance(m_globalSettings, instanceSettings, m_stagingPath);

View File

@ -32,7 +32,6 @@
#include "BaseInstance.h"
#include "InstanceTask.h"
#include "settings/INISettingsObject.h"
#include "minecraft/legacy/LegacyInstance.h"
#include "NullInstance.h"
#include "minecraft/MinecraftInstance.h"
#include "FileSystem.h"
@ -545,7 +544,7 @@ InstancePtr InstanceList::loadInstance(const InstanceId& id)
auto instanceSettings = std::make_shared<INISettingsObject>(FS::PathCombine(instanceRoot, "instance.cfg"));
InstancePtr inst;
instanceSettings->registerSetting("InstanceType", "Legacy");
instanceSettings->registerSetting("InstanceType", "Legacy"); // intentionally Legacy. We don't support it.
QString inst_type = instanceSettings->get("InstanceType").toString();
@ -553,10 +552,6 @@ InstancePtr InstanceList::loadInstance(const InstanceId& id)
{
inst.reset(new MinecraftInstance(m_globalSettings, instanceSettings, instanceRoot));
}
else if (inst_type == "Legacy")
{
inst.reset(new LegacyInstance(m_globalSettings, instanceSettings, instanceRoot));
}
else
{
inst.reset(new NullInstance(m_globalSettings, instanceSettings, instanceRoot));

View File

@ -1,6 +1,5 @@
#pragma once
#include "minecraft/MinecraftInstance.h"
#include "minecraft/legacy/LegacyInstance.h"
#include <FileSystem.h>
#include "ui/pages/BasePage.h"
#include "ui/pages/BasePageProvider.h"
@ -14,7 +13,6 @@
#include "ui/pages/instance/ScreenshotsPage.h"
#include "ui/pages/instance/InstanceSettingsPage.h"
#include "ui/pages/instance/OtherLogsPage.h"
#include "ui/pages/instance/LegacyUpgradePage.h"
#include "ui/pages/instance/WorldListPage.h"
#include "ui/pages/instance/ServersPage.h"
#include "ui/pages/instance/GameOptionsPage.h"
@ -34,31 +32,20 @@ public:
QList<BasePage *> values;
values.append(new LogPage(inst));
std::shared_ptr<MinecraftInstance> onesix = std::dynamic_pointer_cast<MinecraftInstance>(inst);
if(onesix)
{
values.append(new VersionPage(onesix.get()));
auto modsPage = new ModFolderPage(onesix.get(), onesix->loaderModList(), "mods", "loadermods", tr("Mods"), "Loader-mods");
modsPage->setFilter("%1 (*.zip *.jar *.litemod)");
values.append(modsPage);
values.append(new CoreModFolderPage(onesix.get(), onesix->coreModList(), "coremods", "coremods", tr("Core mods"), "Core-mods"));
values.append(new ResourcePackPage(onesix.get()));
values.append(new TexturePackPage(onesix.get()));
values.append(new ShaderPackPage(onesix.get()));
values.append(new NotesPage(onesix.get()));
values.append(new WorldListPage(onesix.get(), onesix->worldList()));
values.append(new ServersPage(onesix));
// values.append(new GameOptionsPage(onesix.get()));
values.append(new ScreenshotsPage(FS::PathCombine(onesix->gameRoot(), "screenshots")));
values.append(new InstanceSettingsPage(onesix.get()));
}
std::shared_ptr<LegacyInstance> legacy = std::dynamic_pointer_cast<LegacyInstance>(inst);
if(legacy)
{
values.append(new LegacyUpgradePage(legacy));
values.append(new NotesPage(legacy.get()));
values.append(new WorldListPage(legacy.get(), legacy->worldList()));
values.append(new ScreenshotsPage(FS::PathCombine(legacy->gameRoot(), "screenshots")));
}
values.append(new VersionPage(onesix.get()));
auto modsPage = new ModFolderPage(onesix.get(), onesix->loaderModList(), "mods", "loadermods", tr("Mods"), "Loader-mods");
modsPage->setFilter("%1 (*.zip *.jar *.litemod)");
values.append(modsPage);
values.append(new CoreModFolderPage(onesix.get(), onesix->coreModList(), "coremods", "coremods", tr("Core mods"), "Core-mods"));
values.append(new ResourcePackPage(onesix.get()));
values.append(new TexturePackPage(onesix.get()));
values.append(new ShaderPackPage(onesix.get()));
values.append(new NotesPage(onesix.get()));
values.append(new WorldListPage(onesix.get(), onesix->worldList()));
values.append(new ServersPage(onesix));
// values.append(new GameOptionsPage(onesix.get()));
values.append(new ScreenshotsPage(FS::PathCombine(onesix->gameRoot(), "screenshots")));
values.append(new InstanceSettingsPage(onesix.get()));
auto logMatcher = inst->getLogFileMatcher();
if(logMatcher)
{

View File

@ -124,18 +124,7 @@ MinecraftInstance::MinecraftInstance(SettingsObjectPtr globalSettings, SettingsO
m_settings->registerSetting("JoinServerOnLaunch", false);
m_settings->registerSetting("JoinServerOnLaunchAddress", "");
// DEPRECATED: Read what versions the user configuration thinks should be used
m_settings->registerSetting({"IntendedVersion", "MinecraftVersion"}, "");
m_settings->registerSetting("LWJGLVersion", "");
m_settings->registerSetting("ForgeVersion", "");
m_settings->registerSetting("LiteloaderVersion", "");
m_components.reset(new PackProfile(this));
m_components->setOldConfigVersion("net.minecraft", m_settings->get("IntendedVersion").toString());
auto setting = m_settings->getSetting("LWJGLVersion");
m_components->setOldConfigVersion("org.lwjgl", m_settings->get("LWJGLVersion").toString());
m_components->setOldConfigVersion("net.minecraftforge", m_settings->get("ForgeVersion").toString());
m_components->setOldConfigVersion("com.mumfrey.liteloader", m_settings->get("LiteloaderVersion").toString());
}
void MinecraftInstance::saveNow()

View File

@ -272,18 +272,6 @@ void PackProfile::save_internal()
bool PackProfile::load()
{
auto filename = componentsFilePath();
QFile componentsFile(filename);
// migrate old config to new one, if needed
if(!componentsFile.exists())
{
if(!migratePreComponentConfig())
{
// FIXME: the user should be notified...
qCritical() << "Failed to convert old pre-component config for instance" << d->m_instance->name();
return false;
}
}
// load the new component list and swap it with the current one...
ComponentContainer newComponents;
@ -369,239 +357,6 @@ void PackProfile::updateFailed(const QString& error)
invalidateLaunchProfile();
}
// NOTE this is really old stuff, and only needs to be used when loading the old hardcoded component-unaware format (loadPreComponentConfig).
static void upgradeDeprecatedFiles(QString root, QString instanceName)
{
auto versionJsonPath = FS::PathCombine(root, "version.json");
auto customJsonPath = FS::PathCombine(root, "custom.json");
auto mcJson = FS::PathCombine(root, "patches" , "net.minecraft.json");
QString sourceFile;
QString renameFile;
// convert old crap.
if(QFile::exists(customJsonPath))
{
sourceFile = customJsonPath;
renameFile = versionJsonPath;
}
else if(QFile::exists(versionJsonPath))
{
sourceFile = versionJsonPath;
}
if(!sourceFile.isEmpty() && !QFile::exists(mcJson))
{
if(!FS::ensureFilePathExists(mcJson))
{
qWarning() << "Couldn't create patches folder for" << instanceName;
return;
}
if(!renameFile.isEmpty() && QFile::exists(renameFile))
{
if(!QFile::rename(renameFile, renameFile + ".old"))
{
qWarning() << "Couldn't rename" << renameFile << "to" << renameFile + ".old" << "in" << instanceName;
return;
}
}
auto file = ProfileUtils::parseJsonFile(QFileInfo(sourceFile), false);
ProfileUtils::removeLwjglFromPatch(file);
file->uid = "net.minecraft";
file->version = file->minecraftVersion;
file->name = "Minecraft";
Meta::Require needsLwjgl;
needsLwjgl.uid = "org.lwjgl";
file->requires.insert(needsLwjgl);
if(!ProfileUtils::saveJsonFile(OneSixVersionFormat::versionFileToJson(file), mcJson))
{
return;
}
if(!QFile::rename(sourceFile, sourceFile + ".old"))
{
qWarning() << "Couldn't rename" << sourceFile << "to" << sourceFile + ".old" << "in" << instanceName;
return;
}
}
}
/*
* Migrate old layout to the component based one...
* - Part of the version information is taken from `instance.cfg` (fed to this class from outside).
* - Part is taken from the old order.json file.
* - Part is loaded from loose json files in the instance's `patches` directory.
*/
bool PackProfile::migratePreComponentConfig()
{
// upgrade the very old files from the beginnings of MultiMC 5
upgradeDeprecatedFiles(d->m_instance->instanceRoot(), d->m_instance->name());
QList<ComponentPtr> components;
QSet<QString> loaded;
auto addBuiltinPatch = [&](const QString &uid, bool asDependency, const QString & emptyVersion, const Meta::Require & req, const Meta::Require & conflict)
{
auto jsonFilePath = FS::PathCombine(d->m_instance->instanceRoot(), "patches" , uid + ".json");
auto intendedVersion = d->getOldConfigVersion(uid);
// load up the base minecraft patch
ComponentPtr component;
if(QFile::exists(jsonFilePath))
{
if(intendedVersion.isEmpty())
{
intendedVersion = emptyVersion;
}
auto file = ProfileUtils::parseJsonFile(QFileInfo(jsonFilePath), false);
// fix uid
file->uid = uid;
// if version is missing, add it from the outside.
if(file->version.isEmpty())
{
file->version = intendedVersion;
}
// if this is a dependency (LWJGL), mark it also as volatile
if(asDependency)
{
file->m_volatile = true;
}
// insert requirements if needed
if(!req.uid.isEmpty())
{
file->requires.insert(req);
}
// insert conflicts if needed
if(!conflict.uid.isEmpty())
{
file->conflicts.insert(conflict);
}
// FIXME: @QUALITY do not ignore return value
ProfileUtils::saveJsonFile(OneSixVersionFormat::versionFileToJson(file), jsonFilePath);
component = new Component(this, uid, file);
component->m_version = intendedVersion;
}
else if(!intendedVersion.isEmpty())
{
auto metaVersion = APPLICATION->metadataIndex()->get(uid, intendedVersion);
component = new Component(this, metaVersion);
}
else
{
return;
}
component->m_dependencyOnly = asDependency;
component->m_important = !asDependency;
components.append(component);
};
// TODO: insert depends and conflicts here if these are customized files...
Meta::Require reqLwjgl;
reqLwjgl.uid = "org.lwjgl";
reqLwjgl.suggests = "2.9.1";
Meta::Require conflictLwjgl3;
conflictLwjgl3.uid = "org.lwjgl3";
Meta::Require nullReq;
addBuiltinPatch("org.lwjgl", true, "2.9.1", nullReq, conflictLwjgl3);
addBuiltinPatch("net.minecraft", false, QString(), reqLwjgl, nullReq);
// first, collect all other file-based patches and load them
QMap<QString, ComponentPtr> loadedComponents;
QDir patchesDir(FS::PathCombine(d->m_instance->instanceRoot(),"patches"));
for (auto info : patchesDir.entryInfoList(QStringList() << "*.json", QDir::Files))
{
// parse the file
qDebug() << "Reading" << info.fileName();
auto file = ProfileUtils::parseJsonFile(info, true);
// correct missing or wrong uid based on the file name
QString uid = info.completeBaseName();
// ignore builtins, they've been handled already
if (uid == "net.minecraft")
continue;
if (uid == "org.lwjgl")
continue;
// handle horrible corner cases
if(uid.isEmpty())
{
// if you have a file named '.json', make it just go away.
// FIXME: @QUALITY do not ignore return value
QFile::remove(info.absoluteFilePath());
continue;
}
file->uid = uid;
// FIXME: @QUALITY do not ignore return value
ProfileUtils::saveJsonFile(OneSixVersionFormat::versionFileToJson(file), info.absoluteFilePath());
auto component = new Component(this, file->uid, file);
auto version = d->getOldConfigVersion(file->uid);
if(!version.isEmpty())
{
component->m_version = version;
}
loadedComponents[file->uid] = component;
}
// try to load the other 'hardcoded' patches (forge, liteloader), if they weren't loaded from files
auto loadSpecial = [&](const QString & uid, int order)
{
auto patchVersion = d->getOldConfigVersion(uid);
if(!patchVersion.isEmpty() && !loadedComponents.contains(uid))
{
auto patch = new Component(this, APPLICATION->metadataIndex()->get(uid, patchVersion));
patch->setOrder(order);
loadedComponents[uid] = patch;
}
};
loadSpecial("net.minecraftforge", 5);
loadSpecial("com.mumfrey.liteloader", 10);
// load the old order.json file, if present
ProfileUtils::PatchOrder userOrder;
ProfileUtils::readOverrideOrders(FS::PathCombine(d->m_instance->instanceRoot(), "order.json"), userOrder);
// now add all the patches by user sort order
for (auto uid : userOrder)
{
// ignore builtins
if (uid == "net.minecraft")
continue;
if (uid == "org.lwjgl")
continue;
// ordering has a patch that is gone?
if(!loadedComponents.contains(uid))
{
continue;
}
components.append(loadedComponents.take(uid));
}
// is there anything left to sort? - this is used when there are leftover components that aren't part of the order.json
if(!loadedComponents.isEmpty())
{
// inserting into multimap by order number as key sorts the patches and detects duplicates
QMultiMap<int, ComponentPtr> files;
auto iter = loadedComponents.begin();
while(iter != loadedComponents.end())
{
files.insert((*iter)->getOrder(), *iter);
iter++;
}
// then just extract the patches and put them in the list
for (auto order : files.keys())
{
const auto &values = files.values(order);
for(auto &value: values)
{
// TODO: put back the insertion of problem messages here, so the user knows about the id duplication
components.append(value);
}
}
}
// new we have a complete list of components...
return savePackProfile(componentsFilePath(), components);
}
// END: save/load
void PackProfile::appendComponent(ComponentPtr component)
@ -1169,15 +924,6 @@ std::shared_ptr<LaunchProfile> PackProfile::getProfile() const
return d->m_profile;
}
void PackProfile::setOldConfigVersion(const QString& uid, const QString& version)
{
if(version.isEmpty())
{
return;
}
d->m_oldConfigVersions[uid] = version;
}
bool PackProfile::setComponentVersion(const QString& uid, const QString& version, bool important)
{
auto iter = d->componentIndex.find(uid);

View File

@ -143,8 +143,6 @@ private:
bool installCustomJar_internal(QString filepath);
bool removeComponent_internal(ComponentPtr patch);
bool migratePreComponentConfig();
private: /* data */
std::unique_ptr<PackProfileData> d;

View File

@ -18,18 +18,6 @@ struct PackProfileData
// the launch profile (volatile, temporary thing created on demand)
std::shared_ptr<LaunchProfile> m_profile;
// version information migrated from instance.cfg file. Single use on migration!
std::map<QString, QString> m_oldConfigVersions;
QString getOldConfigVersion(const QString& uid) const
{
const auto iter = m_oldConfigVersions.find(uid);
if(iter != m_oldConfigVersions.cend())
{
return (*iter).second;
}
return QString();
}
// persistent list of components and related machinery
ComponentContainer components;
ComponentIndex componentIndex;

View File

@ -1,256 +0,0 @@
/* Copyright 2013-2021 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/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", QString());
settings->registerSetting("IntendedJarVersion", QString());
/*
* 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::mainJarToPreserve() const
{
bool customJar = m_settings->get("UseCustomBaseJar").toBool();
if(customJar)
{
auto base = baseJar();
if(QFile::exists(base))
{
return base;
}
}
auto runnable = runnableJar();
if(QFile::exists(runnable))
{
return runnable;
}
return QString();
}
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();
}
Task::Ptr LegacyInstance::createUpdateTask(Net::Mode)
{
return nullptr;
}
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;
}
QString LegacyInstance::gameRoot() const
{
QFileInfo mcDir(FS::PathCombine(instanceRoot(), "minecraft"));
QFileInfo dotMCDir(FS::PathCombine(instanceRoot(), ".minecraft"));
if (mcDir.exists() && !dotMCDir.exists())
return mcDir.filePath();
else
return dotMCDir.filePath();
}
QString LegacyInstance::binRoot() const
{
return FS::PathCombine(gameRoot(), "bin");
}
QString LegacyInstance::modsRoot() const {
return FS::PathCombine(gameRoot(), "mods");
}
QString LegacyInstance::jarModsDir() const
{
return FS::PathCombine(instanceRoot(), "instMods");
}
QString LegacyInstance::libDir() const
{
return FS::PathCombine(gameRoot(), "lib");
}
QString LegacyInstance::savesDir() const
{
return FS::PathCombine(gameRoot(), "saves");
}
QString LegacyInstance::coreModsDir() const
{
return FS::PathCombine(gameRoot(), "coremods");
}
QString LegacyInstance::resourceDir() const
{
return FS::PathCombine(gameRoot(), "resources");
}
QString LegacyInstance::texturePacksDir() const
{
return FS::PathCombine(gameRoot(), "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(gameRoot(), "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");
}
std::shared_ptr<WorldList> LegacyInstance::worldList() const
{
if (!m_world_list)
{
m_world_list.reset(new WorldList(savesDir()));
}
return m_world_list;
}
QString LegacyInstance::typeName() const
{
return tr("Legacy");
}
QString LegacyInstance::getStatusbarDescription()
{
return tr("Instance from previous versions.");
}
QStringList LegacyInstance::verboseDescription(AuthSessionPtr session, MinecraftServerTargetPtr serverToJoin)
{
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

@ -1,142 +0,0 @@
/* Copyright 2013-2021 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 "launch/LaunchTask.h"
class ModFolderModel;
class LegacyModList;
class WorldList;
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 LegacyInstance : public BaseInstance
{
Q_OBJECT
public:
explicit LegacyInstance(SettingsObjectPtr globalSettings, SettingsObjectPtr settings, const QString &rootDir);
virtual void saveNow() 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 coreModsDir() const;
QString resourceDir() const;
QString instanceConfigFolder() const override;
QString gameRoot() const override; // Path to the instance's minecraft directory.
QString modsRoot() const override; // 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;
// the main jar that we actually want to keep when migrating the instance
QString mainJarToPreserve() 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;
std::shared_ptr<WorldList> worldList() 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() const override
{
return {"legacy-instance", "texturepacks"};
};
virtual bool shouldUpdate() const;
virtual Task::Ptr createUpdateTask(Net::Mode mode) override;
virtual QString typeName() const override;
bool canLaunch() const override
{
return false;
}
bool canEdit() const override
{
return true;
}
bool canExport() const override
{
return false;
}
shared_qobject_ptr<LaunchTask> createLaunchTask(
AuthSessionPtr account, MinecraftServerTargetPtr serverToJoin) override
{
return nullptr;
}
IPathMatcher::Ptr getLogFileMatcher() override
{
return nullptr;
}
QString getLogFileRoot() override
{
return gameRoot();
}
QString getStatusbarDescription() override;
QStringList verboseDescription(AuthSessionPtr session, MinecraftServerTargetPtr serverToJoin) override;
QProcessEnvironment createEnvironment() override
{
return QProcessEnvironment();
}
QMap<QString, QString> getVariables() const override
{
return {};
}
protected:
mutable std::shared_ptr<LegacyModList> jar_mod_list;
mutable std::shared_ptr<WorldList> m_world_list;
};

View File

@ -1,136 +0,0 @@
/* Copyright 2013-2021 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);
m_dir.setSorting(QDir::Name | QDir::IgnoreCase | QDir::LocaleAware);
}
struct OrderItem
{
QString id;
bool enabled = false;
};
typedef QList<OrderItem> OrderList;
static void internalSort(QList<LegacyModList::Mod> &what)
{
auto predicate = [](const LegacyModList::Mod &left, const LegacyModList::Mod &right)
{
return left.fileName().localeAwareCompare(right.fileName()) < 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();
// 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(info);
}
}
// if there are any untracked files... append them sorted at the end
if (folderContents.size())
{
for (auto entry : folderContents)
{
newMods.append(entry);
}
internalSort(newMods);
orderedMods.append(newMods);
}
mods.swap(orderedMods);
return true;
}

View File

@ -1,47 +0,0 @@
/* Copyright 2013-2021 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>
class LegacyModList
{
public:
using Mod = QFileInfo;
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;
};

View File

@ -1,138 +0,0 @@
#include "LegacyUpgradeTask.h"
#include "settings/INISettingsObject.h"
#include "FileSystem.h"
#include "NullInstance.h"
#include "pathmatcher/RegexpMatcher.h"
#include <QtConcurrentRun>
#include "LegacyInstance.h"
#include "minecraft/MinecraftInstance.h"
#include "minecraft/PackProfile.h"
#include "LegacyModList.h"
#include "classparser.h"
LegacyUpgradeTask::LegacyUpgradeTask(InstancePtr origInstance)
{
m_origInstance = origInstance;
}
void LegacyUpgradeTask::executeTask()
{
setStatus(tr("Copying instance %1").arg(m_origInstance->name()));
FS::copy folderCopy(m_origInstance->instanceRoot(), m_stagingPath);
folderCopy.followSymlinks(true);
m_copyFuture = QtConcurrent::run(QThreadPool::globalInstance(), folderCopy);
connect(&m_copyFutureWatcher, &QFutureWatcher<bool>::finished, this, &LegacyUpgradeTask::copyFinished);
connect(&m_copyFutureWatcher, &QFutureWatcher<bool>::canceled, this, &LegacyUpgradeTask::copyAborted);
m_copyFutureWatcher.setFuture(m_copyFuture);
}
static QString decideVersion(const QString& currentVersion, const QString& intendedVersion)
{
if(intendedVersion != currentVersion)
{
if(!intendedVersion.isEmpty())
{
return intendedVersion;
}
else if(!currentVersion.isEmpty())
{
return currentVersion;
}
}
else
{
if(!intendedVersion.isEmpty())
{
return intendedVersion;
}
}
return QString();
}
void LegacyUpgradeTask::copyFinished()
{
auto successful = m_copyFuture.result();
if(!successful)
{
emitFailed(tr("Instance folder copy failed."));
return;
}
auto legacyInst = std::dynamic_pointer_cast<LegacyInstance>(m_origInstance);
auto instanceSettings = std::make_shared<INISettingsObject>(FS::PathCombine(m_stagingPath, "instance.cfg"));
instanceSettings->registerSetting("InstanceType", "Legacy");
instanceSettings->set("InstanceType", "OneSix");
// NOTE: this scope ensures the instance is fully saved before we emitSucceeded
{
MinecraftInstance inst(m_globalSettings, instanceSettings, m_stagingPath);
inst.setName(m_instName);
QString preferredVersionNumber = decideVersion(legacyInst->currentVersionId(), legacyInst->intendedVersionId());
if(preferredVersionNumber.isNull())
{
// try to decide version based on the jar(s?)
preferredVersionNumber = classparser::GetMinecraftJarVersion(legacyInst->baseJar());
if(preferredVersionNumber.isNull())
{
preferredVersionNumber = classparser::GetMinecraftJarVersion(legacyInst->runnableJar());
if(preferredVersionNumber.isNull())
{
emitFailed(tr("Could not decide Minecraft version."));
return;
}
}
}
auto components = inst.getPackProfile();
components->buildingFromScratch();
components->setComponentVersion("net.minecraft", preferredVersionNumber, true);
QString jarPath = legacyInst->mainJarToPreserve();
if(!jarPath.isNull())
{
qDebug() << "Preserving base jar! : " << jarPath;
// FIXME: handle case when the jar is unreadable?
// TODO: check the hash, if it's the same as the upstream jar, do not do this
components->installCustomJar(jarPath);
}
auto jarMods = legacyInst->jarModList()->allMods();
for(auto & jarMod: jarMods)
{
QString modPath = jarMod.absoluteFilePath();
qDebug() << "jarMod: " << modPath;
components->installJarMods({modPath});
}
// remove all the extra garbage we no longer need
auto removeAll = [&](const QString &root, const QStringList &things)
{
for(auto &thing : things)
{
auto removePath = FS::PathCombine(root, thing);
QFileInfo stat(removePath);
if(stat.isDir())
{
FS::deletePath(removePath);
}
else
{
QFile::remove(removePath);
}
}
};
QStringList rootRemovables = {"modlist", "version", "instMods"};
QStringList mcRemovables = {"bin", "MultiMCLauncher.jar", "icon.png"};
removeAll(inst.instanceRoot(), rootRemovables);
removeAll(inst.gameRoot(), mcRemovables);
}
emitSucceeded();
}
void LegacyUpgradeTask::copyAborted()
{
emitFailed(tr("Instance folder copy has been aborted."));
return;
}

View File

@ -1,29 +0,0 @@
#pragma once
#include "InstanceTask.h"
#include "net/NetJob.h"
#include <QUrl>
#include <QFuture>
#include <QFutureWatcher>
#include "settings/SettingsObject.h"
#include "BaseVersion.h"
#include "BaseInstance.h"
class LegacyUpgradeTask : public InstanceTask
{
Q_OBJECT
public:
explicit LegacyUpgradeTask(InstancePtr origInstance);
protected:
//! Entry point for tasks.
virtual void executeTask() override;
void copyFinished();
void copyAborted();
private: /* data */
InstancePtr m_origInstance;
QFuture<bool> m_copyFuture;
QFutureWatcher<bool> m_copyFutureWatcher;
};

View File

@ -720,8 +720,6 @@ void PackInstallTask::install()
auto instanceConfigPath = FS::PathCombine(m_stagingPath, "instance.cfg");
auto instanceSettings = std::make_shared<INISettingsObject>(instanceConfigPath);
instanceSettings->suspendSave();
instanceSettings->registerSetting("InstanceType", "Legacy");
instanceSettings->set("InstanceType", "OneSix");
MinecraftInstance instance(m_globalSettings, instanceSettings, m_stagingPath);
auto components = instance.getPackProfile();

View File

@ -122,8 +122,6 @@ void PackInstallTask::install()
QString instanceConfigPath = FS::PathCombine(m_stagingPath, "instance.cfg");
auto instanceSettings = std::make_shared<INISettingsObject>(instanceConfigPath);
instanceSettings->suspendSave();
instanceSettings->registerSetting("InstanceType", "Legacy");
instanceSettings->set("InstanceType", "OneSix");
MinecraftInstance instance(m_globalSettings, instanceSettings, m_stagingPath);
auto components = instance.getPackProfile();

View File

@ -181,8 +181,6 @@ void PackInstallTask::install()
auto instanceConfigPath = FS::PathCombine(m_stagingPath, "instance.cfg");
auto instanceSettings = std::make_shared<INISettingsObject>(instanceConfigPath);
instanceSettings->suspendSave();
instanceSettings->registerSetting("InstanceType", "Legacy");
instanceSettings->set("InstanceType", "OneSix");
MinecraftInstance instance(m_globalSettings, instanceSettings, m_stagingPath);
auto components = instance.getPackProfile();

View File

@ -31,8 +31,6 @@ void Technic::TechnicPackProcessor::run(SettingsObjectPtr globalSettings, const
QString minecraftPath = FS::PathCombine(stagingPath, ".minecraft");
QString configPath = FS::PathCombine(stagingPath, "instance.cfg");
auto instanceSettings = std::make_shared<INISettingsObject>(configPath);
instanceSettings->registerSetting("InstanceType", "Legacy");
instanceSettings->set("InstanceType", "OneSix");
MinecraftInstance instance(globalSettings, instanceSettings, stagingPath);
instance.setName(instName);

View File

@ -1,51 +0,0 @@
#include "LegacyUpgradePage.h"
#include "ui_LegacyUpgradePage.h"
#include "InstanceList.h"
#include "minecraft/legacy/LegacyInstance.h"
#include "minecraft/legacy/LegacyUpgradeTask.h"
#include "Application.h"
#include "ui/dialogs/CustomMessageBox.h"
#include "ui/dialogs/ProgressDialog.h"
LegacyUpgradePage::LegacyUpgradePage(InstancePtr inst, QWidget *parent)
: QWidget(parent), ui(new Ui::LegacyUpgradePage), m_inst(inst)
{
ui->setupUi(this);
}
LegacyUpgradePage::~LegacyUpgradePage()
{
delete ui;
}
void LegacyUpgradePage::runModalTask(Task *task)
{
connect(task, &Task::failed, [this](QString reason)
{
CustomMessageBox::selectable(this, tr("Error"), reason, QMessageBox::Warning)->show();
});
ProgressDialog loadDialog(this);
loadDialog.setSkipButton(true, tr("Abort"));
if(loadDialog.execWithTask(task) == QDialog::Accepted)
{
m_container->requestClose();
}
}
void LegacyUpgradePage::on_upgradeButton_clicked()
{
QString newName = tr("%1 (Migrated)").arg(m_inst->name());
auto upgradeTask = new LegacyUpgradeTask(m_inst);
upgradeTask->setName(newName);
upgradeTask->setGroup(APPLICATION->instances()->getInstanceGroup(m_inst->id()));
upgradeTask->setIcon(m_inst->iconKey());
unique_qobject_ptr<Task> task(APPLICATION->instances()->wrapInstanceTask(upgradeTask));
runModalTask(task.get());
}
bool LegacyUpgradePage::shouldDisplay() const
{
return !m_inst->isRunning();
}

View File

@ -1,64 +0,0 @@
/* Copyright 2013-2021 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 <QWidget>
#include "minecraft/legacy/LegacyInstance.h"
#include "ui/pages/BasePage.h"
#include <Application.h>
#include "tasks/Task.h"
namespace Ui
{
class LegacyUpgradePage;
}
class LegacyUpgradePage : public QWidget, public BasePage
{
Q_OBJECT
public:
explicit LegacyUpgradePage(InstancePtr inst, QWidget *parent = 0);
virtual ~LegacyUpgradePage();
virtual QString displayName() const override
{
return tr("Upgrade");
}
virtual QIcon icon() const override
{
return APPLICATION->getThemedIcon("checkupdate");
}
virtual QString id() const override
{
return "upgrade";
}
virtual QString helpPage() const override
{
return "Legacy-upgrade";
}
virtual bool shouldDisplay() const override;
private slots:
void on_upgradeButton_clicked();
private:
void runModalTask(Task *task);
private:
Ui::LegacyUpgradePage *ui;
InstancePtr m_inst;
};

View File

@ -1,54 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>LegacyUpgradePage</class>
<widget class="QWidget" name="LegacyUpgradePage">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>546</width>
<height>405</height>
</rect>
</property>
<layout class="QVBoxLayout" name="verticalLayout_5">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="QTextBrowser" name="textBrowser">
<property name="html">
<string>&lt;!DOCTYPE HTML PUBLIC &quot;-//W3C//DTD HTML 4.0//EN&quot; &quot;http://www.w3.org/TR/REC-html40/strict.dtd&quot;&gt;
&lt;html&gt;&lt;head&gt;&lt;meta name=&quot;qrichtext&quot; content=&quot;1&quot; /&gt;&lt;style type=&quot;text/css&quot;&gt;
p, li { white-space: pre-wrap; }
&lt;/style&gt;&lt;/head&gt;&lt;body style=&quot; font-family:'Noto Sans'; font-size:11pt; font-weight:400; font-style:normal;&quot;&gt;
&lt;h1 style=&quot; margin-top:18px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-size:xx-large; font-weight:600;&quot;&gt;Upgrade is required&lt;/span&gt;&lt;/h1&gt;
&lt;p style=&quot; margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;PolyMC now supports old Minecraft versions and all the required features in the new (OneSix) instance format. As a consequence, the old (Legacy) format has been entirely disabled and old instances need to be upgraded.&lt;/p&gt;
&lt;p style=&quot; margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;The upgrade will create a new instance with the same contents as the current one, in the new format. The original instance will remain untouched, in case anything goes wrong in the process.&lt;/p&gt;
&lt;p style=&quot; margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;Please report any issues on our &lt;a href=&quot;https://github.com/PolyMC/PolyMC/issues&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#3584e4;&quot;&gt;github issues page&lt;/span&gt;&lt;/a&gt;.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="openExternalLinks">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QCommandLinkButton" name="upgradeButton">
<property name="text">
<string>Upgrade the instance</string>
</property>
</widget>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>