aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CMakeLists.txt12
-rw-r--r--buildconfig/BuildConfig.cpp.in3
-rw-r--r--buildconfig/BuildConfig.h3
-rw-r--r--cmake/MacOSXBundleInfo.plist.in11
-rw-r--r--launcher/Application.cpp54
-rw-r--r--launcher/Application.h8
-rw-r--r--launcher/InstanceImportTask.cpp35
-rw-r--r--launcher/InstanceImportTask.h1
-rw-r--r--launcher/MangoHud.cpp43
-rw-r--r--launcher/MangoHud.h4
-rw-r--r--launcher/minecraft/MinecraftInstance.cpp29
-rw-r--r--launcher/minecraft/PackProfile.cpp3
-rw-r--r--launcher/minecraft/launch/ExtractNatives.cpp12
-rw-r--r--launcher/modplatform/ResourceAPI.h4
-rw-r--r--launcher/modplatform/flame/FlameAPI.cpp11
-rw-r--r--launcher/modplatform/flame/FlameAPI.h7
-rw-r--r--launcher/modplatform/flame/FlameInstanceCreationTask.cpp8
-rw-r--r--launcher/modplatform/flame/FlamePackExportTask.cpp3
-rw-r--r--launcher/modplatform/import_ftb/PackHelpers.cpp6
-rw-r--r--launcher/modplatform/import_ftb/PackInstallTask.cpp4
-rw-r--r--launcher/modplatform/modrinth/ModrinthAPI.h7
-rw-r--r--launcher/modplatform/modrinth/ModrinthCheckUpdate.cpp4
-rw-r--r--launcher/modplatform/modrinth/ModrinthInstanceCreationTask.cpp4
-rw-r--r--launcher/modplatform/modrinth/ModrinthInstanceCreationTask.h2
-rw-r--r--launcher/modplatform/modrinth/ModrinthPackExportTask.cpp3
-rw-r--r--launcher/resources/multimc/multimc.qrc1
-rw-r--r--launcher/resources/multimc/scalable/instances/neoforged.svg3
-rw-r--r--launcher/ui/MainWindow.cpp103
-rw-r--r--launcher/ui/MainWindow.h2
-rw-r--r--launcher/ui/dialogs/InstallLoaderDialog.cpp4
-rw-r--r--launcher/ui/dialogs/NewInstanceDialog.cpp7
-rw-r--r--launcher/ui/dialogs/NewInstanceDialog.h5
-rw-r--r--launcher/ui/dialogs/SkinUploadDialog.ui6
-rw-r--r--launcher/ui/pages/global/MinecraftPage.cpp35
-rw-r--r--launcher/ui/pages/global/MinecraftPage.h3
-rw-r--r--launcher/ui/pages/global/MinecraftPage.ui40
-rw-r--r--launcher/ui/pages/instance/InstanceSettingsPage.cpp35
-rw-r--r--launcher/ui/pages/instance/InstanceSettingsPage.h3
-rw-r--r--launcher/ui/pages/instance/InstanceSettingsPage.ui44
-rw-r--r--launcher/ui/pages/modplatform/CustomPage.cpp3
-rw-r--r--launcher/ui/pages/modplatform/CustomPage.ui10
-rw-r--r--launcher/ui/pages/modplatform/ImportPage.cpp72
-rw-r--r--launcher/ui/pages/modplatform/ImportPage.h3
-rw-r--r--launcher/ui/pages/modplatform/ImportPage.ui2
-rw-r--r--program_info/org.prismlauncher.PrismLauncher.desktop.in2
-rw-r--r--program_info/win_install.nsi.in4
46 files changed, 577 insertions, 91 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index a2853cb5..638fba05 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -216,6 +216,18 @@ set(Launcher_SUBREDDIT_URL "https://prismlauncher.org/reddit" CACHE STRING "URL
set(Launcher_FORCE_BUNDLED_LIBS OFF CACHE BOOL "Prevent using system libraries, if they are available as submodules")
set(Launcher_QT_VERSION_MAJOR "6" CACHE STRING "Major Qt version to build against")
+# Native libraries
+if(UNIX AND APPLE)
+ set(Launcher_GLFW_LIBRARY_NAME "libglfw.dylib" CACHE STRING "Name of native glfw library")
+ set(Launcher_OPENAL_LIBRARY_NAME "libopenal.dylib" CACHE STRING "Name of native openal library")
+elseif(UNIX)
+ set(Launcher_GLFW_LIBRARY_NAME "libglfw.so" CACHE STRING "Name of native glfw library")
+ set(Launcher_OPENAL_LIBRARY_NAME "libopenal.so" CACHE STRING "Name of native openal library")
+elseif(WIN32)
+ set(Launcher_GLFW_LIBRARY_NAME "glfw.dll" CACHE STRING "Name of native glfw library")
+ set(Launcher_OPENAL_LIBRARY_NAME "OpenAL.dll" CACHE STRING "Name of native openal library")
+endif()
+
# API Keys
# NOTE: These API keys are here for convenience. If you rebrand this software or intend to break the terms of service
# of these platforms, please change these API keys beforehand.
diff --git a/buildconfig/BuildConfig.cpp.in b/buildconfig/BuildConfig.cpp.in
index d7662a7a..1eb0022b 100644
--- a/buildconfig/BuildConfig.cpp.in
+++ b/buildconfig/BuildConfig.cpp.in
@@ -110,6 +110,9 @@ Config::Config()
FLAME_API_KEY = "@Launcher_CURSEFORGE_API_KEY@";
META_URL = "@Launcher_META_URL@";
+ GLFW_LIBRARY_NAME = "@Launcher_GLFW_LIBRARY_NAME@";
+ OPENAL_LIBRARY_NAME = "@Launcher_OPENAL_LIBRARY_NAME@";
+
BUG_TRACKER_URL = "@Launcher_BUG_TRACKER_URL@";
TRANSLATIONS_URL = "@Launcher_TRANSLATIONS_URL@";
MATRIX_URL = "@Launcher_MATRIX_URL@";
diff --git a/buildconfig/BuildConfig.h b/buildconfig/BuildConfig.h
index 387f494f..a5649b98 100644
--- a/buildconfig/BuildConfig.h
+++ b/buildconfig/BuildConfig.h
@@ -134,6 +134,9 @@ class Config {
*/
QString META_URL;
+ QString GLFW_LIBRARY_NAME;
+ QString OPENAL_LIBRARY_NAME;
+
QString BUG_TRACKER_URL;
QString TRANSLATIONS_URL;
QString MATRIX_URL;
diff --git a/cmake/MacOSXBundleInfo.plist.in b/cmake/MacOSXBundleInfo.plist.in
index 400e482f..d36ac3e8 100644
--- a/cmake/MacOSXBundleInfo.plist.in
+++ b/cmake/MacOSXBundleInfo.plist.in
@@ -67,5 +67,16 @@
<string>Alternate</string>
</dict>
</array>
+ <key>CFBundleURLTypes</key>
+ <array>
+ <dict>
+ <key>CFBundleURLName</key>
+ <string>Curseforge</string>
+ <key>CFBundleURLSchemes</key>
+ <array>
+ <string>curseforge</string>
+ </array>
+ </dict>
+ </array>
</dict>
</plist>
diff --git a/launcher/Application.cpp b/launcher/Application.cpp
index 4da7629c..5a952c74 100644
--- a/launcher/Application.cpp
+++ b/launcher/Application.cpp
@@ -194,8 +194,11 @@ Application::Application(int& argc, char** argv) : QApplication(argc, argv)
{ { "s", "server" }, "Join the specified server on launch (only valid in combination with --launch)", "address" },
{ { "a", "profile" }, "Use the account specified by its profile name (only valid in combination with --launch)", "profile" },
{ "alive", "Write a small '" + liveCheckFile + "' file after the launcher starts" },
- { { "I", "import" }, "Import instance from specified zip (local path or URL)", "file" },
+ { { "I", "import" }, "Import instance or resource from specified local path or URL", "url" },
{ "show", "Opens the window for the specified instance (by instance ID)", "show" } });
+ // Has to be positional for some OS to handle that properly
+ parser.addPositionalArgument("URL", "Import the resource(s) at the given URL(s) (same as -I / --import)", "[URL...]");
+
parser.addHelpOption();
parser.addVersionOption();
@@ -208,13 +211,13 @@ Application::Application(int& argc, char** argv) : QApplication(argc, argv)
m_instanceIdToShowWindowOf = parser.value("show");
- for (auto zip_path : parser.values("import")) {
- m_zipsToImport.append(QUrl::fromLocalFile(QFileInfo(zip_path).absoluteFilePath()));
+ for (auto url : parser.values("import")) {
+ m_urlsToImport.append(normalizeImportUrl(url));
}
// treat unspecified positional arguments as import urls
- for (auto zip_path : parser.positionalArguments()) {
- m_zipsToImport.append(QUrl::fromLocalFile(QFileInfo(zip_path).absoluteFilePath()));
+ for (auto url : parser.positionalArguments()) {
+ m_urlsToImport.append(normalizeImportUrl(url));
}
// error if --launch is missing with --server or --profile
@@ -313,11 +316,11 @@ Application::Application(int& argc, char** argv) : QApplication(argc, argv)
activate.command = "activate";
m_peerInstance->sendMessage(activate.serialize(), timeout);
- if (!m_zipsToImport.isEmpty()) {
- for (auto zip_url : m_zipsToImport) {
+ if (!m_urlsToImport.isEmpty()) {
+ for (auto url : m_urlsToImport) {
ApplicationMessage import;
import.command = "import";
- import.args.insert("path", zip_url.toString());
+ import.args.insert("url", url.toString());
m_peerInstance->sendMessage(import.serialize(), timeout);
}
}
@@ -582,7 +585,9 @@ Application::Application(int& argc, char** argv) : QApplication(argc, argv)
// Native library workarounds
m_settings->registerSetting("UseNativeOpenAL", false);
+ m_settings->registerSetting("CustomOpenALPath", "");
m_settings->registerSetting("UseNativeGLFW", false);
+ m_settings->registerSetting("CustomGLFWPath", "");
// Peformance related options
m_settings->registerSetting("EnableFeralGamemode", false);
@@ -842,6 +847,8 @@ Application::Application(int& argc, char** argv) : QApplication(argc, argv)
updateCapabilities();
+ detectLibraries();
+
if (createSetupWizard()) {
return;
}
@@ -978,9 +985,9 @@ void Application::performMainStartupAction()
showMainWindow(false);
qDebug() << "<> Main window shown.";
}
- if (!m_zipsToImport.isEmpty()) {
- qDebug() << "<> Importing from zip:" << m_zipsToImport;
- m_mainWindow->processURLs(m_zipsToImport);
+ if (!m_urlsToImport.isEmpty()) {
+ qDebug() << "<> Importing from url:" << m_urlsToImport;
+ m_mainWindow->processURLs(m_urlsToImport);
}
}
@@ -1022,12 +1029,12 @@ void Application::messageReceived(const QByteArray& message)
if (command == "activate") {
showMainWindow();
} else if (command == "import") {
- QString path = received.args["path"];
- if (path.isEmpty()) {
+ QString url = received.args["url"];
+ if (url.isEmpty()) {
qWarning() << "Received" << command << "message without a zip path/URL.";
return;
}
- m_mainWindow->processURLs({ QUrl::fromLocalFile(QFileInfo(path).absoluteFilePath()) });
+ m_mainWindow->processURLs({ normalizeImportUrl(url) });
} else if (command == "launch") {
QString id = received.args["id"];
QString server = received.args["server"];
@@ -1411,6 +1418,15 @@ void Application::updateCapabilities()
#endif
}
+void Application::detectLibraries()
+{
+#ifdef Q_OS_LINUX
+ m_detectedGLFWPath = MangoHud::findLibrary(BuildConfig.GLFW_LIBRARY_NAME);
+ m_detectedOpenALPath = MangoHud::findLibrary(BuildConfig.OPENAL_LIBRARY_NAME);
+ qDebug() << "Detected native libraries:" << m_detectedGLFWPath << m_detectedOpenALPath;
+#endif
+}
+
QString Application::getJarPath(QString jarFile)
{
QStringList potentialPaths = {
@@ -1589,3 +1605,13 @@ void Application::triggerUpdateCheck()
qDebug() << "Updater not available.";
}
}
+
+QUrl Application::normalizeImportUrl(QString const& url)
+{
+ auto local_file = QFileInfo(url);
+ if (local_file.exists()) {
+ return QUrl::fromLocalFile(local_file.absoluteFilePath());
+ } else {
+ return QUrl::fromUserInput(url);
+ }
+}
diff --git a/launcher/Application.h b/launcher/Application.h
index 8a85fd95..b227bb81 100644
--- a/launcher/Application.h
+++ b/launcher/Application.h
@@ -142,6 +142,8 @@ class Application : public QApplication {
void updateCapabilities();
+ void detectLibraries();
+
/*!
* Finds and returns the full path to a jar file.
* Returns a null-string if it could not be found.
@@ -177,6 +179,8 @@ class Application : public QApplication {
int suitableMaxMem();
+ QUrl normalizeImportUrl(QString const& url);
+
signals:
void updateAllowedChanged(bool status);
void globalSettingsAboutToOpen();
@@ -274,11 +278,13 @@ class Application : public QApplication {
SetupWizard* m_setupWizard = nullptr;
public:
+ QString m_detectedGLFWPath;
+ QString m_detectedOpenALPath;
QString m_instanceIdToLaunch;
QString m_serverToJoin;
QString m_profileToUse;
bool m_liveCheck = false;
- QList<QUrl> m_zipsToImport;
+ QList<QUrl> m_urlsToImport;
QString m_instanceIdToShowWindowOf;
std::unique_ptr<QFile> logFile;
};
diff --git a/launcher/InstanceImportTask.cpp b/launcher/InstanceImportTask.cpp
index 3f948a33..bc139e4f 100644
--- a/launcher/InstanceImportTask.cpp
+++ b/launcher/InstanceImportTask.cpp
@@ -50,6 +50,7 @@
#include "modplatform/technic/TechnicPackProcessor.h"
#include "settings/INISettingsObject.h"
+#include "tasks/Task.h"
#include "net/ApiDownload.h"
@@ -90,25 +91,27 @@ void InstanceImportTask::executeTask()
setStatus(tr("Downloading modpack:\n%1").arg(m_sourceUrl.toString()));
m_downloadRequired = true;
- const QString path(m_sourceUrl.host() + '/' + m_sourceUrl.path());
-
- auto entry = APPLICATION->metacache()->resolveEntry("general", path);
- entry->setStale(true);
- m_archivePath = entry->getFullPath();
-
- m_filesNetJob.reset(new NetJob(tr("Modpack download"), APPLICATION->network()));
- m_filesNetJob->addNetAction(Net::ApiDownload::makeCached(m_sourceUrl, entry));
-
- connect(m_filesNetJob.get(), &NetJob::succeeded, this, &InstanceImportTask::downloadSucceeded);
- connect(m_filesNetJob.get(), &NetJob::progress, this, &InstanceImportTask::downloadProgressChanged);
- connect(m_filesNetJob.get(), &NetJob::stepProgress, this, &InstanceImportTask::propagateStepProgress);
- connect(m_filesNetJob.get(), &NetJob::failed, this, &InstanceImportTask::downloadFailed);
- connect(m_filesNetJob.get(), &NetJob::aborted, this, &InstanceImportTask::downloadAborted);
-
- m_filesNetJob->start();
+ downloadFromUrl();
}
}
+void InstanceImportTask::downloadFromUrl()
+{
+ const QString path = m_sourceUrl.host() + '/' + m_sourceUrl.path();
+ auto entry = APPLICATION->metacache()->resolveEntry("general", path);
+ entry->setStale(true);
+ m_filesNetJob.reset(new NetJob(tr("Modpack download"), APPLICATION->network()));
+ m_filesNetJob->addNetAction(Net::ApiDownload::makeCached(m_sourceUrl, entry));
+ m_archivePath = entry->getFullPath();
+
+ connect(m_filesNetJob.get(), &NetJob::succeeded, this, &InstanceImportTask::downloadSucceeded);
+ connect(m_filesNetJob.get(), &NetJob::progress, this, &InstanceImportTask::downloadProgressChanged);
+ connect(m_filesNetJob.get(), &NetJob::stepProgress, this, &InstanceImportTask::propagateStepProgress);
+ connect(m_filesNetJob.get(), &NetJob::failed, this, &InstanceImportTask::downloadFailed);
+ connect(m_filesNetJob.get(), &NetJob::aborted, this, &InstanceImportTask::downloadAborted);
+ m_filesNetJob->start();
+}
+
void InstanceImportTask::downloadSucceeded()
{
processZipPack();
diff --git a/launcher/InstanceImportTask.h b/launcher/InstanceImportTask.h
index 4459e440..ca3d30ad 100644
--- a/launcher/InstanceImportTask.h
+++ b/launcher/InstanceImportTask.h
@@ -101,4 +101,5 @@ class InstanceImportTask : public InstanceTask {
// FIXME: nuke
QWidget* m_parent;
+ void downloadFromUrl();
};
diff --git a/launcher/MangoHud.cpp b/launcher/MangoHud.cpp
index 5758da3a..ab79f418 100644
--- a/launcher/MangoHud.cpp
+++ b/launcher/MangoHud.cpp
@@ -16,6 +16,7 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
+#include <QDebug>
#include <QDir>
#include <QString>
#include <QStringList>
@@ -26,6 +27,15 @@
#include "Json.h"
#include "MangoHud.h"
+#ifdef __GLIBC__
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE
+#define UNDEF_GNU_SOURCE
+#endif
+#include <dlfcn.h>
+#include <linux/limits.h>
+#endif
+
namespace MangoHud {
QString getLibraryString()
@@ -106,4 +116,37 @@ QString getLibraryString()
return QString();
}
+
+QString findLibrary(QString libName)
+{
+#ifdef __GLIBC__
+ const char* library = libName.toLocal8Bit().constData();
+
+ void* handle = dlopen(library, RTLD_NOW);
+ if (!handle) {
+ qCritical() << "dlopen() failed:" << dlerror();
+ return {};
+ }
+
+ char path[PATH_MAX];
+ if (dlinfo(handle, RTLD_DI_ORIGIN, path) == -1) {
+ qCritical() << "dlinfo() failed:" << dlerror();
+ dlclose(handle);
+ return {};
+ }
+
+ auto fullPath = FS::PathCombine(QString(path), libName);
+
+ dlclose(handle);
+ return fullPath;
+#else
+ qWarning() << "MangoHud::findLibrary is not implemented on this platform";
+ return {};
+#endif
+}
} // namespace MangoHud
+
+#ifdef UNDEF_GNU_SOURCE
+#undef _GNU_SOURCE
+#undef UNDEF_GNU_SOURCE
+#endif
diff --git a/launcher/MangoHud.h b/launcher/MangoHud.h
index 7b7c2849..5361999b 100644
--- a/launcher/MangoHud.h
+++ b/launcher/MangoHud.h
@@ -24,4 +24,6 @@
namespace MangoHud {
QString getLibraryString();
-}
+
+QString findLibrary(QString libName);
+} // namespace MangoHud
diff --git a/launcher/minecraft/MinecraftInstance.cpp b/launcher/minecraft/MinecraftInstance.cpp
index 7e7b3554..699aaffa 100644
--- a/launcher/minecraft/MinecraftInstance.cpp
+++ b/launcher/minecraft/MinecraftInstance.cpp
@@ -170,7 +170,9 @@ void MinecraftInstance::loadSpecificSettings()
// Native library workarounds
auto nativeLibraryWorkaroundsOverride = m_settings->registerSetting("OverrideNativeWorkarounds", false);
m_settings->registerOverride(global_settings->getSetting("UseNativeOpenAL"), nativeLibraryWorkaroundsOverride);
+ m_settings->registerOverride(global_settings->getSetting("CustomOpenALPath"), nativeLibraryWorkaroundsOverride);
m_settings->registerOverride(global_settings->getSetting("UseNativeGLFW"), nativeLibraryWorkaroundsOverride);
+ m_settings->registerOverride(global_settings->getSetting("CustomGLFWPath"), nativeLibraryWorkaroundsOverride);
// Peformance related options
auto performanceOverride = m_settings->registerSetting("OverridePerformance", false);
@@ -437,6 +439,33 @@ QStringList MinecraftInstance::extraArguments()
if (loaders.has_value() && loaders.value() & ResourceAPI::Quilt && settings()->get("DisableQuiltBeacon").toBool())
list.append("-Dloader.disable_beacon=true");
}
+
+ {
+ QString openALPath;
+ QString glfwPath;
+
+ if (settings()->get("UseNativeOpenAL").toBool()) {
+ openALPath = APPLICATION->m_detectedOpenALPath;
+ auto customPath = settings()->get("CustomOpenALPath").toString();
+ if (!customPath.isEmpty())
+ openALPath = customPath;
+ }
+ if (settings()->get("UseNativeGLFW").toBool()) {
+ glfwPath = APPLICATION->m_detectedGLFWPath;
+ auto customPath = settings()->get("CustomGLFWPath").toString();
+ if (!customPath.isEmpty())
+ glfwPath = customPath;
+ }
+
+ QFileInfo openALInfo(openALPath);
+ QFileInfo glfwInfo(glfwPath);
+
+ if (!openALPath.isEmpty() && openALInfo.exists())
+ list.append("-Dorg.lwjgl.openal.libname=" + openALInfo.absoluteFilePath());
+ if (!glfwPath.isEmpty() && glfwInfo.exists())
+ list.append("-Dorg.lwjgl.glfw.libname=" + glfwInfo.absoluteFilePath());
+ }
+
return list;
}
diff --git a/launcher/minecraft/PackProfile.cpp b/launcher/minecraft/PackProfile.cpp
index cf8270cd..92988808 100644
--- a/launcher/minecraft/PackProfile.cpp
+++ b/launcher/minecraft/PackProfile.cpp
@@ -62,7 +62,8 @@
#include "Application.h"
#include "modplatform/ResourceAPI.h"
-static const QMap<QString, ResourceAPI::ModLoaderType> modloaderMapping{ { "net.minecraftforge", ResourceAPI::Forge },
+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 } };
diff --git a/launcher/minecraft/launch/ExtractNatives.cpp b/launcher/minecraft/launch/ExtractNatives.cpp
index cebeaedd..8f3cac4d 100644
--- a/launcher/minecraft/launch/ExtractNatives.cpp
+++ b/launcher/minecraft/launch/ExtractNatives.cpp
@@ -39,7 +39,7 @@ static QString replaceSuffix(QString target, const QString& suffix, const QStrin
return target + replacement;
}
-static bool unzipNatives(QString source, QString targetFolder, bool applyJnilibHack, bool nativeOpenAL, bool nativeGLFW)
+static bool unzipNatives(QString source, QString targetFolder, bool applyJnilibHack)
{
QuaZip zip(source);
if (!zip.open(QuaZip::mdUnzip)) {
@@ -52,12 +52,6 @@ static bool unzipNatives(QString source, QString targetFolder, bool applyJnilibH
do {
QString name = zip.getCurrentFileName();
auto lowercase = name.toLower();
- if (nativeGLFW && name.contains("glfw")) {
- continue;
- }
- if (nativeOpenAL && name.contains("openal")) {
- continue;
- }
if (applyJnilibHack) {
name = replaceSuffix(name, ".jnilib", ".dylib");
}
@@ -83,14 +77,12 @@ void ExtractNatives::executeTask()
return;
}
auto settings = minecraftInstance->settings();
- bool nativeOpenAL = settings->get("UseNativeOpenAL").toBool();
- bool nativeGLFW = settings->get("UseNativeGLFW").toBool();
auto outputPath = minecraftInstance->getNativePath();
auto javaVersion = minecraftInstance->getJavaVersion();
bool jniHackEnabled = javaVersion.major() >= 8;
for (const auto& source : toExtract) {
- if (!unzipNatives(source, outputPath, jniHackEnabled, nativeOpenAL, nativeGLFW)) {
+ if (!unzipNatives(source, outputPath, jniHackEnabled)) {
const char* reason = QT_TR_NOOP("Couldn't extract native jar '%1' to destination '%2'");
emit logLine(QString(reason).arg(source, outputPath), MessageLevel::Fatal);
emitFailed(tr(reason).arg(source, outputPath));
diff --git a/launcher/modplatform/ResourceAPI.h b/launcher/modplatform/ResourceAPI.h
index a92217a0..f6ccb426 100644
--- a/launcher/modplatform/ResourceAPI.h
+++ b/launcher/modplatform/ResourceAPI.h
@@ -54,7 +54,7 @@ class ResourceAPI {
public:
virtual ~ResourceAPI() = default;
- enum ModLoaderType { Forge = 1 << 0, Cauldron = 1 << 1, LiteLoader = 1 << 2, Fabric = 1 << 3, Quilt = 1 << 4 };
+ 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 {
@@ -164,6 +164,8 @@ class ResourceAPI {
static auto getModLoaderString(ModLoaderType type) -> const QString
{
switch (type) {
+ case NeoForge:
+ return "neoforge";
case Forge:
return "forge";
case Cauldron:
diff --git a/launcher/modplatform/flame/FlameAPI.cpp b/launcher/modplatform/flame/FlameAPI.cpp
index 73ed1011..74d7db97 100644
--- a/launcher/modplatform/flame/FlameAPI.cpp
+++ b/launcher/modplatform/flame/FlameAPI.cpp
@@ -204,6 +204,17 @@ Task::Ptr FlameAPI::getFiles(const QStringList& fileIds, std::shared_ptr<QByteAr
return netJob;
}
+Task::Ptr FlameAPI::getFile(const QString& addonId, const QString& fileId, std::shared_ptr<QByteArray> response) const
+{
+ auto netJob = makeShared<NetJob>(QString("Flame::GetFile"), APPLICATION->network());
+ netJob->addNetAction(
+ Net::ApiDownload::makeByteArray(QUrl(QString("https://api.curseforge.com/v1/mods/%1/files/%2").arg(addonId, fileId)), response));
+
+ QObject::connect(netJob.get(), &NetJob::failed, [addonId, fileId] { qDebug() << "Flame API file failure" << addonId << fileId; });
+
+ return netJob;
+}
+
// https://docs.curseforge.com/?python#tocS_ModsSearchSortField
static QList<ResourceAPI::SortingMethod> s_sorts = { { 1, "Featured", QObject::tr("Sort by Featured") },
{ 2, "Popularity", QObject::tr("Sort by Popularity") },
diff --git a/launcher/modplatform/flame/FlameAPI.h b/launcher/modplatform/flame/FlameAPI.h
index 49bc316f..a1256e17 100644
--- a/launcher/modplatform/flame/FlameAPI.h
+++ b/launcher/modplatform/flame/FlameAPI.h
@@ -20,10 +20,11 @@ class FlameAPI : public NetworkResourceAPI {
Task::Ptr getProjects(QStringList addonIds, std::shared_ptr<QByteArray> response) const ove