diff options
Diffstat (limited to 'meshmc/launcher/minecraft/legacy')
| -rw-r--r-- | meshmc/launcher/minecraft/legacy/LegacyInstance.cpp | 270 | ||||
| -rw-r--r-- | meshmc/launcher/minecraft/legacy/LegacyInstance.h | 172 | ||||
| -rw-r--r-- | meshmc/launcher/minecraft/legacy/LegacyModList.cpp | 150 | ||||
| -rw-r--r-- | meshmc/launcher/minecraft/legacy/LegacyModList.h | 69 | ||||
| -rw-r--r-- | meshmc/launcher/minecraft/legacy/LegacyUpgradeTask.cpp | 151 | ||||
| -rw-r--r-- | meshmc/launcher/minecraft/legacy/LegacyUpgradeTask.h | 49 |
6 files changed, 861 insertions, 0 deletions
diff --git a/meshmc/launcher/minecraft/legacy/LegacyInstance.cpp b/meshmc/launcher/minecraft/legacy/LegacyInstance.cpp new file mode 100644 index 0000000000..c010974481 --- /dev/null +++ b/meshmc/launcher/minecraft/legacy/LegacyInstance.cpp @@ -0,0 +1,270 @@ +/* SPDX-FileCopyrightText: 2026 Project Tick + * SPDX-FileContributor: Project Tick + * SPDX-License-Identifier: GPL-3.0-or-later + * + * MeshMC - A Custom Launcher for Minecraft + * Copyright (C) 2026 Project Tick + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + * + * This file incorporates work covered by the following copyright and + * permission notice: + * + * 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/MeshMCPartLaunch.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; +} diff --git a/meshmc/launcher/minecraft/legacy/LegacyInstance.h b/meshmc/launcher/minecraft/legacy/LegacyInstance.h new file mode 100644 index 0000000000..6edcee96db --- /dev/null +++ b/meshmc/launcher/minecraft/legacy/LegacyInstance.h @@ -0,0 +1,172 @@ +/* SPDX-FileCopyrightText: 2026 Project Tick + * SPDX-FileContributor: Project Tick + * SPDX-License-Identifier: GPL-3.0-or-later + * + * MeshMC - A Custom Launcher for Minecraft + * Copyright (C) 2026 Project Tick + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + * + * This file incorporates work covered by the following copyright and + * permission notice: + * + * 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; +}; diff --git a/meshmc/launcher/minecraft/legacy/LegacyModList.cpp b/meshmc/launcher/minecraft/legacy/LegacyModList.cpp new file mode 100644 index 0000000000..32158bf59e --- /dev/null +++ b/meshmc/launcher/minecraft/legacy/LegacyModList.cpp @@ -0,0 +1,150 @@ +/* SPDX-FileCopyrightText: 2026 Project Tick + * SPDX-FileContributor: Project Tick + * SPDX-License-Identifier: GPL-3.0-or-later + * + * MeshMC - A Custom Launcher for Minecraft + * Copyright (C) 2026 Project Tick + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + * + * This file incorporates work covered by the following copyright and + * permission notice: + * + * 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; +} diff --git a/meshmc/launcher/minecraft/legacy/LegacyModList.h b/meshmc/launcher/minecraft/legacy/LegacyModList.h new file mode 100644 index 0000000000..4a5627e7c8 --- /dev/null +++ b/meshmc/launcher/minecraft/legacy/LegacyModList.h @@ -0,0 +1,69 @@ +/* SPDX-FileCopyrightText: 2026 Project Tick + * SPDX-FileContributor: Project Tick + * SPDX-License-Identifier: GPL-3.0-or-later + * + * MeshMC - A Custom Launcher for Minecraft + * Copyright (C) 2026 Project Tick + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + * + * This file incorporates work covered by the following copyright and + * permission notice: + * + * 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; +}; diff --git a/meshmc/launcher/minecraft/legacy/LegacyUpgradeTask.cpp b/meshmc/launcher/minecraft/legacy/LegacyUpgradeTask.cpp new file mode 100644 index 0000000000..89b3506153 --- /dev/null +++ b/meshmc/launcher/minecraft/legacy/LegacyUpgradeTask.cpp @@ -0,0 +1,151 @@ +/* SPDX-FileCopyrightText: 2026 Project Tick + * SPDX-FileContributor: Project Tick + * SPDX-License-Identifier: GPL-3.0-or-later + * + * MeshMC - A Custom Launcher for Minecraft + * Copyright (C) 2026 Project Tick + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ + +#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", "MeshMCLauncher.jar", "icon.png"}; + removeAll(inst.instanceRoot(), rootRemovables); + removeAll(inst.gameRoot(), mcRemovables); + } + emitSucceeded(); +} + +void LegacyUpgradeTask::copyAborted() +{ + emitFailed(tr("Instance folder copy has been aborted.")); + return; +} diff --git a/meshmc/launcher/minecraft/legacy/LegacyUpgradeTask.h b/meshmc/launcher/minecraft/legacy/LegacyUpgradeTask.h new file mode 100644 index 0000000000..a407cb8df8 --- /dev/null +++ b/meshmc/launcher/minecraft/legacy/LegacyUpgradeTask.h @@ -0,0 +1,49 @@ +/* SPDX-FileCopyrightText: 2026 Project Tick + * SPDX-FileContributor: Project Tick + * SPDX-License-Identifier: GPL-3.0-or-later + * + * MeshMC - A Custom Launcher for Minecraft + * Copyright (C) 2026 Project Tick + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ + +#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; +}; |
