aboutsummaryrefslogtreecommitdiff
path: root/launcher
diff options
context:
space:
mode:
Diffstat (limited to 'launcher')
-rw-r--r--launcher/Application.cpp16
-rw-r--r--launcher/Application.h2
-rw-r--r--launcher/CMakeLists.txt1
-rw-r--r--launcher/InstancePageProvider.h3
-rw-r--r--launcher/MMCZip.cpp2
-rw-r--r--launcher/minecraft/MinecraftInstance.cpp17
-rw-r--r--launcher/minecraft/MinecraftInstance.h3
-rw-r--r--launcher/minecraft/launch/ScanModFolders.cpp14
-rw-r--r--launcher/minecraft/launch/ScanModFolders.h2
-rw-r--r--launcher/minecraft/mod/ModFolderModel.cpp2
-rw-r--r--launcher/minecraft/mod/ModFolderModel.h2
-rw-r--r--launcher/minecraft/mod/Resource.cpp3
-rw-r--r--launcher/minecraft/mod/ResourceFolderModel.cpp6
-rw-r--r--launcher/minecraft/mod/ResourceFolderModel.h2
-rw-r--r--launcher/minecraft/mod/tasks/LocalModParseTask.cpp53
-rw-r--r--launcher/modplatform/helpers/HashUtils.cpp2
-rw-r--r--launcher/net/Download.cpp14
-rw-r--r--launcher/net/Upload.cpp13
-rw-r--r--launcher/ui/dialogs/BlockedModsDialog.cpp2
-rw-r--r--launcher/ui/pages/global/APIPage.cpp7
-rw-r--r--launcher/ui/pages/global/APIPage.ui51
-rw-r--r--launcher/ui/pages/global/LauncherPage.cpp18
-rw-r--r--launcher/ui/pages/global/LauncherPage.h1
-rw-r--r--launcher/ui/pages/global/LauncherPage.ui66
-rw-r--r--launcher/ui/pages/instance/ModFolderPage.cpp9
-rw-r--r--launcher/ui/pages/instance/ModFolderPage.h13
26 files changed, 276 insertions, 48 deletions
diff --git a/launcher/Application.cpp b/launcher/Application.cpp
index aed862dc..879af535 100644
--- a/launcher/Application.cpp
+++ b/launcher/Application.cpp
@@ -7,6 +7,7 @@
* Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
* Copyright (C) 2022 Lenny McLennington <lenny@sneed.church>
* Copyright (C) 2022 Tayou <tayou@gmx.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
@@ -225,7 +226,7 @@ Application::Application(int &argc, char **argv) : QApplication(argc, argv)
m_serverToJoin = parser.value("server");
m_profileToUse = parser.value("profile");
m_liveCheck = parser.isSet("alive");
-
+
m_instanceIdToShowWindowOf = parser.value("show");
for (auto zip_path : parser.values("import")){
@@ -346,7 +347,7 @@ Application::Application(int &argc, char **argv) : QApplication(argc, argv)
import.command = "import";
import.args.insert("path", zip_url.toString());
m_peerInstance->sendMessage(import.serialize(), timeout);
- }
+ }
}
}
else
@@ -515,6 +516,7 @@ Application::Application(int &argc, char **argv) : QApplication(argc, argv)
m_settings->registerSetting("InstanceDir", "instances");
m_settings->registerSetting({"CentralModsDir", "ModsDir"}, "mods");
m_settings->registerSetting("IconsDir", "icons");
+ m_settings->registerSetting("DownloadsDir", QStandardPaths::writableLocation(QStandardPaths::DownloadLocation));
// Editors
m_settings->registerSetting("JsonEditor", QString());
@@ -660,6 +662,7 @@ Application::Application(int &argc, char **argv) : QApplication(argc, argv)
m_settings->set("FlameKeyOverride", flameKey);
m_settings->reset("CFKeyOverride");
}
+ m_settings->registerSetting("ModrinthToken", "");
m_settings->registerSetting("UserAgentOverride", "");
// Init page provider
@@ -1548,6 +1551,15 @@ QString Application::getFlameAPIKey()
return BuildConfig.FLAME_API_KEY;
}
+QString Application::getModrinthAPIToken()
+{
+ QString tokenOverride = m_settings->get("ModrinthToken").toString();
+ if (!tokenOverride.isEmpty())
+ return tokenOverride;
+
+ return QString();
+}
+
QString Application::getUserAgent()
{
QString uaOverride = m_settings->get("UserAgentOverride").toString();
diff --git a/launcher/Application.h b/launcher/Application.h
index 1b3dc499..91c5fc63 100644
--- a/launcher/Application.h
+++ b/launcher/Application.h
@@ -3,6 +3,7 @@
* Prism Launcher - Minecraft Launcher
* Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
* Copyright (C) 2022 Tayou <tayou@gmx.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
@@ -177,6 +178,7 @@ public:
QString getMSAClientID();
QString getFlameAPIKey();
+ QString getModrinthAPIToken();
QString getUserAgent();
QString getUserAgentUncached();
diff --git a/launcher/CMakeLists.txt b/launcher/CMakeLists.txt
index 66099c4e..c475773d 100644
--- a/launcher/CMakeLists.txt
+++ b/launcher/CMakeLists.txt
@@ -1045,6 +1045,7 @@ target_link_libraries(Launcher_logic
nbt++
${ZLIB_LIBRARIES}
tomlplusplus::tomlplusplus
+ qdcss
BuildConfig
Katabasis
Qt${QT_VERSION_MAJOR}::Widgets
diff --git a/launcher/InstancePageProvider.h b/launcher/InstancePageProvider.h
index 5d8beca9..b4b6e739 100644
--- a/launcher/InstancePageProvider.h
+++ b/launcher/InstancePageProvider.h
@@ -36,9 +36,10 @@ public:
values.append(new VersionPage(onesix.get()));
values.append(ManagedPackPage::createPage(onesix.get()));
auto modsPage = new ModFolderPage(onesix.get(), onesix->loaderModList());
- modsPage->setFilter("%1 (*.zip *.jar *.litemod)");
+ modsPage->setFilter("%1 (*.zip *.jar *.litemod *.nilmod)");
values.append(modsPage);
values.append(new CoreModFolderPage(onesix.get(), onesix->coreModList()));
+ values.append(new NilModFolderPage(onesix.get(), onesix->nilModList()));
values.append(new ResourcePackPage(onesix.get(), onesix->resourcePackList()));
values.append(new TexturePackPage(onesix.get(), onesix->texturePackList()));
values.append(new ShaderPackPage(onesix.get(), onesix->shaderPackList()));
diff --git a/launcher/MMCZip.cpp b/launcher/MMCZip.cpp
index c6d56543..1eda43fe 100644
--- a/launcher/MMCZip.cpp
+++ b/launcher/MMCZip.cpp
@@ -320,7 +320,7 @@ std::optional<QStringList> MMCZip::extractSubDir(QuaZip *zip, const QString & su
if (relative_file_name.isEmpty()) {
target_file_path = target + '/';
} else {
- target_file_path = FS::PathCombine(target_top_dir.path(), sub_path, relative_file_name);
+ target_file_path = FS::PathCombine(target_top_dir.toLocalFile(), sub_path, relative_file_name);
if (relative_file_name.endsWith('/') && !target_file_path.endsWith('/'))
target_file_path += '/';
}
diff --git a/launcher/minecraft/MinecraftInstance.cpp b/launcher/minecraft/MinecraftInstance.cpp
index 4fe234c4..af4da5d0 100644
--- a/launcher/minecraft/MinecraftInstance.cpp
+++ b/launcher/minecraft/MinecraftInstance.cpp
@@ -290,6 +290,11 @@ QString MinecraftInstance::coreModsDir() const
return FS::PathCombine(gameRoot(), "coremods");
}
+QString MinecraftInstance::nilModsDir() const
+{
+ return FS::PathCombine(gameRoot(), "nilmods");
+}
+
QString MinecraftInstance::resourcePacksDir() const
{
return FS::PathCombine(gameRoot(), "resourcepacks");
@@ -1125,6 +1130,18 @@ std::shared_ptr<ModFolderModel> MinecraftInstance::coreModList() const
return m_core_mod_list;
}
+std::shared_ptr<ModFolderModel> MinecraftInstance::nilModList() const
+{
+ if (!m_nil_mod_list)
+ {
+ bool is_indexed = !APPLICATION->settings()->get("ModMetadataDisabled").toBool();
+ m_nil_mod_list.reset(new ModFolderModel(nilModsDir(), is_indexed, false));
+ m_nil_mod_list->disableInteraction(isRunning());
+ connect(this, &BaseInstance::runningStatusChanged, m_nil_mod_list.get(), &ModFolderModel::disableInteraction);
+ }
+ return m_nil_mod_list;
+}
+
std::shared_ptr<ResourcePackFolderModel> MinecraftInstance::resourcePackList() const
{
if (!m_resource_pack_list)
diff --git a/launcher/minecraft/MinecraftInstance.h b/launcher/minecraft/MinecraftInstance.h
index 1bbd7b83..a75fa481 100644
--- a/launcher/minecraft/MinecraftInstance.h
+++ b/launcher/minecraft/MinecraftInstance.h
@@ -84,6 +84,7 @@ public:
QString shaderPacksDir() const;
QString modsRoot() const override;
QString coreModsDir() const;
+ QString nilModsDir() const;
QString modsCacheLocation() const;
QString libDir() const;
QString worldDir() const;
@@ -116,6 +117,7 @@ public:
////// Mod Lists //////
std::shared_ptr<ModFolderModel> loaderModList() const;
std::shared_ptr<ModFolderModel> coreModList() const;
+ std::shared_ptr<ModFolderModel> nilModList() const;
std::shared_ptr<ResourcePackFolderModel> resourcePackList() const;
std::shared_ptr<TexturePackFolderModel> texturePackList() const;
std::shared_ptr<ShaderPackFolderModel> shaderPackList() const;
@@ -170,6 +172,7 @@ protected: // data
std::shared_ptr<PackProfile> m_components;
mutable std::shared_ptr<ModFolderModel> m_loader_mod_list;
mutable std::shared_ptr<ModFolderModel> m_core_mod_list;
+ mutable std::shared_ptr<ModFolderModel> m_nil_mod_list;
mutable std::shared_ptr<ResourcePackFolderModel> m_resource_pack_list;
mutable std::shared_ptr<ShaderPackFolderModel> m_shader_pack_list;
mutable std::shared_ptr<TexturePackFolderModel> m_texture_pack_list;
diff --git a/launcher/minecraft/launch/ScanModFolders.cpp b/launcher/minecraft/launch/ScanModFolders.cpp
index bdffeadd..71e7638c 100644
--- a/launcher/minecraft/launch/ScanModFolders.cpp
+++ b/launcher/minecraft/launch/ScanModFolders.cpp
@@ -55,6 +55,12 @@ void ScanModFolders::executeTask()
if(!cores->update()) {
m_coreModsDone = true;
}
+
+ auto nils = m_inst->nilModList();
+ connect(nils.get(), &ModFolderModel::updateFinished, this, &ScanModFolders::nilModsDone);
+ if(!nils->update()) {
+ m_nilModsDone = true;
+ }
checkDone();
}
@@ -70,9 +76,15 @@ void ScanModFolders::coreModsDone()
checkDone();
}
+void ScanModFolders::nilModsDone()
+{
+ m_nilModsDone = true;
+ checkDone();
+}
+
void ScanModFolders::checkDone()
{
- if(m_modsDone && m_coreModsDone) {
+ if(m_modsDone && m_coreModsDone && m_nilModsDone) {
emitSucceeded();
}
}
diff --git a/launcher/minecraft/launch/ScanModFolders.h b/launcher/minecraft/launch/ScanModFolders.h
index d5989170..111a5850 100644
--- a/launcher/minecraft/launch/ScanModFolders.h
+++ b/launcher/minecraft/launch/ScanModFolders.h
@@ -33,10 +33,12 @@ public:
private slots:
void coreModsDone();
void modsDone();
+ void nilModsDone();
private:
void checkDone();
private: // DATA
bool m_modsDone = false;
+ bool m_nilModsDone = false;
bool m_coreModsDone = false;
};
diff --git a/launcher/minecraft/mod/ModFolderModel.cpp b/launcher/minecraft/mod/ModFolderModel.cpp
index f258ad69..3f31b93c 100644
--- a/launcher/minecraft/mod/ModFolderModel.cpp
+++ b/launcher/minecraft/mod/ModFolderModel.cpp
@@ -50,7 +50,7 @@
#include "minecraft/mod/tasks/ModFolderLoadTask.h"
#include "modplatform/ModIndex.h"
-ModFolderModel::ModFolderModel(const QString &dir, bool is_indexed) : ResourceFolderModel(QDir(dir)), m_is_indexed(is_indexed)
+ModFolderModel::ModFolderModel(const QString &dir, bool is_indexed, bool create_dir) : ResourceFolderModel(QDir(dir), nullptr, create_dir), m_is_indexed(is_indexed)
{
m_column_sort_keys = { SortType::ENABLED, SortType::NAME, SortType::VERSION, SortType::DATE, SortType::PROVIDER };
}
diff --git a/launcher/minecraft/mod/ModFolderModel.h b/launcher/minecraft/mod/ModFolderModel.h
index 6898f6eb..84e70db9 100644
--- a/launcher/minecraft/mod/ModFolderModel.h
+++ b/launcher/minecraft/mod/ModFolderModel.h
@@ -75,7 +75,7 @@ public:
Enable,
Toggle
};
- ModFolderModel(const QString &dir, bool is_indexed = false);
+ ModFolderModel(const QString &dir, bool is_indexed = false, bool create_dir = true);
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
diff --git a/launcher/minecraft/mod/Resource.cpp b/launcher/minecraft/mod/Resource.cpp
index 7c572d92..0d35d755 100644
--- a/launcher/minecraft/mod/Resource.cpp
+++ b/launcher/minecraft/mod/Resource.cpp
@@ -37,6 +37,9 @@ void Resource::parseFile()
if (file_name.endsWith(".zip") || file_name.endsWith(".jar")) {
m_type = ResourceType::ZIPFILE;
file_name.chop(4);
+ } else if (file_name.endsWith(".nilmod")) {
+ m_type = ResourceType::ZIPFILE;
+ file_name.chop(7);
} else if (file_name.endsWith(".litemod")) {
m_type = ResourceType::LITEMOD;
file_name.chop(8);
diff --git a/launcher/minecraft/mod/ResourceFolderModel.cpp b/launcher/minecraft/mod/ResourceFolderModel.cpp
index fdfb434b..f2a77c12 100644
--- a/launcher/minecraft/mod/ResourceFolderModel.cpp
+++ b/launcher/minecraft/mod/ResourceFolderModel.cpp
@@ -12,9 +12,11 @@
#include "tasks/Task.h"
-ResourceFolderModel::ResourceFolderModel(QDir dir, QObject* parent) : QAbstractListModel(parent), m_dir(dir), m_watcher(this)
+ResourceFolderModel::ResourceFolderModel(QDir dir, QObject* parent, bool create_dir) : QAbstractListModel(parent), m_dir(dir), m_watcher(this)
{
- FS::ensureFolderPathExists(m_dir.absolutePath());
+ if (create_dir) {
+ FS::ensureFolderPathExists(m_dir.absolutePath());
+ }
m_dir.setFilter(QDir::Readable | QDir::NoDotAndDotDot | QDir::Files | QDir::Dirs);
m_dir.setSorting(QDir::Name | QDir::IgnoreCase | QDir::LocaleAware);
diff --git a/launcher/minecraft/mod/ResourceFolderModel.h b/launcher/minecraft/mod/ResourceFolderModel.h
index f1bc2dd7..3bd78870 100644
--- a/launcher/minecraft/mod/ResourceFolderModel.h
+++ b/launcher/minecraft/mod/ResourceFolderModel.h
@@ -24,7 +24,7 @@ class QSortFilterProxyModel;
class ResourceFolderModel : public QAbstractListModel {
Q_OBJECT
public:
- ResourceFolderModel(QDir, QObject* parent = nullptr);
+ ResourceFolderModel(QDir, QObject* parent = nullptr, bool create_dir = true);
~ResourceFolderModel() override;
/** Starts watching the paths for changes.
diff --git a/launcher/minecraft/mod/tasks/LocalModParseTask.cpp b/launcher/minecraft/mod/tasks/LocalModParseTask.cpp
index 91cb747f..da27a505 100644
--- a/launcher/minecraft/mod/tasks/LocalModParseTask.cpp
+++ b/launcher/minecraft/mod/tasks/LocalModParseTask.cpp
@@ -3,6 +3,7 @@
#include <quazip/quazip.h>
#include <quazip/quazipfile.h>
#include <toml++/toml.h>
+#include <qdcss.h>
#include <QJsonArray>
#include <QJsonDocument>
#include <QJsonObject>
@@ -285,6 +286,32 @@ ModDetails ReadLiteModInfo(QByteArray contents)
return details;
}
+// https://git.sleeping.town/unascribed/NilLoader/src/commit/d7fc87b255fc31019ff90f80d45894927fac6efc/src/main/java/nilloader/api/NilMetadata.java#L64
+ModDetails ReadNilModInfo(QByteArray contents, QString fname)
+{
+ ModDetails details;
+
+ QDCSS cssData = QDCSS(contents);
+ auto name = cssData.get("@nilmod.name");
+ auto desc = cssData.get("@nilmod.description");
+ auto authors = cssData.get("@nilmod.authors");
+
+ if (name->has_value()) {
+ details.name = name->value();
+ }
+ if (desc->has_value()) {
+ details.description = desc->value();
+ }
+ if (authors->has_value()) {
+ details.authors.append(authors->value());
+ }
+ details.version = cssData.get("@nilmod.version")->value_or("?");
+
+ details.mod_id = fname.remove(".nilmod.css");
+
+ return details;
+}
+
bool process(Mod& mod, ProcessingLevel level)
{
switch (mod.type()) {
@@ -401,6 +428,32 @@ bool processZIP(Mod& mod, ProcessingLevel level)
mod.setDetails(details);
return true;
+ } else if (zip.setCurrentFile("META-INF/nil/mappings.json")) {
+ // nilloader uses the filename of the metadata file for the modid, so we can't know the exact filename
+ // thankfully, there is a good file to use as a canary so we don't look for nil meta all the time
+
+ QString foundNilMeta;
+ for (auto& fname : zip.getFileNameList()) {
+ // nilmods can shade nilloader to be able to run as a standalone agent - which includes nilloader's own meta file
+ if (fname.endsWith(".nilmod.css") && fname != "nilloader.nilmod.css") {
+ foundNilMeta = fname;
+ break;
+ }
+ }
+
+ if (zip.setCurrentFile(foundNilMeta)) {
+ if (!file.open(QIODevice::ReadOnly)) {
+ zip.close();
+ return false;
+ }
+
+ details = ReadNilModInfo(file.readAll(), foundNilMeta);
+ file.close();
+ zip.close();
+
+ mod.setDetails(details);
+ return true;
+ }
}
zip.close();
diff --git a/launcher/modplatform/helpers/HashUtils.cpp b/launcher/modplatform/helpers/HashUtils.cpp
index 2177ddad..81c94e1b 100644
--- a/launcher/modplatform/helpers/HashUtils.cpp
+++ b/launcher/modplatform/helpers/HashUtils.cpp
@@ -79,7 +79,7 @@ void FlameHasher::executeTask()
// CF-specific
auto should_filter_out = [](char c) { return (c == 9 || c == 10 || c == 13 || c == 32); };
- std::ifstream file_stream(StringUtils::toStdString(m_path), std::ifstream::binary);
+ std::ifstream file_stream(StringUtils::toStdString(m_path).c_str(), std::ifstream::binary);
// TODO: This is very heavy work, but apparently QtConcurrent can't use move semantics, so we can't boop this to another thread.
// How do we make this non-blocking then?
m_hash = QString::number(MurmurHash2(std::move(file_stream), 4 * MiB, should_filter_out));
diff --git a/launcher/net/Download.cpp b/launcher/net/Download.cpp
index 5982c8c9..e8a1d0b0 100644
--- a/launcher/net/Download.cpp
+++ b/launcher/net/Download.cpp
@@ -1,8 +1,9 @@
// SPDX-License-Identifier: GPL-3.0-only
/*
- * PolyMC - Minecraft Launcher
+ * Prism Launcher - Minecraft Launcher
* Copyright (c) 2022 flowln <flowlnlnln@gmail.com>
* 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
@@ -113,10 +114,15 @@ void Download::executeTask()
}
request.setHeader(QNetworkRequest::UserAgentHeader, APPLICATION->getUserAgent().toUtf8());
- if (APPLICATION->capabilities() & Application::SupportsFlame
- && request.url().host().contains("api.curseforge.com")) {
+ // TODO remove duplication
+ if (APPLICATION->capabilities() & Application::SupportsFlame && request.url().host() == QUrl(BuildConfig.FLAME_BASE_URL).host()) {
request.setRawHeader("x-api-key", APPLICATION->getFlameAPIKey().toUtf8());
- };
+ } else if (request.url().host() == QUrl(BuildConfig.MODRINTH_PROD_URL).host() ||
+ request.url().host() == QUrl(BuildConfig.MODRINTH_STAGING_URL).host()) {
+ QString token = APPLICATION->getModrinthAPIToken();
+ if (!token.isNull())
+ request.setRawHeader("Authorization", token.toUtf8());
+ }
QNetworkReply* rep = m_network->get(request);
diff --git a/launcher/net/Upload.cpp b/launcher/net/Upload.cpp
index 79b6af8d..ccf43c2d 100644
--- a/launcher/net/Upload.cpp
+++ b/launcher/net/Upload.cpp
@@ -1,8 +1,9 @@
// SPDX-License-Identifier: GPL-3.0-only
/*
- * PolyMC - Minecraft Launcher
+ * Prism Launcher - Minecraft Launcher
* Copyright (c) 2022 flowln <flowlnlnln@gmail.com>
* 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
@@ -216,10 +217,16 @@ namespace Net {
}
request.setHeader(QNetworkRequest::UserAgentHeader, APPLICATION->getUserAgent().toUtf8());
- if (APPLICATION->capabilities() & Application::SupportsFlame
- && request.url().host().contains("api.curseforge.com")) {
+ // TODO remove duplication
+ if (APPLICATION->capabilities() & Application::SupportsFlame && request.url().host() == QUrl(BuildConfig.FLAME_BASE_URL).host()) {
request.setRawHeader("x-api-key", APPLICATION->getFlameAPIKey().toUtf8());
+ } else if (request.url().host() == QUrl(BuildConfig.MODRINTH_PROD_URL).host() ||
+ request.url().host() == QUrl(BuildConfig.MODRINTH_STAGING_URL).host()) {
+ QString token = APPLICATION->getModrinthAPIToken();
+ if (!token.isNull())
+ request.setRawHeader("Authorization", token.toUtf8());
}
+
//TODO other types of post requests ?
request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
QNetworkReply* rep = m_network->post(request, m_post_data);
diff --git a/launcher/ui/dialogs/BlockedModsDialog.cpp b/launcher/ui/dialogs/BlockedModsDialog.cpp
index eb427953..ff885f10 100644
--- a/launcher/ui/dialogs/BlockedModsDialog.cpp
+++ b/launcher/ui/dialogs/BlockedModsDialog.cpp
@@ -184,7 +184,7 @@ void BlockedModsDialog::directoryChanged(QString path)
/// @brief add the user downloads folder and the global mods folder to the filesystem watcher
void BlockedModsDialog::setupWatch()
{
- const QString downloadsFolder = QStandardPaths::writableLocation(QStandardPaths::DownloadLocation);
+ const QString downloadsFolder = APPLICATION->settings()->get("DownloadsDir").toString();
const QString modsFolder = APPLICATION->settings()->get("CentralModsDir").toString();
m_watcher.addPath(downloadsFolder);
m_watcher.addPath(modsFolder);
diff --git a/launcher/ui/pages/global/APIPage.cpp b/launcher/ui/pages/global/APIPage.cpp
index e3d30475..f662ee1c 100644
--- a/launcher/ui/pages/global/APIPage.cpp
+++ b/launcher/ui/pages/global/APIPage.cpp
@@ -1,9 +1,10 @@
// SPDX-License-Identifier: GPL-3.0-only
/*
- * PolyMC - Minecraft Launcher
+ * Prism Launcher - Minecraft Launcher
* Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
* Copyright (c) 2022 Jamie Mansfield <jmansfield@cadixdev.org>
* Copyright (c) 2022 Lenny McLennington <lenny@sneed.church>
+ * 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
@@ -147,6 +148,8 @@ void APIPage::loadSettings()
ui->metaURL->setText(metaURL);
QString flameKey = s->get("FlameKeyOverride").toString();
ui->flameKey->setText(flameKey);
+ QString modrinthToken = s->get("ModrinthToken").toString();
+ ui->modrinthToken->setText(modrinthToken);
QString customUserAgent = s->get("UserAgentOverride").toString();
ui->userAgentLineEdit->setText(customUserAgent);
}
@@ -177,6 +180,8 @@ void APIPage::applySettings()
s->set("MetaURLOverride", metaURL);
QString flameKey = ui->flameKey->text();
s->set("FlameKeyOverride", flameKey);
+ QString modrinthToken = ui->modrinthToken->text();
+ s->set("ModrinthToken", modrinthToken);
s->set("UserAgentOverride", ui->userAgentLineEdit->text());
}
diff --git a/launcher/ui/pages/global/APIPage.ui b/launcher/ui/pages/global/APIPage.ui
index d56a9ef6..40b89d91 100644
--- a/launcher/ui/pages/global/APIPage.ui
+++ b/launcher/ui/pages/global/APIPage.ui
@@ -196,24 +196,69 @@
</widget>
</item>
<item>
- <widget class="QGroupBox" name="groupBox_flame">
+ <widget class="QGroupBox" name="groupBox_modrinth">
<property name="enabled">
<bool>true</bool>
</property>
<property name="title">
- <string>&amp;CurseForge Core API</string>
+ <string>&amp;Modrinth API</string>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="0">
<widget class="QLabel" name="label_8">
<property name="text">
- <string>Note: you probably don't need to set this if CurseForge already works.</string>
+ <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Note: you only need to set this to access private data. Read the &lt;a href=&quot;https://docs.modrinth.com/api-spec/#section/Authentication&quot;&gt;documentation&lt;/a&gt; for more information.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="label_7">
<property name="text">
+ <string>Enter a custom API token for Modrinth here.</string>
+ </property>
+ <property name="textFormat">
+ <enum>Qt::RichText</enum>
+ </property>
+ <property name="wordWrap">
+ <bool>true</bool>
+ </property>
+ <property name="openExternalLinks">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="0">
+ <widget class="QLineEdit" name="modrinthToken">
+ <property name="enabled">
+ <bool>true</bool>
+ </property>
+ <property name="placeholderText">
+ <string>(None)</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <widget class="QGroupBox" name="groupBox_flame">
+ <property name="enabled">
+ <bool>true</bool>
+ </property>
+ <property name="title">
+ <string>&amp;CurseForge Core API</string>
+ </property>
+ <layout class="QGridLayout" name="gridLayout_2">
+ <item row="0" column="0">
+ <widget class="QLabel" name="label_10">
+ <property name="text">
+ <string>Note: you probably don't need to set this if CurseForge already works.</string>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="0">
+ <widget class="QLabel" name="label_9">
+ <property name="text">
<string>Enter a custom API Key for CurseForge here.</string>
</property>
<property name="textFormat">
diff --git a/launcher/ui/pages/global/LauncherPage.cpp b/launcher/ui/pages/global/LauncherPage.cpp
index a9f44c0b..324eb461 100644
--- a/launcher/ui/pages/global/LauncherPage.cpp
+++ b/launcher/ui/pages/global/LauncherPage.cpp
@@ -140,8 +140,8 @@ void LauncherPage::on_instDirBrowseBtn_clicked()
if (result == QMessageBox::Ok)
{
ui->instDirTextBox->setText(cooked_dir);
- }
- }
+ }
+ }
else
{
ui->instDirTextBox->setText(cooked_dir);
@@ -160,6 +160,7 @@ void LauncherPage::on_iconsDirBrowseBtn_clicked()
ui->iconsDirTextBox->setText(cooked_dir);
}
}
+
void LauncherPage::on_modsDirBrowseBtn_clicked()
{
QString raw_dir = QFileDialog::getExistingDirectory(this, tr("Mods Folder"), ui->modsDirTextBox->text());
@@ -172,6 +173,17 @@ void LauncherPage::on_modsDirBrowseBtn_clicked()
}
}
+void LauncherPage::on_downloadsDirBrowseBtn_clicked()
+{
+ QString raw_dir = QFileDialog::getExistingDirectory(this, tr("Downloads Folder"), ui->downloadsDirTextBox->text());
+
+ if (!raw_dir.isEmpty() && QDir(raw_dir).exists())
+ {
+ QString cooked_dir = FS::NormalizePath(raw_dir);
+ ui->downloadsDirTextBox->setText(cooked_dir);
+ }
+}
+
void LauncherPage::on_metadataDisableBtn_clicked()
{
ui->metadataWarningLabel->setHidden(!ui->metadataDisableBtn->isChecked());
@@ -204,6 +216,7 @@ void LauncherPage::applySettings()
s->set("InstanceDir", ui->instDirTextBox->text());
s->set("CentralModsDir", ui->modsDirTextBox->text());
s->set("IconsDir", ui->iconsDirTextBox->text());
+ s->set("DownloadsDir", ui->downloadsDirTextBox->text());
auto sortMode = (InstSortMode)ui->sortingModeGroup->checkedId();
switch (sortMode)
@@ -260,6 +273,7 @@ void LauncherPage::loadSettings()
ui->instDirTextBox->setText(s->get("InstanceDir").toString());
ui->modsDirTextBox->setText(s->get("CentralModsDir").toString());
ui->iconsDirTextBox->setText(s->get("IconsDir").toString());
+ ui->downloadsDirTextBox->setText(s->get("DownloadsDir").toString());
QString sortMode = s->get("InstSortMode").toString();
diff --git a/launcher/ui/pages/global/LauncherPage.h b/launcher/ui/pages/global/LauncherPage.h
index c60156c2..33f66f1b 100644
--- a/launcher/ui/pages/global/LauncherPage.h
+++ b/launcher/ui/pages/global/LauncherPage.h
@@ -88,6 +88,7 @@ slots:
void on_instDirBrowseBtn_clicked();
void on_modsDirBrowseBtn_clicked();
void on_iconsDirBrowseBtn_clicked();
+ void on_downloadsDirBrowseBtn_clicked();
void on_metadataDisableBtn_clicked();
/*!
diff --git a/launcher/ui/pages/global/LauncherPage.ui b/launcher/ui/pages/global/LauncherPage.ui
index f084d970..923b7f95 100644
--- a/launcher/ui/pages/global/LauncherPage.ui
+++ b/launcher/ui/pages/global/LauncherPage.ui
@@ -38,7 +38,7 @@
<enum>QTabWidget::Rounded</enum>
</property>
<property name="currentIndex">
- <number>1</number>
+ <number>0</number>
</property>
<widget class="QWidget" name="featuresTab">
<attribute name="title">
@@ -67,20 +67,32 @@
<string>Folders</string>
</property>
<layout class="QGridLayout" name="foldersBoxLayout">
- <item row="1" column="2">
- <widget class="QToolButton" name="modsDirBrowseBtn">
+ <item row="0" column="2">
+ <widget class="QToolButton" name="instDirBrowseBtn">
<property name="text">
<string notr="true">...</string>
</property>
</widget>
</item>
- <item row="0" column="2">
- <widget class="QToolButton" name="instDirBrowseBtn">
+ <item row="1" column="1">
+ <widget class="QLineEdit" name="modsDirTextBox"/>
+ </item>
+ <item row="0" column="1">
+ <widget class="QLineEdit" name="instDirTextBox"/>
+ </item>
+ <item row="0" column="0">
+ <widget class="QLabel" name="labelInstDir">
<property name="text">
- <string notr="true">...</string>
+ <string>I&amp;nstances:</string>
+ </property>
+ <property name="buddy">
+ <cstring>instDirTextBox</cstring>
</property>
</widget>
</item>
+ <item row="2" column="1">
+ <widget class="QLineEdit" name="iconsDirTextBox"/>
+ </item>
<item row="2" column="2">
<widget class="QToolButton" name="iconsDirBrowseBtn">
<property name="text">
@@ -88,8 +100,22 @@
</property>
</widget>
</item>
- <item row="0" column="1">
- <widget class="QLineEdit" name="instDirTextBox"/>
+ <item row="1" column="2">
+ <widget class="QToolButton" name="modsDirBrowseBtn">
+ <property name="text">
+ <string notr="true">...</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="0">
+ <widget class="QLabel" name="labelModsDir">
+ <property name="text">
+ <string>&amp;Mods:</string>
+ </property>
+ <property name="buddy">
+ <cstring>modsDirTextBox</cstring>
+ </property>
+ </widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="labelIconsDir">
@@ -101,29 +127,23 @@
</property>
</widget>
</item>
- <item row="1" column="1">
- <widget class="QLineEdit" name="modsDirTextBox"/>
- </item>
- <item row="0" column="0">
- <widget class="QLabel" name="labelInstDir">
+ <item row="3" column="0">
+ <widget class="QLabel" name="labelDownloadsDir">
<property name="text">
- <string>I&amp;nstances:</string>
+ <string>&amp;Downloads:</string>
</property>
<property name="buddy">
- <cstring>instDirTextBox</cstring>
+ <cstring>downloadsDirTextBox</cstring>
</property>
</widget>
</item>
- <item row="2" column="1">
- <widget class="QLineEdit" name="iconsDirTextBox"/>
+ <item row="3" column="1">
+ <widget class="QLineEdit" name="downloadsDirTextBox"/>
</item>
- <item row="1" column="0">
- <widget class="QLabel" name="labelModsDir">
+ <item row="3" column="2">
+ <widget class="QToolButton" name="downloadsDirBrowseBtn">
<property name="text">
- <string>&amp;Mods:</string>
- </property>
- <property name="buddy">
- <cstring>modsDirTextBox</cstring>
+ <string>...</string>
</property>
</widget>
</item>
diff --git a/launcher/ui/pages/instance/ModFolderPage.cpp b/launcher/ui/pages/instance/ModFolderPage.cpp
index d9069915..4548af59 100644
--- a/launcher/ui/pages/instance/ModFolderPage.cpp
+++ b/launcher/ui/pages/instance/ModFolderPage.cpp
@@ -273,3 +273,12 @@ bool CoreModFolderPage::shouldDisplay() const
}
return false;
}
+
+NilModFolderPage::NilModFolderPage(BaseInstance* inst, std::shared_ptr<ModFolderModel> mods, QWidget* parent)
+ : ModFolderPage(inst, mods, parent)
+{}
+
+bool NilModFolderPage::shouldDisplay() const
+{
+ return m_model->dir().exists();
+}
diff --git a/launcher/ui/pages/instance/ModFolderPage.h b/launcher/ui/pages/instance/ModFolderPage.h
index ff58b38a..2fc7b574 100644
--- a/launcher/ui/pages/instance/ModFolderPage.h
+++ b/launcher/ui/pages/instance/ModFolderPage.h
@@ -81,3 +81,16 @@ class CoreModFolderPage : public ModFolderPage {
virtual bool shouldDisplay() const override;
};
+
+class NilModFolderPage : public ModFolderPage {
+ public:
+ explicit NilModFolderPage(BaseInstance* inst, std::shared_ptr<ModFolderModel> mods, QWidget* parent = 0);
+ virtual ~NilModFolderPage() = default;
+
+ virtual QString displayName() const override { return tr("Nilmods"); }
+ virtual QIcon icon() const override { return APPLICATION->getThemedIcon("coremods"); }
+ virtual QString id() const override { return "nilmods"; }
+ virtual QString helpPage() const override { return "Nilmods"; }
+
+ virtual bool shouldDisplay() const override;
+};