aboutsummaryrefslogtreecommitdiff
path: root/launcher
diff options
context:
space:
mode:
Diffstat (limited to 'launcher')
-rw-r--r--launcher/Application.cpp14
-rw-r--r--launcher/Application.h1
-rw-r--r--launcher/BaseInstance.cpp3
-rw-r--r--launcher/BaseInstance.h6
-rw-r--r--launcher/LaunchController.cpp8
-rw-r--r--launcher/MMCTime.cpp7
-rw-r--r--launcher/MMCTime.h2
-rw-r--r--launcher/NullInstance.h2
-rw-r--r--launcher/Version.h20
-rw-r--r--launcher/launch/LogModel.h2
-rw-r--r--launcher/minecraft/ComponentUpdateTask.cpp4
-rw-r--r--launcher/minecraft/MinecraftInstance.cpp72
-rw-r--r--launcher/minecraft/MinecraftInstance.h4
-rw-r--r--launcher/minecraft/PackProfile.cpp36
-rw-r--r--launcher/minecraft/PackProfile.h11
-rw-r--r--launcher/minecraft/auth/AccountList.cpp5
-rw-r--r--launcher/minecraft/mod/ModFolderModel.cpp49
-rw-r--r--launcher/minecraft/mod/ModFolderModel.h2
-rw-r--r--launcher/minecraft/mod/tasks/GetModDependenciesTask.cpp9
-rw-r--r--launcher/minecraft/mod/tasks/GetModDependenciesTask.h2
-rw-r--r--launcher/modplatform/CheckUpdateTask.h4
-rw-r--r--launcher/modplatform/ModIndex.cpp21
-rw-r--r--launcher/modplatform/ModIndex.h14
-rw-r--r--launcher/modplatform/ResourceAPI.h30
-rw-r--r--launcher/modplatform/flame/FileResolvingTask.cpp7
-rw-r--r--launcher/modplatform/flame/FlameAPI.cpp11
-rw-r--r--launcher/modplatform/flame/FlameAPI.h92
-rw-r--r--launcher/modplatform/flame/FlameCheckUpdate.cpp2
-rw-r--r--launcher/modplatform/flame/FlameCheckUpdate.h2
-rw-r--r--launcher/modplatform/flame/FlameModIndex.cpp29
-rw-r--r--launcher/modplatform/flame/FlameModIndex.h2
-rw-r--r--launcher/modplatform/helpers/NetworkResourceAPI.cpp2
-rw-r--r--launcher/modplatform/import_ftb/PackHelpers.cpp8
-rw-r--r--launcher/modplatform/import_ftb/PackHelpers.h2
-rw-r--r--launcher/modplatform/import_ftb/PackInstallTask.cpp12
-rw-r--r--launcher/modplatform/modrinth/ModrinthAPI.cpp4
-rw-r--r--launcher/modplatform/modrinth/ModrinthAPI.h17
-rw-r--r--launcher/modplatform/modrinth/ModrinthCheckUpdate.cpp7
-rw-r--r--launcher/modplatform/modrinth/ModrinthCheckUpdate.h2
-rw-r--r--launcher/modplatform/modrinth/ModrinthPackIndex.cpp36
-rw-r--r--launcher/modplatform/modrinth/ModrinthPackIndex.h7
-rw-r--r--launcher/net/HttpMetaCache.cpp19
-rw-r--r--launcher/ui/InstanceWindow.cpp117
-rw-r--r--launcher/ui/InstanceWindow.h13
-rw-r--r--launcher/ui/MainWindow.cpp149
-rw-r--r--launcher/ui/MainWindow.h13
-rw-r--r--launcher/ui/MainWindow.ui16
-rw-r--r--launcher/ui/dialogs/ModUpdateDialog.cpp6
-rw-r--r--launcher/ui/dialogs/ResourceDownloadDialog.cpp2
-rw-r--r--launcher/ui/pages/global/AccountListPage.cpp5
-rw-r--r--launcher/ui/pages/global/JavaPage.cpp4
-rw-r--r--launcher/ui/pages/global/MinecraftPage.cpp8
-rw-r--r--launcher/ui/pages/global/MinecraftPage.ui26
-rw-r--r--launcher/ui/pages/instance/ExternalResourcesPage.cpp1
-rw-r--r--launcher/ui/pages/instance/InstanceSettingsPage.cpp17
-rw-r--r--launcher/ui/pages/instance/InstanceSettingsPage.ui25
-rw-r--r--launcher/ui/pages/instance/ServersPage.cpp24
-rw-r--r--launcher/ui/pages/instance/VersionPage.cpp9
-rw-r--r--launcher/ui/pages/modplatform/ModModel.cpp4
-rw-r--r--launcher/ui/pages/modplatform/ModPage.cpp3
-rw-r--r--launcher/ui/pages/modplatform/ModPage.h2
-rw-r--r--launcher/ui/pages/modplatform/ShaderPackPage.cpp3
-rw-r--r--launcher/ui/pages/modplatform/flame/FlameResourceModels.cpp2
-rw-r--r--launcher/ui/pages/modplatform/flame/FlameResourcePages.cpp6
-rw-r--r--launcher/ui/pages/modplatform/flame/FlameResourcePages.h2
-rw-r--r--launcher/ui/pages/modplatform/modrinth/ModrinthResourceModels.cpp10
-rw-r--r--launcher/ui/pages/modplatform/modrinth/ModrinthResourcePages.cpp16
-rw-r--r--launcher/ui/pages/modplatform/modrinth/ModrinthResourcePages.h2
-rw-r--r--launcher/ui/widgets/JavaSettingsWidget.cpp27
69 files changed, 524 insertions, 577 deletions
diff --git a/launcher/Application.cpp b/launcher/Application.cpp
index 78de8747..66044d9a 100644
--- a/launcher/Application.cpp
+++ b/launcher/Application.cpp
@@ -9,7 +9,6 @@
* Copyright (C) 2022 Tayou <git@tayou.org>
* Copyright (C) 2023 TheKodeToad <TheKodeToad@proton.me>
* Copyright (C) 2023 Rachel Powers <508861+Ryex@users.noreply.github.com>
- * Copyright (C) 2023 seth <getchoo at tuta dot io>
*
* 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
@@ -580,9 +579,6 @@ Application::Application(int& argc, char** argv) : QApplication(argc, argv)
m_settings->registerSetting("IgnoreJavaCompatibility", false);
m_settings->registerSetting("IgnoreJavaWizard", false);
- // Mod loader settings
- m_settings->registerSetting("DisableQuiltBeacon", false);
-
// Native library workarounds
m_settings->registerSetting("UseNativeOpenAL", false);
m_settings->registerSetting("CustomOpenALPath", "");
@@ -598,6 +594,7 @@ Application::Application(int& argc, char** argv) : QApplication(argc, argv)
m_settings->registerSetting("ShowGameTime", true);
m_settings->registerSetting("ShowGlobalGameTime", true);
m_settings->registerSetting("RecordGameTime", true);
+ m_settings->registerSetting("ShowGameTimeWithoutDays", false);
// Minecraft mods
m_settings->registerSetting("ModMetadataDisabled", false);
@@ -968,7 +965,7 @@ void Application::performMainStartupAction()
qDebug() << " Launching with account" << m_profileToUse;
}
- launch(inst, true, false, nullptr, serverToJoin, accountToUse);
+ launch(inst, true, false, serverToJoin, accountToUse);
return;
}
}
@@ -1067,7 +1064,7 @@ void Application::messageReceived(const QByteArray& message)
}
}
- launch(instance, true, false, nullptr, serverObject, accountObject);
+ launch(instance, true, false, serverObject, accountObject);
} else {
qWarning() << "Received invalid message" << message;
}
@@ -1108,7 +1105,6 @@ bool Application::openJsonEditor(const QString& filename)
bool Application::launch(InstancePtr instance,
bool online,
bool demo,
- BaseProfilerFactory* profiler,
MinecraftServerTargetPtr serverToJoin,
MinecraftAccountPtr accountToUse)
{
@@ -1116,7 +1112,7 @@ bool Application::launch(InstancePtr instance,
qDebug() << "Cannot launch instances while an update is running. Please try again when updates are completed.";
} else if (instance->canLaunch()) {
auto& extras = m_instanceExtras[instance->id()];
- auto& window = extras.window;
+ auto window = extras.window;
if (window) {
if (!window->saveAll()) {
return false;
@@ -1127,7 +1123,7 @@ bool Application::launch(InstancePtr instance,
controller->setInstance(instance);
controller->setOnline(online);
controller->setDemo(demo);
- controller->setProfiler(profiler);
+ controller->setProfiler(profilers().value(instance->settings()->get("Profiler").toString(), nullptr).get());
controller->setServerToJoin(serverToJoin);
controller->setAccountToUse(accountToUse);
if (window) {
diff --git a/launcher/Application.h b/launcher/Application.h
index 29774b1c..b227bb81 100644
--- a/launcher/Application.h
+++ b/launcher/Application.h
@@ -195,7 +195,6 @@ class Application : public QApplication {
bool launch(InstancePtr instance,
bool online = true,
bool demo = false,
- BaseProfilerFactory* profiler = nullptr,
MinecraftServerTargetPtr serverToJoin = nullptr,
MinecraftAccountPtr accountToUse = nullptr);
bool kill(InstancePtr instance);
diff --git a/launcher/BaseInstance.cpp b/launcher/BaseInstance.cpp
index 70c6da6b..72503639 100644
--- a/launcher/BaseInstance.cpp
+++ b/launcher/BaseInstance.cpp
@@ -3,6 +3,7 @@
* Prism Launcher - Minecraft Launcher
* Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
* Copyright (c) 2022 Jamie Mansfield <jmansfield@cadixdev.org>
+ * Copyright (C) 2023 TheKodeToad <TheKodeToad@proton.me>
*
* 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
@@ -100,6 +101,8 @@ BaseInstance::BaseInstance(SettingsObjectPtr globalSettings, SettingsObjectPtr s
m_settings->registerSetting("ManagedPackName", "");
m_settings->registerSetting("ManagedPackVersionID", "");
m_settings->registerSetting("ManagedPackVersionName", "");
+
+ m_settings->registerSetting("Profiler", "");
}
QString BaseInstance::getPreLaunchCommand()
diff --git a/launcher/BaseInstance.h b/launcher/BaseInstance.h
index 38dc7c4a..47fff595 100644
--- a/launcher/BaseInstance.h
+++ b/launcher/BaseInstance.h
@@ -3,6 +3,7 @@
* Prism Launcher - Minecraft Launcher
* Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
* Copyright (c) 2022 Jamie Mansfield <jmansfield@cadixdev.org>
+ * Copyright (C) 2023 TheKodeToad <TheKodeToad@proton.me>
*
* 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
@@ -38,6 +39,7 @@
#include <cassert>
#include <QDateTime>
+#include <QMenu>
#include <QObject>
#include <QProcess>
#include <QSet>
@@ -246,6 +248,8 @@ class BaseInstance : public QObject, public std::enable_shared_from_this<BaseIns
virtual bool canEdit() const = 0;
virtual bool canExport() const = 0;
+ virtual void populateLaunchMenu(QMenu* menu) = 0;
+
bool reloadSettings();
/**
@@ -282,6 +286,8 @@ class BaseInstance : public QObject, public std::enable_shared_from_this<BaseIns
void runningStatusChanged(bool running);
+ void profilerChanged();
+
void statusChanged(Status from, Status to);
protected slots:
diff --git a/launcher/LaunchController.cpp b/launcher/LaunchController.cpp
index 380489e0..b21eb281 100644
--- a/launcher/LaunchController.cpp
+++ b/launcher/LaunchController.cpp
@@ -2,6 +2,7 @@
/*
* Prism Launcher - Minecraft Launcher
* Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
+ * Copyright (C) 2023 TheKodeToad <TheKodeToad@proton.me>
*
* 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
@@ -361,22 +362,21 @@ void LaunchController::readyForLaunch()
QString error;
if (!m_profiler->check(&error)) {
m_launcher->abort();
- QMessageBox::critical(m_parentWidget, tr("Error!"), tr("Couldn't start profiler: %1").arg(error));
emitFailed("Profiler startup failed!");
+ QMessageBox::critical(m_parentWidget, tr("Error!"), tr("Profiler check for %1 failed: %2").arg(m_profiler->name(), error));
return;
}
BaseProfiler* profilerInstance = m_profiler->createProfiler(m_launcher->instance(), this);
connect(profilerInstance, &BaseProfiler::readyToLaunch, [this](const QString& message) {
- QMessageBox msg;
+ QMessageBox msg(m_parentWidget);
msg.setText(tr("The game launch is delayed until you press the "
"button. This is the right time to setup the profiler, as the "
"profiler server is running now.\n\n%1")
.arg(message));
msg.setWindowTitle(tr("Waiting."));
msg.setIcon(QMessageBox::Information);
- msg.addButton(tr("Launch"), QMessageBox::AcceptRole);
- msg.setModal(true);
+ msg.addButton(tr("&Launch"), QMessageBox::AcceptRole);
msg.exec();
m_launcher->proceed();
});
diff --git a/launcher/MMCTime.cpp b/launcher/MMCTime.cpp
index 3972dbd5..1765fd84 100644
--- a/launcher/MMCTime.cpp
+++ b/launcher/MMCTime.cpp
@@ -16,19 +16,20 @@
*/
#include <MMCTime.h>
+#include <qobject.h>
#include <QDateTime>
#include <QObject>
#include <QTextStream>
-QString Time::prettifyDuration(int64_t duration)
+QString Time::prettifyDuration(int64_t duration, bool noDays)
{
int seconds = (int)(duration % 60);
duration /= 60;
int minutes = (int)(duration % 60);
duration /= 60;
- int hours = (int)(duration % 24);
- int days = (int)(duration / 24);
+ int hours = (int)(noDays ? duration : (duration % 24));
+ int days = (int)(noDays ? 0 : (duration / 24));
if ((hours == 0) && (days == 0)) {
return QObject::tr("%1min %2s").arg(minutes).arg(seconds);
}
diff --git a/launcher/MMCTime.h b/launcher/MMCTime.h
index b7d34b5d..ea6d37e7 100644
--- a/launcher/MMCTime.h
+++ b/launcher/MMCTime.h
@@ -20,7 +20,7 @@
namespace Time {
-QString prettifyDuration(int64_t duration);
+QString prettifyDuration(int64_t duration, bool noDays = false);
/**
* @brief Returns a string with short form time duration ie. `2days 1h3m4s56.0ms`.
diff --git a/launcher/NullInstance.h b/launcher/NullInstance.h
index ff658c43..c79600e7 100644
--- a/launcher/NullInstance.h
+++ b/launcher/NullInstance.h
@@ -2,6 +2,7 @@
/*
* Prism Launcher - Minecraft Launcher
* Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
+ * Copyright (C) 2023 TheKodeToad <TheKodeToad@proton.me>
*
* 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
@@ -62,6 +63,7 @@ class NullInstance : public BaseInstance {
bool canExport() const override { return false; }
bool canEdit() const override { return false; }
bool canLaunch() const override { return false; }
+ void populateLaunchMenu(QMenu* menu) override {}
QStringList verboseDescription(AuthSessionPtr session, MinecraftServerTargetPtr serverToJoin) override
{
QStringList out;
diff --git a/launcher/Version.h b/launcher/Version.h
index 92bff9ba..9c043b01 100644
--- a/launcher/Version.h
+++ b/launcher/Version.h
@@ -103,14 +103,8 @@ class Version {
QString m_fullString;
- [[nodiscard]] inline bool isAppendix() const
- {
- return m_stringPart.startsWith('+');
- }
- [[nodiscard]] inline bool isPreRelease() const
- {
- return m_stringPart.startsWith('-') && m_stringPart.length() > 1;
- }
+ [[nodiscard]] inline bool isAppendix() const { return m_stringPart.startsWith('+'); }
+ [[nodiscard]] inline bool isPreRelease() const { return m_stringPart.startsWith('-') && m_stringPart.length() > 1; }
inline bool operator==(const Section& other) const
{
@@ -156,14 +150,8 @@ class Version {
return m_fullString < other.m_fullString;
}
- inline bool operator!=(const Section& other) const
- {
- return !(*this == other);
- }
- inline bool operator>(const Section& other) const
- {
- return !(*this < other || *this == other);
- }
+ inline bool operator!=(const Section& other) const { return !(*this == other); }
+ inline bool operator>(const Section& other) const { return !(*this < other || *this == other); }
};
private:
diff --git a/launcher/launch/LogModel.h b/launcher/launch/LogModel.h
index ba2e4054..18e51d7e 100644
--- a/launcher/launch/LogModel.h
+++ b/launcher/launch/LogModel.h
@@ -30,7 +30,7 @@ class LogModel : public QAbstractListModel {
enum Roles { LevelRole = Qt::UserRole };
- private /* types */:
+ private /* types */:
struct entry {
MessageLevel::Enum level;
QString line;
diff --git a/launcher/minecraft/ComponentUpdateTask.cpp b/launcher/minecraft/ComponentUpdateTask.cpp
index 0b85b81a..bb838043 100644
--- a/launcher/minecraft/ComponentUpdateTask.cpp
+++ b/launcher/minecraft/ComponentUpdateTask.cpp
@@ -2,14 +2,14 @@
#include "Component.h"
#include "ComponentUpdateTask_p.h"
-#include "OneSixVersionFormat.h"
#include "PackProfile.h"
#include "PackProfile_p.h"
#include "Version.h"
#include "cassert"
#include "meta/Index.h"
#include "meta/Version.h"
-#include "meta/VersionList.h"
+#include "minecraft/OneSixVersionFormat.h"
+#include "minecraft/ProfileUtils.h"
#include "net/Mode.h"
#include "Application.h"
diff --git a/launcher/minecraft/MinecraftInstance.cpp b/launcher/minecraft/MinecraftInstance.cpp
index 62d22019..d7dabe07 100644
--- a/launcher/minecraft/MinecraftInstance.cpp
+++ b/launcher/minecraft/MinecraftInstance.cpp
@@ -3,8 +3,7 @@
* Prism Launcher - Minecraft Launcher
* Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
* Copyright (C) 2022 Jamie Mansfield <jmansfield@cadixdev.org>
- * Copyright (C) 2022 TheKodeToad <TheKodeToad@proton.me>
- * Copyright (c) 2023 seth <getchoo at tuta dot io>
+ * Copyright (C) 2023 TheKodeToad <TheKodeToad@proton.me>
*
* 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
@@ -88,6 +87,10 @@
#include "minecraft/gameoptions/GameOptions.h"
#include "minecraft/update/FoldersTask.h"
+#include "tools/BaseProfiler.h"
+
+#include <QActionGroup>
+
#ifdef Q_OS_LINUX
#include "MangoHud.h"
#endif
@@ -181,10 +184,6 @@ void MinecraftInstance::loadSpecificSettings()
m_settings->registerOverride(global_settings->getSetting("CloseAfterLaunch"), miscellaneousOverride);
m_settings->registerOverride(global_settings->getSetting("QuitAfterGameStop"), miscellaneousOverride);
- // Mod loader specific options
- auto modLoaderSettings = m_settings->registerSetting("OverrideModLoaderSettings", false);
- m_settings->registerOverride(global_settings->getSetting("DisableQuiltBeacon"), modLoaderSettings);
-
m_settings->set("InstanceType", "OneSix");
}
@@ -231,6 +230,50 @@ QSet<QString> MinecraftInstance::traits() const
return profile->getTraits();
}
+// FIXME: move UI code out of MinecraftInstance
+void MinecraftInstance::populateLaunchMenu(QMenu* menu)
+{
+ QAction* normalLaunch = menu->addAction(tr("&Launch"));
+ normalLaunch->setShortcut(QKeySequence::Open);
+ QAction* normalLaunchOffline = menu->addAction(tr("Launch &Offline"));
+ normalLaunchOffline->setShortcut(QKeySequence(tr("Ctrl+Shift+O")));
+ QAction* normalLaunchDemo = menu->addAction(tr("Launch &Demo"));
+ normalLaunchDemo->setShortcut(QKeySequence(tr("Ctrl+Alt+O")));
+
+ normalLaunchDemo->setEnabled(supportsDemo());
+
+ connect(normalLaunch, &QAction::triggered, [this] { APPLICATION->launch(shared_from_this()); });
+ connect(normalLaunchOffline, &QAction::triggered, [this] { APPLICATION->launch(shared_from_this(), false, false); });
+ connect(normalLaunchDemo, &QAction::triggered, [this] { APPLICATION->launch(shared_from_this(), false, true); });
+
+ QString profilersTitle = tr("Profilers");
+ menu->addSeparator()->setText(profilersTitle);
+
+ auto profilers = new QActionGroup(menu);
+ profilers->setExclusive(true);
+ connect(profilers, &QActionGroup::triggered, [this](QAction* action) {
+ settings()->set("Profiler", action->data());
+ emit profilerChanged();
+ });
+
+ QAction* noProfilerAction = menu->addAction(tr("&No Profiler"));
+ noProfilerAction->setData("");
+ noProfilerAction->setCheckable(true);
+ noProfilerAction->setChecked(true);
+ profilers->addAction(noProfilerAction);
+
+ for (auto profiler = APPLICATION->profilers().begin(); profiler != APPLICATION->profilers().end(); profiler++) {
+ QAction* profilerAction = menu->addAction(profiler.value()->name());
+ profilers->addAction(profilerAction);
+ profilerAction->setData(profiler.key());
+ profilerAction->setCheckable(true);
+ profilerAction->setChecked(settings()->get("Profiler").toString() == profiler.key());
+
+ QString error;
+ profilerAction->setEnabled(profiler.value()->check(&error));
+ }
+}
+
QString MinecraftInstance::gameRoot() const
{
QFileInfo mcDir(FS::PathCombine(instanceRoot(), "minecraft"));
@@ -387,12 +430,6 @@ QStringList MinecraftInstance::extraArguments()
}
{
- const auto loaders = version->getModLoaders();
- if (loaders.has_value() && loaders.value() & ResourceAPI::Quilt && settings()->get("DisableQuiltBeacon").toBool())
- list.append("-Dloader.disable_beacon=true");
- }
-
- {
QString openALPath;
QString glfwPath;
@@ -897,13 +934,16 @@ QString MinecraftInstance::getStatusbarDescription()
if (m_settings->get("ShowGameTime").toBool()) {
if (lastTimePlayed() > 0) {
QDateTime lastLaunchTime = QDateTime::fromMSecsSinceEpoch(lastLaunch());
- description.append(tr(", last played on %1 for %2")
- .arg(QLocale().toString(lastLaunchTime, QLocale::ShortFormat))
- .arg(Time::prettifyDuration(lastTimePlayed())));
+ description.append(
+ tr(", last played on %1 for %2")
+ .arg(QLocale().toString(lastLaunchTime, QLocale::ShortFormat))
+ .arg(Time::prettifyDuration(lastTimePlayed(), APPLICATION->settings()->get("ShowGameTimeWithoutDays").toBool())));
}
if (totalTimePlayed() > 0) {
- description.append(tr(", total played for %1").arg(Time::prettifyDuration(totalTimePlayed())));
+ description.append(
+ tr(", total played for %1")
+ .arg(Time::prettifyDuration(totalTimePlayed(), APPLICATION->settings()->get("ShowGameTimeWithoutDays").toBool())));
}
}
if (hasCrashed()) {
diff --git a/launcher/minecraft/MinecraftInstance.h b/launcher/minecraft/MinecraftInstance.h
index c331cc6f..dabd44ba 100644
--- a/launcher/minecraft/MinecraftInstance.h
+++ b/launcher/minecraft/MinecraftInstance.h
@@ -2,7 +2,7 @@
/*
* Prism Launcher - Minecraft Launcher
* Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
- * Copyright (C) 2022 TheKodeToad <TheKodeToad@proton.me>
+ * Copyright (C) 2023 TheKodeToad <TheKodeToad@proton.me>
*
* 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
@@ -70,6 +70,8 @@ class MinecraftInstance : public BaseInstance {
bool canExport() const override { return true; }
+ void populateLaunchMenu(QMenu* menu) override;
+
////// Directories and files //////
QString jarModsDir() const;
QString resourcePacksDir() const;
diff --git a/launcher/minecraft/PackProfile.cpp b/launcher/minecraft/PackProfile.cpp
index 92988808..9e42c5dd 100644
--- a/launcher/minecraft/PackProfile.cpp
+++ b/launcher/minecraft/PackProfile.cpp
@@ -58,15 +58,14 @@
#include "ComponentUpdateTask.h"
#include "PackProfile.h"
#include "PackProfile_p.h"
+#include "minecraft/mod/Mod.h"
+#include "modplatform/ModIndex.h"
-#include "Application.h"
-#include "modplatform/ResourceAPI.h"
-
-static const QMap<QString, ResourceAPI::ModLoaderType> modloaderMapping{ { "net.neoforged", ResourceAPI::NeoForge },
- { "net.minecraftforge", ResourceAPI::Forge },
- { "net.fabricmc.fabric-loader", ResourceAPI::Fabric },
- { "org.quiltmc.quilt-loader", ResourceAPI::Quilt },
- { "com.mumfrey.liteloader", ResourceAPI::LiteLoader } };
+static const QMap<QString, ModPlatform::ModLoaderType> modloaderMapping{ { "net.neoforged", ModPlatform::NeoForge },
+ { "net.minecraftforge", ModPlatform::Forge },
+ { "net.fabricmc.fabric-loader", ModPlatform::Fabric },
+ { "org.quiltmc.quilt-loader", ModPlatform::Quilt },
+ { "com.mumfrey.liteloader", ModPlatform::LiteLoader } };
PackProfile::PackProfile(MinecraftInstance* instance) : QAbstractListModel()
{
@@ -990,12 +989,12 @@ void PackProfile::disableInteraction(bool disable)
}
}
-std::optional<ResourceAPI::ModLoaderTypes> PackProfile::getModLoaders()
+std::optional<ModPlatform::ModLoaderTypes> PackProfile::getModLoaders()
{
- ResourceAPI::ModLoaderTypes result;
+ ModPlatform::ModLoaderTypes result;
bool has_any_loader = false;
- QMapIterator<QString, ResourceAPI::ModLoaderType> i(modloaderMapping);
+ QMapIterator<QString, ModPlatform::ModLoaderType> i(modloaderMapping);
while (i.hasNext()) {
i.next();
@@ -1009,3 +1008,18 @@ std::optional<ResourceAPI::ModLoaderTypes> PackProfile::getModLoaders()
return {};
return result;
}
+
+std::optional<ModPlatform::ModLoaderTypes> PackProfile::getSupportedModLoaders()
+{
+ auto loadersOpt = getModLoaders();
+ if (!loadersOpt.has_value())
+ return loadersOpt;
+ auto loaders = loadersOpt.value();
+ // TODO: remove this or add version condition once Quilt drops official Fabric support
+ if (loaders & ModPlatform::Quilt)
+ loaders |= ModPlatform::Fabric;
+ // TODO: remove this or add version condition once NeoForge drops official Forge support
+ if (loaders & ModPlatform::NeoForge)
+ loaders |= ModPlatform::Forge;
+ return loaders;
+}
diff --git a/launcher/minecraft/PackProfile.h b/launcher/minecraft/PackProfile.h
index ce44fa58..e72b6ebf 100644
--- a/launcher/minecraft/PackProfile.h
+++ b/launcher/minecraft/PackProfile.h
@@ -44,14 +44,11 @@
#include <QList>
#include <QString>
#include <memory>
+#include <optional>
-#include "BaseVersion.h"
#include "Component.h"
#include "LaunchProfile.h"
-#include "Library.h"
-#include "MojangDownloadInfo.h"
-#include "ProfileUtils.h"
-#include "modplatform/ResourceAPI.h"
+#include "modplatform/ModIndex.h"
#include "net/Mode.h"
class MinecraftInstance;
@@ -146,7 +143,9 @@ class PackProfile : public QAbstractListModel {
// todo(merged): is this the best approach
void appendComponent(ComponentPtr component);
- std::optional<ResourceAPI::ModLoaderTypes> getModLoaders();
+ std::optional<ModPlatform::ModLoaderTypes> getModLoaders();
+ // this returns aditional loaders(Quilt supports fabric and NeoForge supports Forge)
+ std::optional<ModPlatform::ModLoaderTypes> getSupportedModLoaders();
private:
void scheduleSave();
diff --git a/launcher/minecraft/auth/AccountList.cpp b/launcher/minecraft/auth/AccountList.cpp
index c534ea3b..84dbd841 100644
--- a/launcher/minecraft/auth/AccountList.cpp
+++ b/launcher/minecraft/auth/AccountList.cpp
@@ -415,7 +415,7 @@ Qt::ItemFlags AccountList::flags(const QModelIndex& index) const
bool AccountList::setData(const QModelIndex& idx, const QVariant& value, int role)
{
- if (idx.row() < 0 || idx.row() >= rowCount(idx) || !idx.isValid()) {
+ if (idx.row() < 0 || idx.row() >= rowCount(idx.parent()) || !idx.isValid()) {
return false;
}
@@ -423,7 +423,8 @@ bool AccountList::setData(const QModelIndex& idx, const QVariant& value, int rol
if (value == Qt::Checked) {
MinecraftAccountPtr account = at(idx.row());
setDefaultAccount(account);
- }
+ } else if (m_defaultAccount == at(idx.row()))
+ setDefaultAccount(nullptr);
}
emit dataChanged(idx, index(idx.row(), columnCount(QModelIndex()) - 1));
diff --git a/launcher/minecraft/mod/ModFolderModel.cpp b/launcher/minecraft/mod/ModFolderModel.cpp
index 280e70d7..eed35615 100644
--- a/launcher/minecraft/mod/ModFolderModel.cpp
+++ b/launcher/minecraft/mod/ModFolderModel.cpp
@@ -51,8 +51,13 @@
#include "Application.h"
+#include "Json.h"
#include "minecraft/mod/tasks/LocalModParseTask.h"
+#include "minecraft/mod/tasks/LocalModUpdateTask.h"
#include "minecraft/mod/tasks/ModFolderLoadTask.h"
+#include "modplatform/ModIndex.h"
+#include "modplatform/flame/FlameAPI.h"
+#include "modplatform/flame/FlameModIndex.h"
ModFolderModel::ModFolderModel(const QString& dir, BaseInstance* instance, bool is_indexed, bool create_dir)
: ResourceFolderModel(QDir(dir), instance, nullptr, create_dir), m_is_indexed(is_indexed)
@@ -309,3 +314,47 @@ void ModFolderModel::onParseSucceeded(int ticket, QString mod_id)
emit dataChanged(index(row), index(row, columnCount(QModelIndex()) - 1));
}
+
+static const FlameAPI flameAPI;
+bool ModFolderModel::installMod(QString file_path, ModPlatform::IndexedVersion& vers)
+{
+ if (vers.addonId.isValid()) {
+ ModPlatform::IndexedPack pack{
+ vers.addonId,
+ ModPlatform::ResourceProvider::FLAME,
+ };
+
+ QEventLoop loop;
+
+ auto response = std::make_shared<QByteArray>();
+ auto job = flameAPI.getProject(vers.addonId.toString(), response);
+
+ QObject::connect(job.get(), &Task::failed, [&loop] { loop.quit(); });
+ QObject::connect(job.get(), &Task::aborted, &loop, &QEventLoop::quit);
+ QObject::connect(job.get(), &Task::succeeded, [response, this, &vers, &loop, &pack] {
+ QJsonParseError parse_error{};
+ QJsonDocument doc = QJsonDocument::fromJson(*response, &parse_error);
+ if (parse_error.error != QJsonParseError::NoError) {
+ qWarning() << "Error while parsing JSON response for mod info at " << parse_error.offset
+ << " reason: " << parse_error.errorString();
+ qDebug() << *response;
+ return;
+ }
+ try {
+ auto obj = Json::requireObject(Json::requireObject(doc), "data");
+ FlameMod::loadIndexedPack(pack, obj);
+ } catch (const JSONValidationError& e) {
+ qDebug() << doc;
+ qWarning() << "Error while reading mod info: " << e.cause();
+ }
+ LocalModUpdateTask update_metadata(indexDir(), pack, vers);
+ QObject::connect(&update_metadata, &Task::finished, &loop, &QEventLoop::quit);
+ update_metadata.start();
+ });
+
+ job->start();
+
+ loop.exec();
+ }
+ return ResourceFolderModel::installResource(file_path);
+}
diff --git a/launcher/minecraft/mod/ModFolderModel.h b/launcher/minecraft/mod/ModFolderModel.h
index 06fd7814..f1890e87 100644
--- a/launcher/minecraft/mod/ModFolderModel.h
+++ b/launcher/minecraft/mod/ModFolderModel.h
@@ -48,6 +48,7 @@
#include "minecraft/mod/tasks/LocalModParseTask.h"
#include "minecraft/mod/tasks/ModFolderLoadTask.h"
+#include "modplatform/ModIndex.h"
class LegacyInstance;
class BaseInstance;
@@ -75,6 +76,7 @@ class ModFolderModel : public ResourceFolderModel {
[[nodiscard]] Task* createParseTask(Resource&) override;
bool installMod(QString file_path) { return ResourceFolderModel::installResource(file_path); }
+ bool installMod(QString file_path, ModPlatform::IndexedVersion& vers);
bool uninstallMod(const QString& filename, bool preserve_metadata = false);
/// Deletes all the selected mods
diff --git a/launcher/minecraft/mod/tasks/GetModDependenciesTask.cpp b/launcher/minecraft/mod/tasks/GetModDependenciesTask.cpp
index 20240e02..87439173 100644
--- a/launcher/minecraft/mod/tasks/GetModDependenciesTask.cpp
+++ b/launcher/minecraft/mod/tasks/GetModDependenciesTask.cpp
@@ -39,9 +39,9 @@ static Version mcVersion(BaseInstance* inst)
return static_cast<MinecraftInstance*>(inst)->getPackProfile()->getComponent("net.minecraft")->getVersion();
}
-static ResourceAPI::ModLoaderTypes mcLoaders(BaseInstance* inst)
+static ModPlatform::ModLoaderTypes mcLoaders(BaseInstance* inst)
{
- return static_cast<MinecraftInstance*>(inst)->getPackProfile()->getModLoaders().value();
+ return static_cast<MinecraftInstance*>(inst)->getPackProfile()->getSupportedModLoaders().value();
}
GetModDependenciesTask::GetModDependenciesTask(QObject* parent,
@@ -75,7 +75,7 @@ void GetModDependenciesTask::prepare()
ModPlatform::Dependency GetModDependenciesTask::getOverride(const ModPlatform::Dependency& dep,
const ModPlatform::ResourceProvider providerName)
{
- if (auto isQuilt = m_loaderType & ResourceAPI::Quilt; isQuilt || m_loaderType & ResourceAPI::Fabric) {
+ if (auto isQuilt = m_loaderType & ModPlatform::Quilt; isQuilt || m_loaderType & ModPlatform::Fabric) {
auto overide = ModPlatform::getOverrideDeps();
auto over = std::find_if(overide.cbegin(), overide.cend(), [dep, providerName, isQuilt](auto o) {
return o.provider == providerName && dep.addonId == (isQuilt ? o.fabric : o.quilt);
@@ -191,7 +191,7 @@ Task::Ptr GetModDependenciesTask::prepareDependencyTask(const ModPlatform::Depen
}
pDep->version = provider.mod->loadDependencyVersions(dep, arr);
if (!pDep->version.addonId.isValid()) {
- if (m_loaderType & ResourceAPI::Quilt) { // falback for quilt
+ if (m_loaderType & ModPlatform::Quilt) { // falback for quilt
auto overide = ModPlatform::getOverrideDeps();
auto over = std::find_if(overide.cbegin(), overide.cend(),
[dep, provider](auto o) { return o.provider == provider.name && dep.addonId == o.quilt; });
@@ -201,6 +201,7 @@ Task::Ptr GetModDependenciesTask::prepareDependencyTask(const ModPlatform::Depen
return;
}
}
+ removePack(dep.addonId);
qWarning() << "Error while reading mod version empty ";
qDebug() << doc;
return;
diff --git a/launcher/minecraft/mod/tasks/GetModDependenciesTask.h b/launcher/minecraft/mod/tasks/GetModDependenciesTask.h
index 5a29b6ea..2580f807 100644
--- a/launcher/minecraft/mod/tasks/GetModDependenciesTask.h
+++ b/launcher/minecraft/mod/tasks/GetModDependenciesTask.h
@@ -81,5 +81,5 @@ class GetModDependenciesTask : public SequentialTask {
Provider m_modrinth_provider;
Version m_version;
- ResourceAPI::ModLoaderTypes m_loaderType;
+ ModPlatform::ModLoaderTypes m_loaderType;
};
diff --git a/launcher/modplatform/CheckUpdateTask.h b/launcher/modplatform/CheckUpdateTask.h
index 94b16dcc..61e6a3a9 100644
--- a/launcher/modplatform/CheckUpdateTask.h
+++ b/launcher/modplatform/CheckUpdateTask.h
@@ -15,7 +15,7 @@ class CheckUpdateTask : public Task {
public:
CheckUpdateTask(QList<Mod*>& mods,
std::list<Version>& mcVersions,
- std::optional<ResourceAPI::ModLoaderTypes> loaders,
+ std::optional<ModPlatform::ModLoaderTypes> loaders,
std::shared_ptr<ModFolderModel> mods_folder)
: Task(nullptr), m_mods(mods), m_game_versions(mcVersions), m_loaders(loaders), m_mods_folder(mods_folder){};
@@ -55,7 +55,7 @@ class CheckUpdateTask : public Task {
protected:
QList<Mod*>& m_mods;
std::list<Version>& m_game_versions;
- std::optional<ResourceAPI::ModLoaderTypes> m_loaders;
+ std::optional<ModPlatform::ModLoaderTypes> m_loaders;
std::shared_ptr<ModFolderModel> m_mods_folder;
std::vector<UpdatableMod> m_updatable;
diff --git a/launcher/modplatform/ModIndex.cpp b/launcher/modplatform/ModIndex.cpp
index 350a9f10..e8e4a38d 100644
--- a/launcher/modplatform/ModIndex.cpp
+++ b/launcher/modplatform/ModIndex.cpp
@@ -83,4 +83,25 @@ QString getMetaURL(ResourceProvider provider, QVariant projectID)
projectID.toString();
}
+auto getModLoaderString(ModLoaderType type) -> const QString
+{
+ switch (type) {
+ case NeoForge:
+ return "neoforge";
+ case Forge:
+ return "forge";
+ case Cauldron:
+ return "cauldron";
+ case LiteLoader:
+ return "liteloader";
+ case Fabric:
+ return "fabric";
+ case Quilt:
+ return "quilt";
+ default:
+ break;
+ }
+ return "";
+}
+
} // namespace ModPlatform
diff --git a/launcher/modplatform/ModIndex.h b/launcher/modplatform/ModIndex.h
index cad21703..7d144176 100644
--- a/launcher/modplatform/ModIndex.h
+++ b/launcher/modplatform/ModIndex.h
@@ -30,6 +30,9 @@ class QIODevice;
namespace ModPlatform {
+enum ModLoaderType { NeoForge = 1 << 0, Forge = 1 << 1, Cauldron = 1 << 2, LiteLoader = 1 << 3, Fabric = 1 << 4, Quilt = 1 << 5 };
+Q_DECLARE_FLAGS(ModLoaderTypes, ModLoaderType)
+
enum class ResourceProvider { MODRINTH, FLAME };
enum class ResourceType { MOD, RESOURCE_PACK, SHADER_PACK };
@@ -70,7 +73,7 @@ struct IndexedVersion {
QString downloadUrl;
QString date;
QString fileName;
- QStringList loaders = {};
+ ModLoaderTypes loaders = {};
QString hash_type;
QString hash;
bool is_preferred = true;
@@ -128,7 +131,6 @@ struct IndexedPack {
return std::any_of(versions.constBegin(), versions.constEnd(), [](auto const& v) { return v.is_currently_selected; });
}
};
-QString getMetaURL(ResourceProvider provider, QVariant projectID);
struct OverrideDep {
QString quilt;
@@ -148,6 +150,14 @@ inline auto getOverrideDeps() -> QList<OverrideDep>
QString getMetaURL(ResourceProvider provider, QVariant projectID);
+auto getModLoaderString(ModLoaderType type) -> const QString;
+
+constexpr bool hasSingleModLoaderSelected(ModLoaderTypes l) noexcept
+{
+ auto x = static_cast<int>(l);
+ return x && !(x & (x - 1));
+}
+
} // namespace ModPlatform
Q_DECLARE_METATYPE(ModPlatform::IndexedPack)
diff --git a/launcher/modplatform/ResourceAPI.h b/launcher/modplatform/ResourceAPI.h
index f6ccb426..7965d0f5 100644
--- a/launcher/modplatform/ResourceAPI.h
+++ b/launcher/modplatform/ResourceAPI.h
@@ -54,9 +54,6 @@ class ResourceAPI {
public:
virtual ~ResourceAPI() = default;
- enum ModLoaderType { NeoForge = 1 << 0, Forge = 1 << 1, Cauldron = 1 << 2, LiteLoader = 1 << 3, Fabric = 1 << 4, Quilt = 1 << 5 };
- Q_DECLARE_FLAGS(ModLoaderTypes, ModLoaderType)
-
struct SortingMethod {
// The index of the sorting method. Used to allow for arbitrary ordering in the list of methods.
// Used by Flame in the API request.
@@ -74,7 +71,7 @@ class ResourceAPI {
std::optional<QString> search;
std::optional<SortingMethod> sorting;
- std::optional<ModLoaderTypes> loaders;
+ std::optional<ModPlatform::ModLoaderTypes> loaders;
std::optional<std::list<Version> > versions;
};
struct SearchCallbacks {
@@ -87,7 +84,7 @@ class ResourceAPI {
ModPlatform::IndexedPack pack;
std::optional<std::list<Version> > mcVersions;
- std::optional<ModLoaderTypes> loaders;
+ std::optional<ModPlatform::ModLoaderTypes> loaders;
VersionSearchArgs(VersionSearchArgs const&) = default;
void operator=(VersionSearchArgs other)
@@ -114,7 +111,7 @@ class ResourceAPI {
struct DependencySearchArgs {
ModPlatform::Dependency dependency;
Version mcVersion;
- ModLoaderTypes loader;
+ ModPlatform::ModLoaderTypes loader;
};
struct DependencySearchCallbacks {
@@ -161,27 +158,6 @@ class ResourceAPI {
return nullptr;
}
- static auto getModLoaderString(ModLoaderType type) -> const QString
- {
- switch (type) {
- case NeoForge:
- return "neoforge";
- case Forge:
- return "forge";
- case Cauldron:
- return "cauldron";
- case LiteLoader:
- return "liteloader";
- case Fabric:
- return "fabric";
- case Quilt:
- return "quilt";
- default:
- break;
- }
- return "";
- }
-
protected:
[[nodiscard]] inline QString debugName() const { return "External resource API"; }
diff --git a/launcher/modplatform/flame/FileResolvingTask.cpp b/launcher/modplatform/flame/FileResolvingTask.cpp
index 860d7340..5865bee9 100644
--- a/launcher/modplatform/flame/FileResolvingTask.cpp
+++ b/launcher/modplatform/flame/FileResolvingTask.cpp
@@ -1,6 +1,7 @@
#include "FileResolvingTask.h"
#include "Json.h"
+#include "modplatform/ModIndex.h"
#include "net/ApiDownload.h"
#include "net/ApiUpload.h"
#include "net/Upload.h"
@@ -102,7 +103,7 @@ void Flame::FileResolvingTask::netJobFinished()
auto url = QString("https://api.modrinth.com/v2/version_file/%1?algorithm=sha1").arg(hash);
auto output = std::make_shared<QByteArray>();
auto dl = Net::ApiDownload::makeByteArray(QUrl(url), output);
- QObject::connect(dl.get(), &Net::Download::succeeded, [&out]() { out.resolved = true; });
+ QObject::connect(dl.get(), &Net::ApiDownload::succeeded, [&out]() { out.resolved = true; });
m_checkJob->addNetAction(dl);
blockedProjects.insert(&out, output);
@@ -153,7 +154,7 @@ void Flame::FileResolvingTask::modrinthCheckFinished()
// If there's more than one mod loader for this version, we can't know for sure
// which file is relative to each loader, so it's best to not use any one and
// let the user download it manually.
- if (file.loaders.size() <= 1) {
+ if (!file.loaders || hasSingleModLoaderSelected(file.loaders)) {
out->url = file.downloadUrl;
qDebug() << "Found alternative on modrinth " << out->fileName;
} else {
@@ -175,7 +176,7 @@ void Flame::FileResolvingTask::modrinthCheckFinished()
auto url = QString("https://api.curseforge.com/v1/mods/%1").arg(projectId);
auto dl = Net::ApiDownload::makeByteArray(url, output);
qDebug() << "Fetching url slug for file:" << mod->fileName;
- QObject::connect(dl.get(), &Net::Download::succeeded, [block, index, output]() {
+ QObject::connect(dl.get(), &Net::ApiDownload::succeeded, [block, index, output]() {
auto mod = block->at(index); // use the shared_ptr so it is captured and only freed when we are done
auto json = QJsonDocument::fromJson(*output);
auto base =
diff --git a/launcher/modplatform/flame/FlameAPI.cpp b/launcher/modplatform/flame/FlameAPI.cpp
index 74d7db97..e99ce3a5 100644
--- a/launcher/modplatform/flame/FlameAPI.cpp
+++ b/launcher/modplatform/flame/FlameAPI.cpp
@@ -6,7 +6,6 @@
#include "FlameModIndex.h"
#include "Application.h"
-#include "BuildConfig.h"
#include "Json.h"
#include "net/ApiDownload.h"
#include "net/ApiUpload.h"
@@ -131,19 +130,13 @@ auto FlameAPI::getLatestVersion(VersionSearchArgs&& args) -> ModPlatform::Indexe
auto obj = Json::requireObject(doc);
auto arr = Json::requireArray(obj, "data");
- QJsonObject latest_file_obj;
- ModPlatform::IndexedVersion ver_tmp;
-
for (auto file : arr) {
auto file_obj = Json::requireObject(file);
auto file_tmp = FlameMod::loadIndexedPackVersion(file_obj);
- if (file_tmp.date > ver_tmp.date) {
- ver_tmp = file_tmp;
- latest_file_obj = file_obj;
- }
+ if (file_tmp.date > ver.date && (!args.loaders.has_value() || !file_tmp.loaders || args.loaders.value() & file_tmp.loaders))
+ ver = file_tmp;
}
- ver = FlameMod::loadIndexedPackVersion(latest_file_obj);
} catch (Json::JsonException& e) {
qCritical() << "Failed to parse response from a version request.";
qCritical() << e.what();
diff --git a/launcher/modplatform/flame/FlameAPI.h b/launcher/modplatform/flame/FlameAPI.h
index a1256e17..47350c33 100644
--- a/launcher/modplatform/flame/FlameAPI.h
+++ b/launcher/modplatform/flame/FlameAPI.h
@@ -24,7 +24,10 @@ class FlameAPI : public NetworkResourceAPI {
[[nodiscard]] auto getSortingMethods() const -> QList<ResourceAPI::SortingMethod> override;
- static inline auto validateModLoaders(ModLoaderTypes loaders) -> bool { return loaders & (NeoForge | Forge | Fabric | Quilt); }
+ static inline auto validateModLoaders(ModPlatform::ModLoaderTypes loaders) -> bool
+ {
+ return loaders & (ModPlatform::NeoForge | ModPlatform::Forge | ModPlatform::Fabric | ModPlatform::Quilt);
+ }
private:
static int getClassId(ModPlatform::ResourceType type)
@@ -38,21 +41,42 @@ class FlameAPI : public NetworkResourceAPI {
}
}
- static int getMappedModLoader(ModLoaderTypes loaders)
+ static int getMappedModLoader(ModPlatform::ModLoaderType loaders)
{
// https://docs.curseforge.com/?http#tocS_ModLoaderType
- if (loaders & Forge)
- return 1;
- if (loaders & Fabric)
- return 4;
- // TODO: remove this once Quilt drops official Fabric support
- if (loaders & Quilt) // NOTE: Most if not all Fabric mods should work *currently*
- return 4; // FIXME: implement multiple loaders filter
- if (loaders & NeoForge)
- return 6;
+ switch (loaders) {
+ case ModPlatform::Forge:
+ return 1;
+ case ModPlatform::Cauldron:
+ return 2;
+ case ModPlatform::LiteLoader:
+ return 3;
+ case ModPlatform::Fabric:
+ return 4;
+ case ModPlatform::Quilt:
+ return 5;
+ case ModPlatform::NeoForge:
+ return 6;
+ }
return 0;
}
+ static auto getModLoaderStrings(const ModPlatform::ModLoaderTypes types) -> const QStringList
+ {
+ QStringList l;
+ for (auto loader : { ModPlatform::NeoForge, ModPlatform::Forge, ModPlatform::Fabric, ModPlatform::Quilt }) {
+ if (types & loader) {
+ l << QString::number(getMappedModLoader(loader));
+ }
+ }
+ return l;
+ }
+
+ static auto getModLoaderFilters(ModPlatform::ModLoaderTypes types) -> const QString
+ {
+ return "[" + getModLoaderStrings(types).join(',') + "]";
+ }
+
private:
[[nodiscard]] std::optional<QString> getSearchURL(SearchArgs const& args) const override
{
@@ -69,7 +93,7 @@ class FlameAPI : public NetworkResourceAPI {
get_arguments.append(QString("sortField=%1").arg(args.sorting.value().index));
get_arguments.append("sortOrder=desc");
if (args.loaders.has_value())
- get_arguments.append(QString("modLoaderType=%1").arg(getMappedModLoader(args.loaders.value())));
+ get_arguments.append(QString("modLoaderTypes=%1").arg(getModLoaderFilters(args.loaders.value())));
get_arguments.append(gameVersionStr);
return "https://api.curseforge.com/v1/mods/search?gameId=432&" + get_arguments.join('&');
@@ -83,47 +107,27 @@ class FlameAPI : public NetworkResourceAPI {
[[nodiscard]] std::optional<QString> getVersionsURL(VersionSearchArgs const& args) const override
{
auto addonId = args.pack.addonId.toString();
- QString url{ QString("https://api.curseforge.com/v1/mods/%1/files?pageSize=10000&").arg(addonId) };
+ QString url = QString("https://api.curseforge.com/v1/mods/%1/files?pageSize=10000").arg(addonId);
- QStringList get_parameters;
if (args.mcVersions.has_value())
- get_parameters.append(QString("gameVersion=%1").arg(args.mcVersions.value().front().toString()));
-
- if (args.loaders.has_value()) {
- int mappedModLoader = getMappedModLoader(args.loaders.value());
-
- if (args.loaders.value() & Quilt) {
- auto overide = ModPlatform::getOverrideDeps();
- auto over = std::find_if(overide.cbegin(), overide.cend(), [addonId](auto dep) {
- return dep.provider == ModPlatform::ResourceProvider::FLAME && addonId == dep.quilt;
- });
- if (over != overide.cend()) {
- mappedModLoader = 5;
- }
- }
+ url += QString("&gameVersion=%1").arg(args.mcVersions.value().front().toString());
- get_parameters.append(QString("modLoaderType=%1").arg(mappedModLoader));
+ if (args.loaders.has_value() && ModPlatform::hasSingleModLoaderSelected(args.loaders.value())) {
+ int mappedModLoader = getMappedModLoader(static_cast<ModPlatform::ModLoaderType>(static_cast<int>(args.loaders.value())));
+ url += QString("&modLoaderType=%1").arg(mappedModLoader);
}
-
- return url + get_parameters.join('&');
+ return url;
};
[[nodiscard]] std::optional<QString> getDependencyURL(DependencySearchArgs const& args) const override
{
- auto mappedModLoader = getMappedModLoader(args.loader);
auto addonId = args.dependency.addonId.toString();
- if (args.loader & Quilt) {
- auto overide = ModPlatform::getOverrideDeps();
- auto over = std::find_if(overide.cbegin(), overide.cend(), [addonId](auto dep) {
- return dep.provider == ModPlatform::ResourceProvider::FLAME && addonId == dep.quilt;
- });
- if (over != overide.cend()) {
- mappedModLoader = 5;
- }
+ auto url =
+ QString("https://api.curseforge.com/v1/mods/%1/files?pageSize=10000&gameVersion=%2").arg(addonId, args.mcVersion.toString());
+ if (args.loader && ModPlatform::hasSingleModLoaderSelected(args.loader)) {
+ int mappedModLoader = getMappedModLoader(static_cast<ModPlatform::ModLoaderType>(static_cast<int>(args.loader)));
+ url += QString("&modLoaderType=%1").arg(mappedModLoader);
}
- return QString("https://api.curseforge.com/v1/mods/%1/files?pageSize=10000&gameVersion=%2&modLoaderType=%3")
- .arg(addonId)
- .arg(args.mcVersion.toString())
- .arg(mappedModLoader);
+ return url;
};
};
diff --git a/launcher/modplatform/flame/FlameCheckUpdate.cpp b/launcher/modplatform/flame/FlameCheckUpdate.cpp
index 255f9134..0501dda6 100644
--- a/launcher/modplatform/flame/FlameCheckUpdate.cpp
+++ b/launcher/modplatform/flame/FlameCheckUpdate.cpp
@@ -5,13 +5,11 @@
#include <MurmurHash2.h>
#include <memory>
-#include "FileSystem.h"
#include "Json.h"
#include "ResourceDownloadTask.h"
#include "minecraft/mod/ModFolderModel.h"
-#include "minecraft/mod/ResourceFolderModel.h"
#include "minecraft/mod/tasks/GetModDependenciesTask.h"
#include "net/ApiDownload.h"
diff --git a/launcher/modplatform/flame/FlameCheckUpdate.h b/launcher/modplatform/flame/FlameCheckUpdate.h
index e3465d7e..05c619a7 100644
--- a/launcher/modplatform/flame/FlameCheckUpdate.h
+++ b/launcher/modplatform/flame/FlameCheckUpdate.h
@@ -10,7 +10,7 @@ class FlameCheckUpdate : public CheckUpdateTask {
public:
FlameCheckUpdate(QList<Mod*>& mods,
std::list<Version>& mcVersions,
- std::optional<ResourceAPI::ModLoaderTypes> loaders,
+ std::optional<ModPlatform::ModLoaderTypes> loaders,
std::shared_ptr<ModFolderModel> mods_folder)
: CheckUpdateTask(mods, mcVersions, loaders, mods_folder)
{}
diff --git a/launcher/modplatform/flame/FlameModIndex.cpp b/launcher/modplatform/flame/FlameModIndex.cpp
index 19803cf6..494dc2a7 100644
--- a/launcher/modplatform/flame/FlameModIndex.cpp
+++ b/launcher/modplatform/flame/FlameModIndex.cpp
@@ -81,6 +81,7 @@ void FlameMod::loadIndexedPackVersions(ModPlatform::IndexedPack& pack,
QVector<ModPlatform::IndexedVersion> unsortedVersions;
auto profile = (dynamic_cast<const MinecraftInstance*>(inst))->getPackProfile();
QString mcVersion = profile->getComponentVersion("net.minecraft");
+ auto loaders = profile->getSupportedModLoaders();
for (auto versionIter : arr) {
auto obj = versionIter.toObject();
@@ -89,7 +90,8 @@ void FlameMod::loadIndexedPackVersions(ModPlatform::IndexedPack& pack,
if (!file.addonId.isValid())
file.addonId = pack.addonId;
- if (file.fileId.isValid()) // Heuristic to check if the returned value is valid
+ if (file.fileId.isValid() &&
+ (!loaders.has_value() || !file.loaders || loaders.value() & file.loaders)) // Heuristic to check if the returned value is valid
unsortedVersions.append(file);
}
@@ -115,6 +117,19 @@ auto FlameMod::loadIndexedPackVersion(QJsonObject& obj, bool load_changelog) ->
if (str.contains('.'))
file.mcVersion.append(str);
+ auto loader = str.toLower();
+ if (loader == "neoforge")
+ file.loaders |= ModPlatform::NeoForge;
+ if (loader == "forge")
+ file.loaders |= ModPlatform::Forge;
+ if (loader == "cauldron")
+ file.loaders |= ModPlatform::Cauldron;
+ if (loader == "liteloader")
+ file.loaders |= ModPlatform::LiteLoader;
+ if (loader == "fabric")
+ file.loaders |= ModPlatform::Fabric;
+ if (loader == "quilt")
+ file.loaders |= ModPlatform::Quilt;
}
file.addonId = Json::requireInteger(obj, "modId");
@@ -173,8 +188,11 @@ auto FlameMod::loadIndexedPackVersion(QJsonObject& obj, bool load_changelog) ->
return file;
}
-ModPlatform::IndexedVersion FlameMod::loadDependencyVersions(const ModPlatform::Dependency& m, QJsonArray& arr)
+ModPlatform::IndexedVersion FlameMod::loadDependencyVersions(const ModPlatform::Dependency& m, QJsonArray& arr, const BaseInstance* inst)
{
+ auto profile = (dynamic_cast<const MinecraftInstance*>(inst))->getPackProfile();
+ QString mcVersion = profile->getComponentVersion("net.minecraft");
+ auto loaders = profile->getSupportedModLoaders();
QVector<ModPlatform::IndexedVersion> versions;
for (auto versionIter : arr) {
auto obj = versionIter.toObject();
@@ -183,7 +201,8 @@ ModPlatform::IndexedVersion FlameMod::loadDependencyVersions(const ModPlatform::
if (!file.addonId.isValid())
file.addonId = m.addonId;
- if (file.fileId.isValid()) // Heuristic to check if the returned value is valid
+ if (file.fileId.isValid() &&
+ (!loaders.has_value() || !file.loaders || loaders.value() & file.loaders)) // Heuristic to check if the returned value is valid
versions.append(file);
}
@@ -192,5 +211,7 @@ ModPlatform::IndexedVersion FlameMod::loadDependencyVersions(const ModPlatform::
return a.date > b.date;
};
std::sort(versions.begin(), versions.end(), orderSortPredicate);
- return versions.front();
+ if (versions.size() != 0)
+ return versions.front();
+ return {};
}
diff --git a/launcher/modplatform/flame/FlameModIndex.h b/launcher/modplatform/flame/FlameModIndex.h
index aa0d6f81..1bcaa44b 100644
--- a/launcher/modplatform/flame/FlameModIndex.h
+++ b/launcher/modplatform/flame/FlameModIndex.h
@@ -19,5 +19,5 @@ void loadIndexedPackVersions(ModPlatform::IndexedPack& pack,
const shared_qobject_ptr<QNetworkAccessManager>& network,
const BaseInstance* inst);
auto loadIndexedPackVersion(QJsonObject& obj, bool load_changelog = false) -> ModPlatform::IndexedVersion;
-auto loadDependencyVersions(const ModPlatform::Dependency& m, QJsonArray& arr) -> ModPlatform::IndexedVersion;
+auto loadDependencyVersions(const ModPlatform::Dependency& m, QJsonArray& arr, const BaseInstance* inst) -> ModPlatform::IndexedVersion;
} // namespace FlameMod \ No newline at end of file
diff --git a/launcher/modplatform/helpers/NetworkResourceAPI.cpp b/launcher/modplatform/helpers/NetworkResourceAPI.cpp
index 46b96662..78b39fff 100644
--- a/launcher/modplatform/helpers/NetworkResourceAPI.cpp
+++ b/launcher/modplatform/helpers/NetworkResourceAPI.cpp
@@ -131,7 +131,7 @@ Task::Ptr NetworkResourceAPI::getDependencyVersion(DependencySearchArgs&& args,
auto netJob = makeShared<NetJob>(QString("%1::Dependency").arg(args.dependency.addonId.toString()), APPLICATION->network());
auto response = std::make_shared<QByteArray>();
- netJob->addNetAction(Net::Download::makeByteArray(versions_url, response));
+ netJob->addNetAction(Net::ApiDownload::makeByteArray(versions_url, response));
QObject::connect(netJob.get(), &NetJob::succeeded, [=] {
QJsonParseError parse_error{};
diff --git a/launcher/modplatform/import_ftb/PackHelpers.cpp b/launcher/modplatform/import_ftb/PackHelpers.cpp
index 118bdd15..ecf97345 100644
--- a/launcher/modplatform/import_ftb/PackHelpers.cpp
+++ b/launcher/modplatform/import_ftb/PackHelpers.cpp
@@ -60,19 +60,19 @@ Modpack parseDirectory(QString path)
auto name = Json::requireString(obj, "name", "name");
auto version = Json::requireString(obj, "version", "version");
if (name == "neoforge") {
- modpack.loaderType = ResourceAPI::NeoForge;
+ modpack.loaderType = ModPlatform::NeoForge;
modpack.version = version;
break;
} else if (name == "forge") {
- modpack.loaderType = ResourceAPI::Forge;
+ modpack.loaderType = ModPlatform::Forge;
modpack.version = version;
break;
} else if (name == "fabric") {
- modpack.loaderType = ResourceAPI::Fabric;
+ modpack.loaderType = ModPlatform::Fabric;
modpack.version = version;
break;
} else if (name == "quilt") {
- modpack.loaderType = ResourceAPI::Quilt;
+ modpack.loaderType = ModPlatform::Quilt;
modpack.version = version;
break;
}
diff --git a/launcher/modplatform/import_ftb/PackHelpers.h b/launcher/modplatform/import_ftb/PackHelpers.h
index 8ea4f3fa..5400252b 100644
--- a/launcher/modplatform/import_ftb/PackHelpers.h
+++ b/launcher/modplatform/import_ftb/PackHelpers.h
@@ -39,7 +39,7 @@ struct Modpack {
// not needed for instance creation
QVariant jvmArgs;
- std::optional<ResourceAPI::ModLoaderType> loaderType;
+ std::optional<ModPlatform::ModLoaderType> loaderType;
QString loaderVersion;
QIcon icon;
diff --git a/launcher/modplatform/import_ftb/PackInstallTask.cpp b/launcher/modplatform/import_ftb/PackInstallTask.cpp
index 9e4decb0..9a3b2595 100644
--- a/launcher/modplatform/import_ftb/PackInstallTask.cpp
+++ b/launcher/modplatform/import_ftb/PackInstallTask.cpp
@@ -68,25 +68,25 @@ void PackInstallTask::copySettings()
auto modloader = m_pack.loaderType;
if (modloader.has_value())
switch (modloader.value()) {
- case ResourceAPI::NeoForge: {
+ case ModPlatform::NeoForge: {
components->setComponentVersion("net.neoforged", m_pack.version, true);
break;
}
- case ResourceAPI::Forge: {
+ case ModPlatform::Forge: {
components->setComponentVersion("net.minecraftforge", m_pack.version, true);
break;
}
- case ResourceAPI::Fabric: {
+ case ModPlatform::Fabric: {
components->setComponentVersion("net.fabricmc.fabric-loader", m_pack.version, true);
break;
}
- case ResourceAPI::Quilt: {
+ case ModPlatform::Quilt: {
components->setComponentVersion("org.quiltmc.quilt-loader", m_pack.version, true);
break;
}
- case ResourceAPI::Cauldron:
+ case ModPlatform::Cauldron:
break;
- case ResourceAPI::LiteLoader:
+ case ModPlatform::LiteLoader:
break;
}
components->saveNow();
diff --git a/launcher/modplatform/modrinth/ModrinthAPI.cpp b/launcher/modplatform/modrinth/ModrinthAPI.cpp
index 466c5b10..f453f5cb 100644
--- a/launcher/modplatform/modrinth/ModrinthAPI.cpp
+++ b/launcher/modplatform/modrinth/ModrinthAPI.cpp
@@ -41,7 +41,7 @@ Task::Ptr ModrinthAPI::currentVersions(const QStringList& hashes, QString hash_f
Task::Ptr ModrinthAPI::latestVersion(QString hash,
QString hash_format,
std::optional<std::list<Version>> mcVersions,
- std::optional<ModLoaderTypes> loaders,
+ std::optional<ModPlatform::ModLoaderTypes> loaders,
std::shared_ptr<QByteArray> response)
{
auto netJob = makeShared<NetJob>(QString("Modrinth::GetLatestVersion"), APPLICATION->network());
@@ -71,7 +71,7 @@ Task::Ptr ModrinthAPI::latestVersion(QString hash,
Task::Ptr ModrinthAPI::latestVersions(const QStringList& hashes,
QString hash_format,
std::optional<std::list<Version>> mcVersions,
- std::optional<ModLoaderTypes> loaders,
+ std::optional<ModPlatform::ModLoaderTypes> loaders,
std::shared_ptr<QByteArray> response)
{
auto netJob = makeShared<NetJob>(QString("Modrinth::GetLatestVersions"), APPLICATION->network());
diff --git a/launcher/modplatform/modrinth/ModrinthAPI.h b/launcher/modplatform/modrinth/ModrinthAPI.h
index 0f150e97..d0f0811b 100644
--- a/launcher/modplatform/modrinth/ModrinthAPI.h
+++ b/launcher/modplatform/modrinth/ModrinthAPI.h
@@ -19,13 +19,13 @@ class ModrinthAPI : public NetworkResourceAPI {
auto latestVersion(QString hash,
QString hash_format,
std::optional<std::list<Version>> mcVersions,
- std::optional<ModLoaderTypes> loaders,
+ std::optional<ModPlatform::ModLoaderTypes> loaders,
std::shared_ptr<QByteArray> response) -> Task::Ptr;
auto latestVersions(const QStringList& hashes,
QString hash_format,
std::optional<std::list<Version>> mcVersions,
- std::optional<ModLoaderTypes> loaders,
+ std::optional<ModPlatform::ModLoaderTypes> loaders,
std::shared_ptr<QByteArray> response) -> Task::Ptr;
Task::Ptr getProjects(QStringList addonIds, std::shared_ptr<QByteArray> response) const override;
@@ -35,20 +35,19 @@ class ModrinthAPI : public NetworkResourceAPI {
inline auto getAuthorURL(const QString& name) const -> QString { return "https://modrinth.com/user/" + name; };
- static auto getModLoaderStrings(const ModLoaderTypes types) -> const QStringList
+ static auto getModLoaderStrings(const ModPlatform::ModLoaderTypes types) -> const QStringList
{
QStringList l;
- for (auto loader : { NeoForge, Forge, Fabric, Quilt, LiteLoader }) {
+ for (auto loader :
+ { ModPlatform::NeoForge, ModPlatform::Forge, ModPlatform::Fabric, ModPlatform::Quilt, ModPlatform::LiteLoader }) {
if (types & loader) {
l << getModLoaderString(loader);
}
}
- if ((types & Quilt) && (~types & Fabric)) // Add Fabric if Quilt is in use, if Fabric isn't already there
- l << getModLoaderString(Fabric);
return l;
}
- static auto getModLoaderFilters(ModLoaderTypes types) -> const QString
+ static auto getModLoaderFilters(ModPlatform::ModLoaderTypes types) -> const QString
{
QStringList l;
for (auto loader : getModLoaderStrings(types)) {
@@ -141,9 +140,9 @@ class ModrinthAPI : public NetworkResourceAPI {
return s.isEmpty() ? QString() : s;
}
- static inline auto validateModLoaders(ModLoaderTypes loaders) -> bool
+ static inline auto validateModLoaders(ModPlatform::ModLoaderTypes loaders) -> bool
{
- return loaders & (NeoForge | Forge | Fabric | Quilt | LiteLoader);
+ return loaders & (ModPlatform::NeoForge | ModPlatform::Forge | ModPlatform::Fabric | ModPlatform::Quilt | ModPlatform::LiteLoader);
}
[[nodiscard]] std::optional<QString> getDependencyURL(DependencySearchArgs const& args) const override
diff --git a/launcher/modplatform/modrinth/ModrinthCheckUpdate.cpp b/launcher/modplatform/modrinth/ModrinthCheckUpdate.cpp
index 6b7bbca2..bfd77243 100644
--- a/launcher/modplatform/modrinth/ModrinthCheckUpdate.cpp
+++ b/launcher/modplatform/modrinth/ModrinthCheckUpdate.cpp
@@ -11,7 +11,6 @@
#include "tasks/ConcurrentTask.h"
#include "minecraft/mod/ModFolderModel.h"
-#include "minecraft/mod/ResourceFolderModel.h"
static ModrinthAPI api;
static ModPlatform::ProviderCapabilities ProviderCaps;
@@ -111,11 +110,11 @@ void ModrinthCheckUpdate::executeTask()
// so we may want to filter it
QString loader_filter;
if (m_loaders.has_value()) {
- static auto flags = { ResourceAPI::ModLoaderType::NeoForge, ResourceAPI::ModLoaderType::Forge,
- ResourceAPI::ModLoaderType::Fabric, ResourceAPI::ModLoaderType::Quilt };
+ static auto flags = { ModPlatform::ModLoaderType::NeoForge, ModPlatform::ModLoaderType::Forge,
+ ModPlatform::ModLoaderType::Fabric, ModPlatform::ModLoaderType::Quilt };
for (auto flag : flags) {
if (m_loaders.value().testFlag(flag)) {
- loader_filter = api.getModLoaderString(flag);
+ loader_filter = ModPlatform::getModLoaderString(flag);
break;
}
}
diff --git a/launcher/modplatform/modrinth/ModrinthCheckUpdate.h b/launcher/modplatform/modrinth/ModrinthCheckUpdate.h
index 4583dd6c..f2f2c7e9 100644
--- a/launcher/modplatform/modrinth/ModrinthCheckUpdate.h
+++ b/launcher/modplatform/modrinth/ModrinthCheckUpdate.h
@@ -10,7 +10,7 @@ class ModrinthCheckUpdate : public CheckUpdateTask {
public:
ModrinthCheckUpdate(QList<Mod*>& mods,
std::list<Version>& mcVersions,
- std::optional<ResourceAPI::ModLoaderTypes> loaders,
+ std::optional<ModPlatform::ModLoaderTypes> loaders,
std::shared_ptr<ModFolderModel> mods_folder)
: CheckUpdateTask(mods, mcVersions, loaders, mods_folder)
{}
diff --git a/launcher/modplatform/modrinth/ModrinthPackIndex.cpp b/launcher/modplatform/modrinth/ModrinthPackIndex.cpp
index 85e66a91..107b9900 100644
--- a/launcher/modplatform/modrinth/ModrinthPackIndex.cpp
+++ b/launcher/modplatform/modrinth/ModrinthPackIndex.cpp
@@ -93,19 +93,19 @@ void Modrinth::loadExtraPackData(ModPlatform::IndexedPack& pack, QJsonObject& ob
pack.extraDataLoaded = true;
}
-void Modrinth::loadIndexedPackVersions(ModPlatform::IndexedPack& pack,
- QJsonArray& arr,
- [[maybe_unused]] const shared_qobject_ptr<QNetworkAccessManager>& network,
- const BaseInstance* inst)
+void Modrinth::loadIndexedPackVersions(ModPlatform::IndexedPack& pack, QJsonArray& arr, const BaseInstance* inst)
{
QVector<ModPlatform::IndexedVersion> unsortedVersions;
- QString mcVersion = (static_cast<const MinecraftInstance*>(inst))->getPackProfile()->getComponentVersion("net.minecraft");
+ auto profile = (dynamic_cast<const MinecraftInstance*>(inst))->getPackProfile();
+ QString mcVersion = profile->getComponentVersion("net.minecraft");
+ auto loaders = profile->getSupportedModLoaders();
for (auto versionIter : arr) {
auto obj = versionIter.toObject();
auto file = loadIndexedPackVersion(obj);
- if (file.fileId.isValid()) // Heuristic to check if the returned value is valid
+ if (file.fileId.isValid() &&
+ (!loaders.has_value() || !file.loaders || loaders.value() & file.loaders)) // Heuristic to check if the returned value is valid
unsortedVersions.append(file);
}
auto orderSortPredicate = [](const ModPlatform::IndexedVersion& a, const ModPlatform::IndexedVersion& b) -> bool {
@@ -134,7 +134,18 @@ auto Modrinth::loadIndexedPackVersion(QJsonObject& obj, QString preferred_hash_t
}
auto loaders = Json::requireArray(obj, "loaders");
for (auto loader : loaders) {
- file.loaders.append(loader.toString());
+ if (loader == "neoforge")
+ file.loaders |= ModPlatform::NeoForge;
+ if (loader == "forge")
+ file.loaders |= ModPlatform::Forge;
+ if (loader == "cauldron")
+ file.loaders |= ModPlatform::Cauldron;
+ if (loader == "liteloader")
+ file.loaders |= ModPlatform::LiteLoader;
+ if (loader == "fabric")
+ file.loaders |= ModPlatform::Fabric;
+ if (loader == "quilt")
+ file.loaders |= ModPlatform::Quilt;
}
file.version = Json::requireString(obj, "name");
file.version_number = Json::requireString(obj, "version_number");
@@ -218,15 +229,20 @@ auto Modrinth::loadIndexedPackVersion(QJsonObject& obj, QString preferred_hash_t
return {};
}
-auto Modrinth::loadDependencyVersions([[maybe_unused]] const ModPlatform::Dependency& m, QJsonArray& arr) -> ModPlatform::IndexedVersion
+auto Modrinth::loadDependencyVersions([[maybe_unused]] const ModPlatform::Dependency& m, QJsonArray& arr, const BaseInstance* inst)
+ -> ModPlatform::IndexedVersion
{
- QVector<ModPlatform::IndexedVersion> versions;
+ auto profile = (dynamic_cast<const MinecraftInstance*>(inst))->getPackProfile();
+ QString mcVersion = profile->getComponentVersion("net.minecraft");
+ auto loaders = profile->getSupportedModLoaders();
+ QVector<ModPlatform::IndexedVersion> versions;
for (auto versionIter : arr) {
auto obj = versionIter.toObject();
auto file = loadIndexedPackVersion(obj);
- if (file.fileId.isValid()) // Heuristic to check if the returned value is valid
+ if (file.fileId.isValid() &&
+ (!loaders.has_value() || !file.loaders || loaders.value() & file.loaders)) // Heuristic to check if the returned value is valid
versions.append(file);
}
auto orderSortPredicate = [](const ModPlatform::IndexedVersion& a, const ModPlatform::IndexedVersion& b) -> bool {
diff --git a/launcher/modplatform/modrinth/ModrinthPackIndex.h b/launcher/modplatform/modrinth/ModrinthPackIndex.h
index 58a0f227..93f91eec 100644
--- a/launcher/modplatform/modrinth/ModrinthPackIndex.h
+++ b/launcher/modplatform/modrinth/ModrinthPackIndex.h
@@ -26,11 +26,8 @@ namespace Modrinth {
void loadIndexedPack(ModPlatform::IndexedPack& m, QJsonObject& obj);
void loadExtraPackData(ModPlatform::IndexedPack& m, QJsonObject& obj);
-void loadIndexedPackVersions(ModPlatform::IndexedPack& pack,
- QJsonArray& arr,
- const shared_qobject_ptr<QNetworkAccessManager>& network,
- const BaseInstance* inst);
+void loadIndexedPackVersions(ModPlatform::IndexedPack& pack, QJsonArray& arr, const BaseInstance* inst);
auto loadIndexedPackVersion(QJsonObject& obj, QString hash_type = "sha512", QString filename_prefer = "") -> ModPlatform::IndexedVersion;
-auto loadDependencyVersions(const ModPlatform::Dependency& m, QJsonArray& arr) -> ModPlatform::IndexedVersion;
+auto loadDependencyVersions(const ModPlatform::Dependency& m, QJsonArray& arr, const BaseInstance* inst) -> ModPlatform::IndexedVersion;
} // namespace Modrinth
diff --git a/launcher/net/HttpMetaCache.cpp b/launcher/net/HttpMetaCache.cpp
index 7809d40f..f37bc0bf 100644
--- a/launcher/net/HttpMetaCache.cpp
+++ b/launcher/net/HttpMetaCache.cpp
@@ -218,9 +218,24 @@ void HttpMetaCache::Load()
if (!index.open(QIODevice::ReadOnly))
return;
- QJsonDocument json = QJsonDocument::fromJson(index.readAll());
+ QJsonParseError parseError;
+ QJsonDocument json = QJsonDocument::fromJson(index.readAll(), &parseError);
+
+ // Fail if the JSON is invalid.
+ if (parseError.error != QJsonParseError::NoError) {
+ qCritical() << QString("Failed to parse HttpMetaCache file: %1 at offset %2")
+ .arg(parseError.errorString(), QString::number(parseError.offset))
+ .toUtf8();
+ return;
+ }
+
+ // Make sure the root is an object.
+ if (!json.isObject()) {
+ qCritical() << "HttpMetaCache root should be an object.";
+ return;
+ }
- auto root = Json::requireObject(json, "HttpMetaCache root");
+ auto root = json.object();
// check file version first
auto version_val = Json::ensureString(root, "version");
diff --git a/launcher/ui/InstanceWindow.cpp b/launcher/ui/InstanceWindow.cpp
index 7025cb79..bf83a56c 100644
--- a/launcher/ui/InstanceWindow.cpp
+++ b/launcher/ui/InstanceWindow.cpp
@@ -44,8 +44,6 @@
#include <QPushButton>
#include <QScrollBar>
-#include "ui/dialogs/CustomMessageBox.h"
-#include "ui/dialogs/ProgressDialog.h"
#include "ui/widgets/PageContainer.h"
#include "InstancePageProvider.h"
@@ -76,40 +74,44 @@ InstanceWindow::InstanceWindow(InstancePtr instance, QWidget* parent) : QMainWin
// Add custom buttons to the page container layout.
{
- auto horizontalLayout = new QHBoxLayout();
+ auto horizontalLayout = new QHBoxLayout(this);
horizontalLayout->setObjectName(QStringLiteral("horizontalLayout"));
horizontalLayout->setContentsMargins(6, -1, 6, -1);
- auto btnHelp = new QPushButton();
+ auto btnHelp = new QPushButton(this);
btnHelp->setText(tr("Help"));
horizontalLayout->addWidget(btnHelp);
- connect(btnHelp, SIGNAL(clicked(bool)), m_container, SLOT(help()));
+ connect(btnHelp, &QPushButton::clicked, m_container, &PageContainer::help);
auto spacer = new QSpacerItem(40, 20, QSizePolicy::Expanding, QSizePolicy::Minimum);
horizontalLayout->addSpacerItem(spacer);
- m_killButton = new QPushButton();
- horizontalLayout->addWidget(m_killButton);
- connect(m_killButton, SIGNAL(clicked(bool)), SLOT(on_btnKillMinecraft_clicked()));
-
- m_launchOfflineButton = new QPushButton();
- horizontalLayout->addWidget(m_launchOfflineButton);
- m_launchOfflineButton->setText(tr("Launch Offline"));
+ m_launchButton = new QToolButton(this);
+ m_launchButton->setText(tr("&Launch"));
+ m_launchButton->setToolTip(tr("Launch the instance"));
+ m_launchButton->setPopupMode(QToolButton::MenuButtonPopup);
+ m_launchButton->setMinimumWidth(80); // HACK!!
+ horizontalLayout->addWidget(m_launchButton);
+ connect(m_launchButton, &QPushButton::clicked, this, [this] { APPLICATION->launch(m_instance); });
- m_launchDemoButton = new QPushButton();
- horizontalLayout->addWidget(m_launchDemoButton);
- m_launchDemoButton->setText(tr("Launch Demo"));
+ m_killButton = new QPushButton(this);
+ m_killButton->setText(tr("&Kill"));
+ m_killButton->setToolTip(tr("Kill the running instance"));
+ m_killButton->setShortcut(QKeySequence(tr("Ctrl+K")));
+ horizontalLayout->addWidget(m_killButton);
+ connect(m_killButton, &QPushButton::clicked, this, [this] { APPLICATION->kill(m_instance); });
- updateLaunchButtons();
- connect(m_launchOfflineButton, SIGNAL(clicked(bool)), SLOT(on_btnLaunchMinecraftOffline_clicked()));
- connect(m_launchDemoButton, SIGNAL(clicked(bool)), SLOT(on_btnLaunchMinecraftDemo_clicked()));
+ updateButtons();
- m_closeButton = new QPushButton();
+ m_closeButton = new QPushButton(this);
m_closeButton->setText(tr("Close"));
horizontalLayout->addWidget(m_closeButton);
- connect(m_closeButton, SIGNAL(clicked(bool)), SLOT(on_closeButton_clicked()));
+ connect(m_closeButton, &QPushButton::clicked, this, &QMainWindow::close);
m_container->addButtons(horizontalLayout);
+
+ connect(m_instance.get(), &BaseInstance::profilerChanged, this, &InstanceWindow::updateButtons);
+ connect(APPLICATION, &Application::globalSettingsClosed, this, &InstanceWindow::updateButtons);
}
// restore window state
@@ -149,47 +151,18 @@ void InstanceWindow::on_instanceStatusChanged(BaseInstance::Status, BaseInstance
}
}
-void InstanceWindow::updateLaunchButtons()
-{
- if (m_instance->isRunning()) {
- m_launchOfflineButton->setEnabled(false);
- m_launchDemoButton->setEnabled(false);
- m_killButton->setText(tr("Kill"));
- m_killButton->setObjectName("killButton");
- m_killButton->setToolTip(tr("Kill the running instance"));
- } else if (!m_instance->canLaunch()) {
- m_launchOfflineButton->setEnabled(false);
- m_launchDemoButton->setEnabled(false);
- m_killButton->setText(tr("Launch"));
- m_killButton->setObjectName("launchButton");
- m_killButton->setToolTip(tr("Launch the instance"));
- m_killButton->setEnabled(false);
- } else {
- m_launchOfflineButton->setEnabled(true);
-
- // Disable demo-mode if not available.
- auto instance = dynamic_cast<MinecraftInstance*>(m_instance.get());
- if (instance) {
- m_launchDemoButton->setEnabled(instance->supportsDemo());
- }
-
- m_killButton->setText(tr("Launch"));
- m_killButton->setObjectName("launchButton");
- m_killButton->setToolTip(tr("Launch the instance"));
- }
- // NOTE: this is a hack to force the button to recalculate its style
- m_killButton->setStyleSheet("/* */");
- m_killButton->setStyleSheet(QString());
-}
-
-void InstanceWindow::on_btnLaunchMinecraftOffline_clicked()
+void InstanceWindow::updateButtons()
{
- APPLICATION->launch(m_instance, false, false, nullptr);
-}
+ m_launchButton->setEnabled(m_instance->canLaunch());
+ m_killButton->setEnabled(m_instance->isRunning());
-void InstanceWindow::on_btnLaunchMinecraftDemo_clicked()
-{
- APPLICATION->launch(m_instance, false, true, nullptr);
+ QMenu* launchMenu = m_launchButton->menu();
+ if (launchMenu)
+ launchMenu->clear();
+ else
+ launchMenu = new QMenu(this);
+ m_instance->populateLaunchMenu(launchMenu);
+ m_launchButton->setMenu(launchMenu);
}
void InstanceWindow::instanceLaunchTaskChanged(shared_qobject_ptr<LaunchTask> proc)
@@ -199,18 +172,13 @@ void InstanceWindow::instanceLaunchTaskChanged(shared_qobject_ptr<LaunchTask> pr
void InstanceWindow::runningStateChanged(bool running)
{
- updateLaunchButtons();
+ updateButtons();
m_container->refreshContainer();
if (running) {
selectPage("log");
}
}
-void InstanceWindow::on_closeButton_clicked()
-{
- close();
-}
-
void InstanceWindow::closeEvent(QCloseEvent* event)
{
bool proceed = true;
@@ -233,15 +201,6 @@ bool InstanceWindow::saveAll()
return m_container->saveAll();
}
-void InstanceWindow::on_btnKillMinecraft_clicked()
-{
- if (m_instance->isRunning()) {
- APPLICATION->kill(m_instance);
- } else {
- APPLICATION->launch(m_instance, true, false, nullptr);
- }
-}
-
QString InstanceWindow::instanceId()
{
return m_instance->id();
@@ -252,17 +211,15 @@ bool InstanceWindow::selectPage(QString pageId)
return m_container->selectPage(pageId);
}
-BasePage* InstanceWindow::selectedPage() const
-{
- return m_container->selectedPage();
-}
-
void InstanceWindow::refreshContainer()
{
m_container->refreshContainer();
}
-InstanceWindow::~InstanceWindow() {}
+BasePage* InstanceWindow::selectedPage() const
+{
+ return m_container->selectedPage();
+}
bool InstanceWindow::requestClose()
{
diff --git a/launcher/ui/InstanceWindow.h b/launcher/ui/InstanceWindow.h
index 70f206f2..e5bc24d4 100644
--- a/launcher/ui/InstanceWindow.h
+++ b/launcher/ui/InstanceWindow.h
@@ -38,6 +38,7 @@
#include <QMainWindow>
#include <QSystemTrayIcon>
+#include <QToolButton>
#include "LaunchController.h"
#include "launch/LaunchTask.h"
@@ -53,7 +54,7 @@ class InstanceWindow : public QMainWindow, public BasePageContainer {
public:
explicit InstanceWindow(InstancePtr proc, QWidget* parent = 0);
- virtual ~InstanceWindow();
+ virtual ~InstanceWindow() = default;
bool selectPage(QString pageId) override;
BasePage* selectedPage() const override;
@@ -71,11 +72,6 @@ class InstanceWindow : public QMainWindow, public BasePageContainer {
void isClosing();
private slots:
- void on_closeButton_clicked();
- void on_btnKillMinecraft_clicked();
- void on_btnLaunchMinecraftOffline_clicked();
- void on_btnLaunchMinecraftDemo_clicked();
-
void instanceLaunchTaskChanged(shared_qobject_ptr<LaunchTask> proc);
void runningStateChanged(bool running);
void on_instanceStatusChanged(BaseInstance::Status, BaseInstance::Status newStatus);
@@ -84,7 +80,7 @@ class InstanceWindow : public QMainWindow, public BasePageContainer {
void closeEvent(QCloseEvent*) override;
private:
- void updateLaunchButtons();
+ void updateButtons();
private:
shared_qobject_ptr<LaunchTask> m_proc;
@@ -92,7 +88,6 @@ class InstanceWindow : public QMainWindow, public BasePageContainer {
bool m_doNotSave = false;
PageContainer* m_container = nullptr;
QPushButton* m_closeButton = nullptr;
+ QToolButton* m_launchButton = nullptr;
QPushButton* m_killButton = nullptr;
- QPushButton* m_launchOfflineButton = nullptr;
- QPushButton* m_launchDemoButton = nullptr;
};
diff --git a/launcher/ui/MainWindow.cpp b/launcher/ui/MainWindow.cpp
index 067108f2..5e55a5ab 100644
--- a/launcher/ui/MainWindow.cpp
+++ b/launcher/ui/MainWindow.cpp
@@ -43,7 +43,6 @@
#include "FileSystem.h"
#include "MainWindow.h"
-#include "ui/dialogs/ExportToModListDialog.h"
#include "ui_MainWindow.h"
#include <QDir>
@@ -90,17 +89,14 @@
#include <news/NewsChecker.h>
#include <tools/BaseProfiler.h>
#include <updater/ExternalUpdater.h>
-#include "InstancePageProvider.h"
#include "InstanceWindow.h"
-#include "JavaCommon.h"
-#include "LaunchController.h"
#include "ui/dialogs/AboutDialog.h"
#include "ui/dialogs/CopyInstanceDialog.h"
#include "ui/dialogs/CustomMessageBox.h"
-#include "ui/dialogs/EditAccountDialog.h"
#include "ui/dialogs/ExportInstanceDialog.h"
#include "ui/dialogs/ExportPackDialog.h"
+#include "ui/dialogs/ExportToModListDialog.h"
#include "ui/dialogs/IconPickerDialog.h"
#include "ui/dialogs/ImportResourceDialog.h"
#include "ui/dialogs/NewInstanceDialog.h"
@@ -113,17 +109,22 @@
#include "ui/themes/ThemeManager.h"
#include "ui/widgets/LabeledToolButton.h"
+#include "minecraft/PackProfile.h"
+#include "minecraft/VersionFile.h"
#include "minecraft/WorldList.h"
#include "minecraft/mod/ModFolderModel.h"
+#include "minecraft/mod/ResourcePackFolderModel.h"
#include "minecraft/mod/ShaderPackFolderModel.h"
+#include "minecraft/mod/TexturePackFolderModel.h"
#include "minecraft/mod/tasks/LocalResourceParse.h"
+#include "modplatform/ModIndex.h"
#include "modplatform/flame/FlameAPI.h"
+#include "modplatform/flame/FlameModIndex.h"
#include "KonamiCode.h"
#include "InstanceCopyTask.h"
-#include "InstanceImportTask.h"
#include "Json.h"
@@ -553,71 +554,15 @@ void MainWindow::updateMainToolBar()
ui->mainToolBar->setVisible(ui->menuBar->isNativeMenuBar() || !APPLICATION->settings()->get("MenuBarInsteadOfToolBar").toBool());
}
-void MainWindow::updateToolsMenu()
+void MainWindow::updateLaunchButton()
{
- bool currentInstanceRunning = m_selectedInstance && m_selectedInstance->isRunning();
-
- ui->actionLaunchInstance->setDisabled(!m_selectedInstance || currentInstanceRunning);
- ui->actionLaunchInstanceOffline->setDisabled(!m_selectedInstance || currentInstanceRunning);
- ui->actionLaunchInstanceDemo->setDisabled(!m_selectedInstance || currentInstanceRunning);
-
QMenu* launchMenu = ui->actionLaunchInstance->menu();
- if (launchMenu) {
+ if (launchMenu)
launchMenu->clear();
- } else {
+ else
launchMenu = new QMenu(this);
- }
- QAction* normalLaunch = launchMenu->addAction(tr("Launch"));
- normalLaunch->setShortcut(QKeySequence::Open);
- QAction* normalLaunchOffline = launchMenu->addAction(tr("Launch Offline"));
- normalLaunchOffline->setShortcut(QKeySequence(tr("Ctrl+Shift+O")));
- QAction* normalLaunchDemo = launchMenu->addAction(tr("Launch Demo"));
- normalLaunchDemo->setShortcut(QKeySequence(tr("Ctrl+Alt+O")));
- if (m_selectedInstance) {
- normalLaunch->setEnabled(m_selectedInstance->canLaunch());
- normalLaunchOffline->setEnabled(m_selectedInstance->canLaunch());
- normalLaunchDemo->setEnabled(m_selectedInstance->canLaunch());
-
- connect(normalLaunch, &QAction::triggered, [this]() { APPLICATION->launch(m_selectedInstance, true, false); });
- connect(normalLaunchOffline, &QAction::triggered, [this]() { APPLICATION->launch(m_selectedInstance, false, false); });
- connect(normalLaunchDemo, &QAction::triggered, [this]() { APPLICATION->launch(m_selectedInstance, false, true); });
- } else {
- normalLaunch->setDisabled(true);
- normalLaunchOffline->setDisabled(true);
- normalLaunchDemo->setDisabled(true);
- }
-
- // Disable demo-mode if not available.
- auto instance = dynamic_cast<MinecraftInstance*>(m_selectedInstance.get());
- if (instance) {
- normalLaunchDemo->setEnabled(instance->supportsDemo());
- }
-
- QString profilersTitle = tr("Profilers");
- launchMenu->addSeparator()->setText(profilersTitle);
- for (auto profiler : APPLICATION->profilers().values()) {
- QAction* profilerAction = launchMenu->addAction(profiler->name());
- QAction* profilerOfflineAction = launchMenu->addAction(tr("%1 Offline").arg(profiler->name()));
- QString error;
- if (!profiler->check(&error)) {
- profilerAction->setDisabled(true);
- profilerOfflineAction->setDisabled(true);
- QString profilerToolTip = tr("Profiler not setup correctly. Go into settings, \"External Tools\".");
- profilerAction->setToolTip(profilerToolTip);
- profilerOfflineAction->setToolTip(profilerToolTip);
- } else if (m_selectedInstance) {
- profilerAction->setEnabled(m_selectedInstance->canLaunch());
- profilerOfflineAction->setEnabled(m_selectedInstance->canLaunch());
-
- connect(profilerAction, &QAction::triggered,
- [this, profiler]() { APPLICATION->launch(m_selectedInstance, true, false, profiler.get()); });
- connect(profilerOfflineAction, &QAction::triggered,
- [this, profiler]() { APPLICATION->launch(m_selectedInstance, false, false, profiler.get()); });
- } else {
- profilerAction->setDisabled(true);
- profilerOfflineAction->setDisabled(true);
- }
- }
+ if (m_selectedInstance)
+ m_selectedInstance->populateLaunchMenu(launchMenu);
ui->actionLaunchInstance->setMenu(launchMenu);
}
@@ -927,7 +872,7 @@ void MainWindow::finalizeInstance(InstancePtr inst)
} else {
CustomMessageBox::selectable(this, tr("Error"),
tr("The launcher cannot download Minecraft or update instances unless you have at least "
- "one account added.\nPlease add your Mojang or Minecraft account."),
+ "one account added.\nPlease add your Microsoft or Mojang account."),
QMessageBox::Warning)
->show();
}
@@ -980,6 +925,7 @@ void MainWindow::processURLs(QList<QUrl> urls)
if (url.scheme().isEmpty())
url.setScheme("file");
+ ModPlatform::IndexedVersion version;
QMap<QString, QString> extra_info;
QUrl local_url;
if (!url.isLocalFile()) { // download the remote resource and identify
@@ -989,6 +935,11 @@ void MainWindow::processURLs(QList<QUrl> urls)
// format of url curseforge://install?addonId=IDHERE&fileId=IDHERE
QUrlQuery query(url);
+ if (query.allQueryItemValues("addonId").isEmpty() || query.allQueryItemValues("fileId").isEmpty()) {
+ qDebug() << "Invalid curseforge link:" << url;
+ continue;
+ }
+
auto addonId = query.allQueryItemValues("addonId")[0];
auto fileId = query.allQueryItemValues("fileId")[0];
@@ -1000,20 +951,19 @@ void MainWindow::processURLs(QList<QUrl> urls)
auto api = FlameAPI();
auto job = api.getFile(addonId, fileId, array);
- QString resource_name;
-
connect(job.get(), &Task::failed, this,
[this](QString reason) { CustomMessageBox::selectable(this, tr("Error"), reason, QMessageBox::Critical)->show(); });
- connect(job.get(), &Task::succeeded, this, [this, array, addonId, fileId, &dl_url, &resource_name] {
+ connect(job.get(), &Task::succeeded, this, [this, array, addonId, fileId, &dl_url, &version] {
qDebug() << "Returned CFURL Json:\n" << array->toStdString().c_str();
auto doc = Json::requireDocument(*array);
auto data = Json::ensureObject(Json::ensureObject(doc.object()), "data");
// No way to find out if it's a mod or a modpack before here
// And also we need to check if it ends with .zip, instead of any better way
- auto fileName = Json::ensureString(data, "fileName");
+ version = FlameMod::loadIndexedPackVersion(data);
+ auto fileName = version.fileName;
// Have to use ensureString then use QUrl to get proper url encoding
- dl_url = QUrl(Json::ensureString(data, "downloadUrl", "", "downloadUrl"));
+ dl_url = QUrl(version.downloadUrl);
if (!dl_url.isValid()) {
CustomMessageBox::selectable(
this, tr("Error"),
@@ -1024,7 +974,6 @@ void MainWindow::processURLs(QList<QUrl> urls)
}
QFileInfo dl_file(dl_url.fileName());
- resource_name = Json::ensureString(data, "displayName", dl_file.completeBaseName(), "displayName");
});
{ // drop stack
@@ -1099,7 +1048,7 @@ void MainWindow::processURLs(QList<QUrl> urls)
qWarning() << "Importing of Data Packs not supported at this time. Ignoring" << localFileName;
break;
case PackedResourceType::Mod:
- minecraftInst->loaderModList()->installMod(localFileName);
+ minecraftInst->loaderModList()->installMod(localFileName, version);
break;
case PackedResourceType::ShaderPack:
minecraftInst->shaderPackList()->installResource(localFileName);
@@ -1278,7 +1227,7 @@ void MainWindow::globalSettingsClosed()
proxymodel->invalidate();
proxymodel->sort(0);
updateMainToolBar();
- updateToolsMenu();
+ updateLaunchButton();
updateThemeMenu();
updateStatusCenter();
// This needs to be done to prevent UI elements disappearing in the event the config is changed
@@ -1408,10 +1357,11 @@ void MainWindow::on_actionDeleteInstance_triggered()
if (APPLICATION->instances()->trashInstance(id)) {
ui->actionUndoTrashInstance->setEnabled(APPLICATION->instances()->trashedSomething());
- return;
+ } else {
+ APPLICATION->instances()->deleteInstance(id);
}
-
- APPLICATION->instances()->deleteInstance(id);
+ APPLICATION->settings()->set("SelectedInstance", QString());
+ selectionBad();
}
void MainWindow::on_actionExportInstanceZip_triggered()
@@ -1513,20 +1463,6 @@ void MainWindow::activateInstance(InstancePtr instance)
APPLICATION->launch(instance);
}
-void MainWindow::on_actionLaunchInstanceOffline_triggered()
-{
- if (m_selectedInstance) {
- APPLICATION->launch(m_selectedInstance, false);
- }
-}
-
-void MainWindow::on_actionLaunchInstanceDemo_triggered()
-{
- if (m_selectedInstance) {
- APPLICATION->launch(m_selectedInstance, false, true);
- }
-}
-
void MainWindow::on_actionKillInstance_triggered()
{
if (m_selectedInstance && m_selectedInstance->isRunning()) {
@@ -1700,6 +1636,7 @@ void MainWindow::instanceChanged(const QModelIndex& current, [[maybe_unused]] co
}
if (m_selectedInstance) {
disconnect(m_selectedInstance.get(), &BaseInstance::runningStatusChanged, this, &MainWindow::refreshCurrentInstance);
+ disconnect(m_selectedInstance.get(), &BaseInstance::profilerChanged, this, &MainWindow::refreshCurrentInstance);
}
QString id = current.data(InstanceList::InstanceIDRole).toString();
m_selectedInstance = APPLICATION->instances()->getInstanceById(id);
@@ -1707,14 +1644,6 @@ void MainWindow::instanceChanged(const QModelIndex& current, [[maybe_unused]] co
ui->instanceToolBar->setEnabled(true);
setInstanceActionsEnabled(true);
ui->actionLaunchInstance->setEnabled(m_selectedInstance->canLaunch());
- ui->actionLaunchInstanceOffline->setEnabled(m_selectedInstance->canLaunch());
- ui->actionLaunchInstanceDemo->setEnabled(m_selectedInstance->canLaunch());
-
- // Disable demo-mode if not available.
- auto instance = dynamic_cast<MinecraftInstance*>(m_selectedInstance.get());
- if (instance) {
- ui->actionLaunchInstanceDemo->setEnabled(instance->supportsDemo());
- }
ui->actionKillInstance->setEnabled(m_selectedInstance->isRunning());
ui->actionExportInstance->setEnabled(m_selectedInstance->canExport());
@@ -1723,18 +1652,13 @@ void MainWindow::instanceChanged(const QModelIndex& current, [[maybe_unused]] co
updateStatusCenter();
updateInstanceToolIcon(m_selectedInstance->iconKey());
- updateToolsMenu();
+ updateLaunchButton();
APPLICATION->settings()->set("SelectedInstance", m_selectedInstance->id());
connect(m_selectedInstance.get(), &BaseInstance::runningStatusChanged, this, &MainWindow::refreshCurrentInstance);
+ connect(m_selectedInstance.get(), &BaseInstance::profilerChanged, this, &MainWindow::refreshCurrentInstance);
} else {
- ui->instanceToolBar->setEnabled(false);
- setInstanceActionsEnabled(false);
- ui->actionLaunchInstance->setEnabled(false);
- ui->actionLaunchInstanceOffline->setEnabled(false);
- ui->actionLaunchInstanceDemo->setEnabled(false);
- ui->actionKillInstance->setEnabled(false);
APPLICATION->settings()->set("SelectedInstance", QString());
selectionBad();
return;
@@ -1759,11 +1683,12 @@ void MainWindow::selectionBad()
{
// start by reseting everything...
m_selectedInstance = nullptr;
+ m_statusLeft->setText(tr("No instance selected"));
statusBar()->clearMessage();
ui->instanceToolBar->setEnabled(false);
setInstanceActionsEnabled(false);
- updateToolsMenu();
+ updateLaunchButton();
renameButton->setText(tr("Rename Instance"));
updateInstanceToolIcon("grass");
@@ -1810,7 +1735,9 @@ void MainWindow::updateStatusCenter()
int timePlayed = APPLICATION->instances()->getTotalPlayTime();
if (timePlayed > 0) {
- m_statusCenter->setText(tr("Total playtime: %1").arg(Time::prettifyDuration(timePlayed)));
+ m_statusCenter->setText(
+ tr("Total playtime: %1")
+ .arg(Time::prettifyDuration(timePlayed, APPLICATION->settings()->get("ShowGameTimeWithoutDays").toBool())));
}
}
// "Instance actions" are actions that require an instance to be selected (i.e. "new instance" is not here)
@@ -1826,7 +1753,7 @@ void MainWindow::setInstanceActionsEnabled(bool enabled)
ui->actionCreateInstanceShortcut->setEnabled(enabled);
}
-void MainWindow::refreshCurrentInstance([[maybe_unused]] bool running)
+void MainWindow::refreshCurrentInstance()
{
auto current = view->selectionModel()->currentIndex();
instanceChanged(current, current);
diff --git a/launcher/ui/MainWindow.h b/launcher/ui/MainWindow.h
index 9fd72d25..0b614452 100644
--- a/launcher/ui/MainWindow.h
+++ b/launcher/ui/MainWindow.h
@@ -144,10 +144,6 @@ class MainWindow : public QMainWindow {
void on_actionLaunchInstance_triggered();
- void on_actionLaunchInstanceOffline_triggered();
-
- void on_actionLaunchInstanceDemo_triggered();
-
void on_actionKillInstance_triggered();
void on_actionDeleteInstance_triggered();
@@ -155,10 +151,7 @@ class MainWindow : public QMainWindow {
void deleteGroup();
void undoTrashInstance();
- inline void on_actionExportInstance_triggered()
- {
- on_actionExportInstanceZip_triggered();
- }
+ inline void on_actionExportInstance_triggered() { on_actionExportInstanceZip_triggered(); }
void on_actionExportInstanceZip_triggered();
void on_actionExportInstanceMrPack_triggered();
void on_actionExportInstanceFlamePack_triggered();
@@ -181,7 +174,7 @@ class MainWindow : public QMainWindow {
void updateMainToolBar();
- void updateToolsMenu();
+ void updateLaunchButton();
void updateThemeMenu();
@@ -215,7 +208,7 @@ class MainWindow : public QMainWindow {
void keyReleaseEvent(QKeyEvent* event) override;
#endif
- void refreshCurrentInstance(bool running);
+ void refreshCurrentInstance();
private:
void retranslateUi();
diff --git a/launcher/ui/MainWindow.ui b/launcher/ui/MainWindow.ui
index 6ef32099..91b2c270 100644
--- a/launcher/ui/MainWindow.ui
+++ b/launcher/ui/MainWindow.ui
@@ -440,22 +440,6 @@
<string>Ctrl+D</string>
</property>
</action>
- <action name="actionLaunchInstanceOffline">
- <property name="text">
- <string>Launch &amp;Offline</string>
- </property>
- <property name="toolTip">
- <string>Launch the selected instance in offline mode.</string>
- </property>
- </action>
- <action name="actionLaunchInstanceDemo">
- <property name="text">
- <string>Launch &amp;Demo</string>
- </property>
- <property name="toolTip">
- <string>Launch the selected instance in demo mode.</string>
- </property>
- </action>
<action name="actionExportInstance">
<property name="icon">
<iconset theme="export">
diff --git a/launcher/ui/dialogs/ModUpdateDialog.cpp b/launcher/ui/dialogs/ModUpdateDialog.cpp
index 66d7e3af..b82442ea 100644
--- a/launcher/ui/dialogs/ModUpdateDialog.cpp
+++ b/launcher/ui/dialogs/ModUpdateDialog.cpp
@@ -8,8 +8,6 @@
#include "modplatform/flame/FlameAPI.h"
#include "ui_ReviewMessageBox.h"
-#include "FileSystem.h"
-#include "Json.h"
#include "Markdown.h"
#include "tasks/ConcurrentTask.h"
@@ -33,9 +31,9 @@ static std::list<Version> mcVersions(BaseInstance* inst)
return { static_cast<MinecraftInstance*>(inst)->getPackProfile()->getComponent("net.minecraft")->getVersion() };
}
-static std::optional<ResourceAPI::ModLoaderTypes> mcLoaders(BaseInstance* inst)
+static std::optional<ModPlatform::ModLoaderTypes> mcLoaders(BaseInstance* inst)
{
- return { static_cast<MinecraftInstance*>(inst)->getPackProfile()->getModLoaders() };
+ return { static_cast<MinecraftInstance*>(inst)->getPackProfile()->getSupportedModLoaders() };
}
ModUpdateDialog::ModUpdateDialog(QWidget* parent,
diff --git a/launcher/ui/dialogs/ResourceDownloadDialog.cpp b/launcher/ui/dialogs/ResourceDownloadDialog.cpp
index a45165ae..9ebf5dc3 100644
--- a/launcher/ui/dialogs/ResourceDownloadDialog.cpp
+++ b/launcher/ui/dialogs/ResourceDownloadDialog.cpp
@@ -258,7 +258,7 @@ QList<BasePage*> ModDownloadDialog::getPages()
{
QList<BasePage*> pages;
- auto loaders = static_cast<MinecraftInstance*>(m_instance)->getPackProfile()->getModLoaders().value();
+ auto loaders = static_cast<MinecraftInstance*>(m_instance)->getPackProfile()->getSupportedModLoaders().value();
if (ModrinthAPI::validateModLoaders(loaders))
pages.append(ModrinthModPage::create(this, *m_instance));
diff --git a/launcher/ui/pages/global/AccountListPage.cpp b/launcher/ui/pages/global/AccountListPage.cpp
index 5c6fb092..c95bfabd 100644
--- a/launcher/ui/pages/global/AccountListPage.cpp
+++ b/launcher/ui/pages/global/AccountListPage.cpp
@@ -64,7 +64,8 @@ AccountListPage::AccountListPage(QWidget* parent) : QMainWindow(parent), ui(new
ui->setupUi(this);
ui->listView->setEmptyString(
tr("Welcome!\n"
- "If you're new here, you can click the \"Add\" button to add your Mojang or Minecraft account."));
+ "If you're new here, you can select the \"Add Microsoft\" or \"Add Mojang\" buttons to link your Microsoft and/or Mojang "
+ "accounts."));
ui->listView->setEmptyMode(VersionListView::String);
ui->listView->setContextMenuPolicy(Qt::CustomContextMenu);
@@ -85,6 +86,8 @@ AccountListPage::AccountListPage(QWidget* parent) : QMainWindow(parent), ui(new
connect(selectionModel, &QItemSelectionModel::selectionChanged,
[this]([[maybe_unused]] const QItemSelection& sel, [[maybe_unused]] const QItemSelection& dsel) { updateButtonStates(); });
connect(ui->listView, &VersionListView::customContextMenuRequested, this, &AccountListPage::ShowContextMenu);
+ connect(ui->listView, &VersionListView::activated, this,
+ [this](const QModelIndex& index) { m_accounts->setDefaultAccount(m_accounts->at(index.row())); });
connect(m_accounts.get(), &AccountList::listChanged, this, &AccountListPage::listChanged);
connect(m_accounts.get(), &AccountList::listActivityChanged, this, &AccountListPage::listChanged);
diff --git a/launcher/ui/pages/global/JavaPage.cpp b/launcher/ui/pages/global/JavaPage.cpp
index 45d8f018..ac50319e 100644
--- a/launcher/ui/pages/global/JavaPage.cpp
+++ b/launcher/ui/pages/global/JavaPage.cpp
@@ -185,6 +185,7 @@ void JavaPage::updateThresholds()
{
auto sysMiB = Sys::getSystemRam() / Sys::mebibyte;
unsigned int maxMem = ui->maxMemSpinBox->value();
+ unsigned int minMem = ui->minMemSpinBox->value();
QString iconName;
@@ -194,6 +195,9 @@ void JavaPage::updateThresholds()
} else if (maxMem > (sysMiB * 0.9)) {
iconName = "status-yellow";
ui->labelMaxMemIcon->setToolTip(tr("Your maximum memory allocation approaches your system memory capacity."));
+ } else if (maxMem < minMem) {
+ iconName = "status-yellow";
+ ui->labelMaxMemIcon->setToolTip(tr("Your maximum memory allocation is smaller than the minimum value"));
} else {
iconName = "status-good";
ui->labelMaxMemIcon->setToolTip("");
diff --git a/launcher/ui/pages/global/MinecraftPage.cpp b/launcher/ui/pages/global/MinecraftPage.cpp
index 1c774721..553cefd8 100644
--- a/launcher/ui/pages/global/MinecraftPage.cpp
+++ b/launcher/ui/pages/global/MinecraftPage.cpp
@@ -2,7 +2,6 @@
/*
* Prism Launcher - Minecraft Launcher
* Copyright (c) 2022 Jamie Mansfield <jmansfield@cadixdev.org>
- * Copyright (C) 2023 seth <getchoo at tuta dot io>
*
* 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
@@ -115,13 +114,11 @@ void MinecraftPage::applySettings()
s->set("ShowGameTime", ui->showGameTime->isChecked());
s->set("ShowGlobalGameTime", ui->showGlobalGameTime->isChecked());
s->set("RecordGameTime", ui->recordGameTime->isChecked());
+ s->set("ShowGameTimeWithoutDays", ui->showGameTimeWithoutDays->isChecked());
// Miscellaneous
s->set("CloseAfterLaunch", ui->closeAfterLaunchCheck->isChecked());
s->set("QuitAfterGameStop", ui->quitAfterGameStopCheck->isChecked());
-
- // Mod loader settings
- s->set("DisableQuiltBeacon", ui->disableQuiltBeaconCheckBox->isChecked());
}
void MinecraftPage::loadSettings()
@@ -169,11 +166,10 @@ void MinecraftPage::loadSettings()
ui->showGameTime->setChecked(s->get("ShowGameTime").toBool());
ui->showGlobalGameTime->setChecked(s->get("ShowGlobalGameTime").toBool());
ui->recordGameTime->setChecked(s->get("RecordGameTime").toBool());
+ ui->showGameTimeWithoutDays->setChecked(s->get("ShowGameTimeWithoutDays").toBool());
ui->closeAfterLaunchCheck->setChecked(s->get("CloseAfterLaunch").toBool());
ui->quitAfterGameStopCheck->setChecked(s->get("QuitAfterGameStop").toBool());
-
- ui->disableQuiltBeaconCheckBox->setChecked(s->get("DisableQuiltBeacon").toBool());
}
void MinecraftPage::retranslate()
diff --git a/launcher/ui/pages/global/MinecraftPage.ui b/launcher/ui/pages/global/MinecraftPage.ui
index 98e90e4e..b5cfa659 100644
--- a/launcher/ui/pages/global/MinecraftPage.ui
+++ b/launcher/ui/pages/global/MinecraftPage.ui
@@ -138,6 +138,13 @@
</property>
</widget>
</item>
+ <item>
+ <widget class="QCheckBox" name="showGameTimeWithoutDays">
+ <property name="text">
+ <string>Show time spent playing in hours</string>
+ </property>
+ </widget>
+ </item>
</layout>
</widget>
</item>
@@ -191,25 +198,6 @@
</attribute>
<layout class="QVBoxLayout" name="verticalLayout_12">
<item>
- <widget class="QGroupBox" name="modLoaderSettingsGroupBox">
- <property name="title">
- <string>Mod loader settings</string>
- </property>
- <layout class="QVBoxLayout" name="verticalLayout_13">
- <item>
- <widget class="QCheckBox" name="disableQuiltBeaconCheckBox">
- <property name="text">
- <string>Disable Quilt Loader Beacon</string>
- </property>
- <property name="toolTip">
- <string>Disable Quilt loader's beacon for counting monthly active users</string>
- </property>
- </widget>
- </item>
- </layout>
- </widget>
- </item>
- <item>
<widget class="QGroupBox" name="nativeLibWorkaroundGroupBox">
<property name="title">
<string>Native library workarounds</string>
diff --git a/launcher/ui/pages/instance/ExternalResourcesPage.cpp b/launcher/ui/pages/instance/ExternalResourcesPage.cpp
index 719db879..1a8fafa9 100644
--- a/launcher/ui/pages/instance/ExternalResourcesPage.cpp
+++ b/launcher/ui/pages/instance/ExternalResourcesPage.cpp
@@ -152,6 +152,7 @@ void ExternalResourcesPage::retranslate()
void ExternalResourcesPage::itemActivated(const QModelIndex&)
{
auto selection = m_filterModel->mapSelectionToSource(ui->treeView->selectionModel()->selection());
+ m_model->setResourceEnabled(selection.indexes(), EnableAction::TOGGLE);
}
void ExternalResourcesPage::filterTextChanged(const QString& newContents)
diff --git a/launcher/ui/pages/instance/InstanceSettingsPage.cpp b/launcher/ui/pages/instance/InstanceSettingsPage.cpp
index 108f2c27..7aa6bd32 100644
--- a/launcher/ui/pages/instance/InstanceSettingsPage.cpp
+++ b/launcher/ui/pages/instance/InstanceSettingsPage.cpp
@@ -3,7 +3,6 @@
* Prism Launcher - Minecraft Launcher
* Copyright (c) 2022 Jamie Mansfield <jmansfield@cadixdev.org>
* Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
- * Copyright (C) 2023 seth <getchoo at tuta dot io>
*
* 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
@@ -254,14 +253,6 @@ void InstanceSettingsPage::applySettings()
m_settings->reset("InstanceAccountId");
}
- bool overrideModLoaderSettings = ui->modLoaderSettingsGroupBox->isChecked();
- m_settings->set("OverrideModLoaderSettings", overrideModLoaderSettings);
- if (overrideModLoaderSettings) {
- m_settings->set("DisableQuiltBeacon", ui->disableQuiltBeaconCheckBox->isChecked());
- } else {
- m_settings->reset("DisableQuiltBeacon");
- }
-
// FIXME: This should probably be called by a signal instead
m_instance->updateRuntimeContext();
}
@@ -365,10 +356,6 @@ void InstanceSettingsPage::loadSettings()
ui->instanceAccountGroupBox->setChecked(m_settings->get("UseAccountForInstance").toBool());
updateAccountsMenu();
-
- // Mod loader specific settings
- ui->modLoaderSettingsGroupBox->setChecked(m_settings->get("OverrideModLoaderSettings").toBool());
- ui->disableQuiltBeaconCheckBox->setChecked(m_settings->get("DisableQuiltBeacon").toBool());
}
void InstanceSettingsPage::on_javaDetectBtn_clicked()
@@ -491,6 +478,7 @@ void InstanceSettingsPage::updateThresholds()
{
auto sysMiB = Sys::getSystemRam() / Sys::mebibyte;
unsigned int maxMem = ui->maxMemSpinBox->value();
+ unsigned int minMem = ui->minMemSpinBox->value();
QString iconName;
@@ -500,6 +488,9 @@ void InstanceSettingsPage::updateThresholds()
} else if (maxMem > (sysMiB * 0.9)) {
iconName = "status-yellow";
ui->labelMaxMemIcon->setToolTip(tr("Your maximum memory allocation approaches your system memory capacity."));
+ } else if (maxMem < minMem) {
+ iconName = "status-yellow";
+ ui->labelMaxMemIcon->setToolTip(tr("Your maximum memory allocation is smaller than the minimum value"));
} else {
iconName = "status-good";
ui->labelMaxMemIcon->setToolTip("");
diff --git a/launcher/ui/pages/instance/InstanceSettingsPage.ui b/launcher/ui/pages/instance/InstanceSettingsPage.ui
index fcc2a5d0..81cf7093 100644
--- a/launcher/ui/pages/instance/InstanceSettingsPage.ui
+++ b/launcher/ui/pages/instance/InstanceSettingsPage.ui
@@ -584,31 +584,6 @@
</attribute>
<layout class="QVBoxLayout" name="verticalLayout_9">
<item>
- <widget class="QGroupBox" name="modLoaderSettingsGroupBox">
- <property name="checkable">
- <bool>true</bool>
- </property>
- <property name="checked">
- <bool>false</bool>
- </property>
- <property name="title">
- <string>Mod loader settings</string>
- </property>
- <layout class="QVBoxLayout" name="VerticalLayout_16">
- <item>
- <widget class="QCheckBox" name="disableQuiltBeaconCheckBox">
- <property name="text">
- <string>Disable Quilt Loader Beacon</string>
- </property>
- <property name="toolTip">
- <string>Disable Quilt loader's beacon for counting monthly active users</string>
- </property>
- </widget>
- </item>
- </layout>
- </widget>
- </item>
- <item>
<widget class="QGroupBox" name="gameTimeGroupBox">
<property name="enabled">
<bool>true</bool>
diff --git a/launcher/ui/pages/instance/ServersPage.cpp b/launcher/ui/pages/instance/ServersPage.cpp
index da49f4a7..2142e6c9 100644
--- a/launcher/ui/pages/instance/ServersPage.cpp
+++ b/launcher/ui/pages/instance/ServersPage.cpp
@@ -3,7 +3,7 @@
* Prism Launcher - Minecraft Launcher
* Copyright (c) 2022 Jamie Mansfield <jmansfield@cadixdev.org>
* Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
- * Copyright (C) 2022 TheKodeToad <TheKodeToad@proton.me>
+ * Copyright (C) 2023 TheKodeToad <TheKodeToad@proton.me>
*
* 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
@@ -354,14 +354,8 @@ class ServersModel : public QAbstractListModel {
}
}
- virtual int rowCount(const QModelIndex& parent = QModelIndex()) const override
- {
- return parent.isValid() ? 0 : m_servers.size();
- }
- int columnCount(const QModelIndex& parent) const override
- {
- return parent.isValid() ? 0 : COLUMN_COUNT;
- }
+ virtual int rowCount(const QModelIndex& parent = QModelIndex()) const override { return parent.isValid() ? 0 : m_servers.size(); }
+ int columnCount(const QModelIndex& parent) const override { return parent.isValid() ? 0 : COLUMN_COUNT; }
Server* at(int index)
{
@@ -445,10 +439,7 @@ class ServersModel : public QAbstractListModel {
qDebug() << "Changed:" << path;
load();
}
- void fileChanged(const QString& path)
- {
- qDebug() << "Changed:" << path;
- }
+ void fileChanged(const QString& path) { qDebug() << "Changed:" << path; }
private slots:
void save_internal()
@@ -492,10 +483,7 @@ class ServersModel : public QAbstractListModel {
m_saveTimer.stop();
}
- bool saveIsScheduled() const
- {
- return m_dirty;
- }
+ bool saveIsScheduled() const { return m_dirty; }
void updateFSObserver()
{
@@ -743,7 +731,7 @@ void ServersPage::on_actionMove_Down_triggered()
void ServersPage::on_actionJoin_triggered()
{
const auto& address = m_model->at(currentServer)->m_address;
- APPLICATION->launch(m_inst, true, false, nullptr, std::make_shared<MinecraftServerTarget>(MinecraftServerTarget::parse(address)));
+ APPLICATION->launch(m_inst, true, false, std::make_shared<MinecraftServerTarget>(MinecraftServerTarget::parse(address)));
}
#include "ServersPage.moc"
diff --git a/launcher/ui/pages/instance/VersionPage.cpp b/launcher/ui/pages/instance/VersionPage.cpp
index ef029d1d..e22c764c 100644
--- a/launcher/ui/pages/instance/VersionPage.cpp
+++ b/launcher/ui/pages/instance/VersionPage.cpp
@@ -166,14 +166,17 @@ VersionPage::VersionPage(MinecraftInstance* inst, QWidget* parent) : QMainWindow
ui->packageView->setSelectionMode(QAbstractItemView::SingleSelection);
ui->packageView->setContextMenuPolicy(Qt::CustomContextMenu);
- connect(ui->packageView->selectionModel(), &QItemSelectionModel::currentChanged, this, &VersionPage::versionCurrent);
auto smodel = ui->packageView->selectionModel();
+ connect(smodel, &QItemSelectionModel::currentChanged, this, &VersionPage::versionCurrent);
connect(smodel, &QItemSelectionModel::currentChanged, this, &VersionPage::packageCurrent);
-
connect(m_profile.get(), &PackProfile::minecraftChanged, this, &VersionPage::updateVersionControls);
updateVersionControls();
preselect(0);
connect(ui->packageView, &ModListView::customContextMenuRequested, this, &VersionPage::showContextMenu);
+ connect(ui->packageView, &QAbstractItemView::activated, this, [this](const QModelIndex& index) {
+ auto component = m_profile->getComponent(index.row());
+ component->setEnabled(!component->isEnabled());
+ });
connect(ui->filterEdit, &QLineEdit::textChanged, this, &VersionPage::onFilterTextChanged);
}
@@ -408,7 +411,7 @@ void VersionPage::on_actionDownload_All_triggered()
if (!APPLICATION->accounts()->anyAccountIsValid()) {
CustomMessageBox::selectable(this, tr("Error"),
tr("Cannot download Minecraft or update instances unless you have at least "
- "one account added.\nPlease add your Mojang or Minecraft account."),
+ "one account added.\nPlease add your Microsoft or Mojang account."),
QMessageBox::Warning)
->show();
return;
diff --git a/launcher/ui/pages/modplatform/ModModel.cpp b/launcher/ui/pages/modplatform/ModModel.cpp
index b7537890..c628f74a 100644
--- a/launcher/ui/pages/modplatform/ModModel.cpp
+++ b/launcher/ui/pages/modplatform/ModModel.cpp
@@ -33,7 +33,7 @@ ResourceAPI::SearchArgs ModModel::createSearchArguments()
auto sort = getCurrentSortingMethodByIndex();
- return { ModPlatform::ResourceType::MOD, m_next_search_offset, m_search_term, sort, profile->getModLoaders(), versions };
+ return { ModPlatform::ResourceType::MOD, m_next_search_offset, m_search_term, sort, profile->getSupportedModLoaders(), versions };
}
ResourceAPI::VersionSearchArgs ModModel::createVersionsArguments(QModelIndex& entry)
@@ -48,7 +48,7 @@ ResourceAPI::VersionSearchArgs ModModel::createVersionsArguments(QModelIndex& en
if (!m_filter->versions.empty())
versions = m_filter->versions;
- return { pack, versions, profile->getModLoaders() };
+ return { pack, versions, profile->getSupportedModLoaders() };
}
ResourceAPI::ProjectInfoArgs ModModel::createInfoArguments(QModelIndex& entry)
diff --git a/launcher/ui/pages/modplatform/ModPage.cpp b/launcher/ui/pages/modplatform/ModPage.cpp
index 60a43128..7eb08f6a 100644
--- a/launcher/ui/pages/modplatform/ModPage.cpp
+++ b/launcher/ui/pages/modplatform/ModPage.cpp
@@ -124,8 +124,7 @@ void ModPage::updateVersionList()
auto version = current_pack->versions[i];
bool valid = false;
for (auto& mcVer : m_filter->versions) {
- // NOTE: Flame doesn't care about loader, so passing it changes nothing.
- if (validateVersion(version, mcVer.toString(), packProfile->getModLoaders())) {
+ if (validateVersion(version, mcVer.toString(), packProfile->getSupportedModLoaders())) {
valid = true;
break;
}
diff --git a/launcher/ui/pages/modplatform/ModPage.h b/launcher/ui/pages/modplatform/ModPage.h
index 5510c191..5a43e49a 100644
--- a/launcher/ui/pages/modplatform/ModPage.h
+++ b/launcher/ui/pages/modplatform/ModPage.h
@@ -55,7 +55,7 @@ class ModPage : public ResourcePage {
virtual auto validateVersion(ModPlatform::IndexedVersion& ver,
QString mineVer,
- std::optional<ResourceAPI::ModLoaderTypes> loaders = {}) const -> bool = 0;
+ std::optional<ModPlatform::ModLoaderTypes> loaders = {}) const -> bool = 0;
[[nodiscard]] bool supportsFiltering() const override { return true; };
auto getFilter() const -> const std::shared_ptr<ModFilterWidget::Filter> { return m_filter; }
diff --git a/launcher/ui/pages/modplatform/ShaderPackPage.cpp b/launcher/ui/pages/modplatform/ShaderPackPage.cpp
index fbf94e84..586dffc5 100644
--- a/launcher/ui/pages/modplatform/ShaderPackPage.cpp
+++ b/launcher/ui/pages/modplatform/ShaderPackPage.cpp
@@ -3,6 +3,7 @@
// SPDX-License-Identifier: GPL-3.0-only
#include "ShaderPackPage.h"
+#include "modplatform/ModIndex.h"
#include "ui_ResourcePage.h"
#include "ShaderPackModel.h"
@@ -48,7 +49,7 @@ void ShaderPackResourcePage::addResourceToPage(ModPlatform::IndexedPack::Ptr pac
const std::shared_ptr<ResourceFolderModel> base_model)
{
QString custom_target_folder;
- if (version.loaders.contains(QStringLiteral("canvas")))
+ if (version.loaders & ModPlatform::Cauldron)
custom_target_folder = QStringLiteral("resourcepacks");
m_model->addPack(pack, version, base_model, false, custom_target_folder);
}
diff --git a/launcher/ui/pages/modplatform/flame/FlameResourceModels.cpp b/launcher/ui/pages/modplatform/flame/FlameResourceModels.cpp
index 2b020c48..c80e4f99 100644
--- a/launcher/ui/pages/modplatform/flame/FlameResourceModels.cpp
+++ b/launcher/ui/pages/modplatform/flame/FlameResourceModels.cpp
@@ -31,7 +31,7 @@ void FlameModModel::loadIndexedPackVersions(ModPlatform::IndexedPack& m, QJsonAr
auto FlameModModel::loadDependencyVersions(const ModPlatform::Dependency& m, QJsonArray& arr) -> ModPlatform::IndexedVersion
{
- return FlameMod::loadDependencyVersions(m, arr);
+ return FlameMod::loadDependencyVersions(m, arr, &m_base_instance);
}
auto FlameModModel::documentToArray(QJsonDocument& obj) const -> QJsonArray
diff --git a/launcher/ui/pages/modplatform/flame/FlameResourcePages.cpp b/launcher/ui/pages/modplatform/flame/FlameResourcePages.cpp
index dc17e705..1403e98f 100644
--- a/launcher/ui/pages/modplatform/flame/FlameResourcePages.cpp
+++ b/launcher/ui/pages/modplatform/flame/FlameResourcePages.cpp
@@ -68,10 +68,10 @@ FlameModPage::FlameModPage(ModDownloadDialog* dialog, BaseInstance& instance) :
auto FlameModPage::validateVersion(ModPlatform::IndexedVersion& ver,
QString mineVer,
- std::optional<ResourceAPI::ModLoaderTypes> loaders) const -> bool
+ std::optional<ModPlatform::ModLoaderTypes> loaders) const -> bool
{
- Q_UNUSED(loaders);
- return ver.mcVersion.contains(mineVer) && !ver.downloadUrl.isEmpty();
+ return ver.mcVersion.contains(mineVer) && !ver.downloadUrl.isEmpty() &&
+ (!loaders.has_value() || !ver.loaders || loaders.value() & ver.loaders);
}
bool FlameModPage::optedOut(ModPlatform::IndexedVersion& ver) const
diff --git a/launcher/ui/pages/modplatform/flame/FlameResourcePages.h b/launcher/ui/pages/modplatform/flame/FlameResourcePages.h
index c6ebc1ea..035da2d5 100644
--- a/launcher/ui/pages/modplatform/flame/FlameResourcePages.h
+++ b/launcher/ui/pages/modplatform/flame/FlameResourcePages.h
@@ -95,7 +95,7 @@ class FlameModPage : public ModPage {
bool validateVersion(ModPlatform::IndexedVersion& ver,
QString mineVer,
- std::optional<ResourceAPI::ModLoaderTypes> loaders = {}) const override;
+ std::optional<ModPlatform::ModLoaderTypes> loaders = {}) const override;
bool optedOut(ModPlatform::IndexedVersion& ver) const override;
void openUrl(const QUrl& url) override;
diff --git a/launcher/ui/pages/modplatform/modrinth/ModrinthResourceModels.cpp b/launcher/ui/pages/modplatform/modrinth/ModrinthResourceModels.cpp
index ce7475b6..85601829 100644
--- a/launcher/ui/pages/modplatform/modrinth/ModrinthResourceModels.cpp
+++ b/launcher/ui/pages/modplatform/modrinth/ModrinthResourceModels.cpp
@@ -39,12 +39,12 @@ void ModrinthModModel::loadExtraPackInfo(ModPlatform::IndexedPack& m, QJsonObjec
void ModrinthModModel::loadIndexedPackVersions(ModPlatform::IndexedPack& m, QJsonArray& arr)
{
- ::Modrinth::loadIndexedPackVersions(m, arr, APPLICATION->network(), &m_base_instance);
+ ::Modrinth::loadIndexedPackVersions(m, arr, &m_base_instance);
}
auto ModrinthModModel::loadDependencyVersions(const ModPlatform::Dependency& m, QJsonArray& arr) -> ModPlatform::IndexedVersion
{
- return ::Modrinth::loadDependencyVersions(m, arr);
+ return ::Modrinth::loadDependencyVersions(m, arr, &m_base_instance);
}
auto ModrinthModModel::documentToArray(QJsonDocument& obj) const -> QJsonArray
@@ -66,7 +66,7 @@ void ModrinthResourcePackModel::loadExtraPackInfo(ModPlatform::IndexedPack& m, Q
void ModrinthResourcePackModel::loadIndexedPackVersions(ModPlatform::IndexedPack& m, QJsonArray& arr)
{
- ::Modrinth::loadIndexedPackVersions(m, arr, APPLICATION->network(), &m_base_instance);
+ ::Modrinth::loadIndexedPackVersions(m, arr, &m_base_instance);
}
auto ModrinthResourcePackModel::documentToArray(QJsonDocument& obj) const -> QJsonArray
@@ -88,7 +88,7 @@ void ModrinthTexturePackModel::loadExtraPackInfo(ModPlatform::IndexedPack& m, QJ
void ModrinthTexturePackModel::loadIndexedPackVersions(ModPlatform::IndexedPack& m, QJsonArray& arr)
{
- ::Modrinth::loadIndexedPackVersions(m, arr, APPLICATION->network(), &m_base_instance);
+ ::Modrinth::loadIndexedPackVersions(m, arr, &m_base_instance);
}
auto ModrinthTexturePackModel::documentToArray(QJsonDocument& obj) const -> QJsonArray
@@ -110,7 +110,7 @@ void ModrinthShaderPackModel::loadExtraPackInfo(ModPlatform::IndexedPack& m, QJs
void ModrinthShaderPackModel::loadIndexedPackVersions(ModPlatform::IndexedPack& m, QJsonArray& arr)
{
- ::Modrinth::loadIndexedPackVersions(m, arr, APPLICATION->network(), &m_base_instance);
+ ::Modrinth::loadIndexedPackVersions(m, arr, &m_base_instance);
}
auto ModrinthShaderPackModel::documentToArray(QJsonDocument& obj) const -> QJsonArray
diff --git a/launcher/ui/pages/modplatform/modrinth/ModrinthResourcePages.cpp b/launcher/ui/pages/modplatform/modrinth/ModrinthResourcePages.cpp
index 616c1a81..a4197b22 100644
--- a/launcher/ui/pages/modplatform/modrinth/ModrinthResourcePages.cpp
+++ b/launcher/ui/pages/modplatform/modrinth/ModrinthResourcePages.cpp
@@ -65,21 +65,9 @@ ModrinthModPage::ModrinthModPage(ModDownloadDialog* dialog, BaseInstance& instan
auto ModrinthModPage::validateVersion(ModPlatform::IndexedVersion& ver,
QString mineVer,
- std::optional<ResourceAPI::ModLoaderTypes> loaders) const -> bool
+ std::optional<ModPlatform::ModLoaderTypes> loaders) const -> bool
{
- auto loaderCompatible = !loaders.has_value();
-
- if (!loaderCompatible) {
- auto loaderStrings = ModrinthAPI::getModLoaderStrings(loaders.value());
- for (auto remoteLoader : ver.loaders) {
- if (loaderStrings.contains(remoteLoader)) {
- loaderCompatible = true;
- break;
- }
- }
- }
-
- return ver.mcVersion.contains(mineVer) && loaderCompatible;
+ return ver.mcVersion.contains(mineVer) && (!loaders.has_value() || !ver.loaders || loaders.value() & ver.loaders);
}
ModrinthResourcePackPage::ModrinthResourcePackPage(ResourcePackDownloadDialog* dialog, BaseInstance& instance)
diff --git a/launcher/ui/pages/modplatform/modrinth/ModrinthResourcePages.h b/launcher/ui/pages/modplatform/modrinth/ModrinthResourcePages.h
index 86ba1ccb..311bcfe3 100644
--- a/launcher/ui/pages/modplatform/modrinth/ModrinthResourcePages.h
+++ b/launcher/ui/pages/modplatform/modrinth/ModrinthResourcePages.h
@@ -93,7 +93,7 @@ class ModrinthModPage : public ModPage {
[[nodiscard]] inline auto helpPage() const -> QString override { return "Mod-platform"; }
- auto validateVersion(ModPlatform::IndexedVersion& ver, QString mineVer, std::optional<ResourceAPI::ModLoaderTypes> loaders = {}) const
+ auto validateVersion(ModPlatform::IndexedVersion& ver, QString mineVer, std::optional<ModPlatform::ModLoaderTypes> loaders = {}) const
-> bool override;
};
diff --git a/launcher/ui/widgets/JavaSettingsWidget.cpp b/launcher/ui/widgets/JavaSettingsWidget.cpp
index 42279a66..d2d92191 100644
--- a/launcher/ui/widgets/JavaSettingsWidget.cpp
+++ b/launcher/ui/widgets/JavaSettingsWidget.cpp
@@ -186,12 +186,20 @@ QString JavaSettingsWidget::javaPath() const
int JavaSettingsWidget::maxHeapSize() const
{
- return m_maxMemSpinBox->value();
+ auto min = m_minMemSpinBox->value();
+ auto max = m_maxMemSpinBox->value();
+ if (max < min)
+ max = min;
+ return max;
}
int JavaSettingsWidget::minHeapSize() const
{
- return m_minMemSpinBox->value();
+ auto min = m_minMemSpinBox->value();
+ auto max = m_maxMemSpinBox->value();
+ if (min > max)
+ min = max;
+ return min;
}
bool JavaSettingsWidget::permGenEnabled() const
@@ -214,17 +222,9 @@ void JavaSettingsWidget::memoryValueChanged(int)
if (obj == m_minMemSpinBox && min != observedMinMemory) {
observedMinMemory = min;
actuallyChanged = true;
- if (min > max) {
- observedMaxMemory = min;
- m_maxMemSpinBox->setValue(min);
- }
} else if (obj == m_maxMemSpinBox && max != observedMaxMemory) {
observedMaxMemory = max;
actuallyChanged = true;
- if (min > max) {
- observedMinMemory = max;
- m_minMemSpinBox->setValue(max);
- }
} else if (obj == m_permGenSpinBox && permgen != observedPermGenMemory) {
observedPermGenMemory = permgen;
actuallyChanged = true;
@@ -361,8 +361,8 @@ void JavaSettingsWidget::checkJavaPath(const QString& path)
setJavaStatus(JavaStatus::Pending);
m_checker.reset(new JavaChecker());
m_checker->m_path = path;
- m_checker->m_minMem = m_minMemSpinBox->value();
- m_checker->m_maxMem = m_maxMemSpinBox->value();
+ m_checker->m_minMem = minHeapSize();
+ m_checker->m_maxMem = maxHeapSize();
if (m_permGenSpinBox->isVisible()) {
m_checker->m_permGen = m_permGenSpinBox->value();
}
@@ -415,6 +415,9 @@ void JavaSettingsWidget::updateThresholds()
} else if (observedMaxMemory > (m_availableMemory * 0.9)) {
iconName = "status-yellow";
m_labelMaxMemIcon->setToolTip(tr("Your maximum memory allocation approaches your system memory capacity."));
+ } else if (observedMaxMemory < observedMinMemory) {
+ iconName = "status-yellow";
+ m_labelMaxMemIcon->setToolTip(tr("Your maximum memory allocation is smaller than the minimum value"));
} else {
iconName = "status-good";
m_labelMaxMemIcon->setToolTip("");