mirror of
https://github.com/PrismLauncher/PrismLauncher.git
synced 2026-06-29 01:54:20 +03:00
Merge f5d9e25b26 into d2fa7cf7f7
This commit is contained in:
commit
096de785ea
8 changed files with 275 additions and 6 deletions
|
|
@ -255,6 +255,8 @@ set(MINECRAFT_SOURCES
|
|||
minecraft/update/FoldersTask.h
|
||||
minecraft/update/LibrariesTask.cpp
|
||||
minecraft/update/LibrariesTask.h
|
||||
minecraft/update/ModUpdateTask.cpp
|
||||
minecraft/update/ModUpdateTask.h
|
||||
|
||||
minecraft/launch/ClaimAccount.cpp
|
||||
minecraft/launch/ClaimAccount.h
|
||||
|
|
|
|||
|
|
@ -73,6 +73,7 @@
|
|||
#include "minecraft/update/FoldersTask.h"
|
||||
#include "minecraft/update/LegacyFMLLibrariesTask.h"
|
||||
#include "minecraft/update/LibrariesTask.h"
|
||||
#include "minecraft/update/ModUpdateTask.h"
|
||||
|
||||
#include "java/JavaUtils.h"
|
||||
|
||||
|
|
@ -263,10 +264,16 @@ void MinecraftInstance::loadSpecificSettings()
|
|||
connect(dataPacksEnabled.get(), &Setting::SettingChanged, this, [this] { m_data_pack_list.reset(); });
|
||||
connect(dataPacksPath.get(), &Setting::SettingChanged, this, [this] { m_data_pack_list.reset(); });
|
||||
|
||||
// Join server on launch, this does not have a global override
|
||||
// Set mod downloaders, this does not have a global override
|
||||
m_settings->registerSetting("OverrideModDownloadLoaders", false);
|
||||
m_settings->registerSetting("ModDownloadLoaders", "[]");
|
||||
|
||||
// Enable automatic mod updates, this does not have a global override
|
||||
m_settings->registerSetting("AutomaticallyUpdateMods", false);
|
||||
m_settings->registerSetting("AutomaticallyUpdateModsAll", false);
|
||||
m_settings->registerSetting("AutomaticallyUpdateModsEnabled", true);
|
||||
// m_settings->registerSetting("AutomaticallyUpdateModsSpecified", "[]");
|
||||
|
||||
qDebug() << "Instance-type specific settings were loaded!";
|
||||
|
||||
setSpecificSettingsLoaded(true);
|
||||
|
|
@ -1202,6 +1209,13 @@ LaunchTask* MinecraftInstance::createLaunchTask(AuthSessionPtr session, Minecraf
|
|||
process->appendStep(makeShared<ScanModFolders>(pptr));
|
||||
}
|
||||
|
||||
// Update mods if "AutomaticallyUpdateMods" is true.
|
||||
// Must come after ScanModFolders to ensure mods are loaded.
|
||||
if (settings()->get("AutomaticallyUpdateMods").toBool()) {
|
||||
process->appendStep(
|
||||
makeShared<TaskStepWrapper>(pptr, makeShared<ModUpdateTask>(this, settings()->get("AutomaticallyUpdateModsEnabled").toBool())));
|
||||
}
|
||||
|
||||
// make sure we have enough RAM, warn the user if we don't
|
||||
{
|
||||
process->appendStep(makeShared<EnsureAvailableMemory>(pptr, this));
|
||||
|
|
|
|||
|
|
@ -45,19 +45,19 @@ void ScanModFolders::executeTask()
|
|||
auto m_inst = m_parent->instance();
|
||||
|
||||
auto loaders = m_inst->loaderModList();
|
||||
connect(loaders, &ModFolderModel::updateFinished, this, &ScanModFolders::modsDone);
|
||||
connect(loaders, &ModFolderModel::updateFinished, this, &ScanModFolders::modsDone, Qt::UniqueConnection);
|
||||
if (!loaders->update()) {
|
||||
m_modsDone = true;
|
||||
}
|
||||
|
||||
auto cores = m_inst->coreModList();
|
||||
connect(cores, &ModFolderModel::updateFinished, this, &ScanModFolders::coreModsDone);
|
||||
connect(cores, &ModFolderModel::updateFinished, this, &ScanModFolders::coreModsDone, Qt::UniqueConnection);
|
||||
if (!cores->update()) {
|
||||
m_coreModsDone = true;
|
||||
}
|
||||
|
||||
auto nils = m_inst->nilModList();
|
||||
connect(nils, &ModFolderModel::updateFinished, this, &ScanModFolders::nilModsDone);
|
||||
connect(nils, &ModFolderModel::updateFinished, this, &ScanModFolders::nilModsDone, Qt::UniqueConnection);
|
||||
if (!nils->update()) {
|
||||
m_nilModsDone = true;
|
||||
}
|
||||
|
|
@ -66,25 +66,63 @@ void ScanModFolders::executeTask()
|
|||
|
||||
void ScanModFolders::modsDone()
|
||||
{
|
||||
qDebug() << "Check done in ScanModFolders modsDone...";
|
||||
if (!isRunning()) {
|
||||
qDebug() << "ScanModFolders::modsDone called but step not running; ignoring.";
|
||||
return;
|
||||
}
|
||||
m_modsDone = true;
|
||||
checkDone();
|
||||
}
|
||||
|
||||
void ScanModFolders::coreModsDone()
|
||||
{
|
||||
qDebug() << "Check done in ScanModFolders coreModsDone...";
|
||||
if (!isRunning()) {
|
||||
qDebug() << "ScanModFolders::coreModsDone called but step not running; "
|
||||
"ignoring.";
|
||||
return;
|
||||
}
|
||||
m_coreModsDone = true;
|
||||
checkDone();
|
||||
}
|
||||
|
||||
void ScanModFolders::nilModsDone()
|
||||
{
|
||||
qDebug() << "Check done in ScanModFolders nilModsDone...";
|
||||
if (!isRunning()) {
|
||||
qDebug() << "ScanModFolders::nilModsDone called but step not running; ignoring.";
|
||||
return;
|
||||
}
|
||||
m_nilModsDone = true;
|
||||
checkDone();
|
||||
}
|
||||
|
||||
void ScanModFolders::checkDone()
|
||||
{
|
||||
qDebug() << "Check done in ScanModFolders...";
|
||||
if (m_modsDone && m_coreModsDone && m_nilModsDone) {
|
||||
// Disconnect model signals before finishing so the finished step doesn't
|
||||
// receive later updateFinished() notifications and try to finish again.
|
||||
auto m_inst = m_parent->instance();
|
||||
if (m_inst) {
|
||||
disconnect(m_inst->loaderModList(), &ModFolderModel::updateFinished, this, &ScanModFolders::modsDone);
|
||||
disconnect(m_inst->coreModList(), &ModFolderModel::updateFinished, this, &ScanModFolders::coreModsDone);
|
||||
disconnect(m_inst->nilModList(), &ModFolderModel::updateFinished, this, &ScanModFolders::nilModsDone);
|
||||
}
|
||||
|
||||
emitSucceeded();
|
||||
}
|
||||
}
|
||||
|
||||
void ScanModFolders::finalize()
|
||||
{
|
||||
auto m_inst = m_parent->instance();
|
||||
if (!m_inst) {
|
||||
return;
|
||||
}
|
||||
|
||||
disconnect(m_inst->loaderModList(), &ModFolderModel::updateFinished, this, &ScanModFolders::modsDone);
|
||||
disconnect(m_inst->coreModList(), &ModFolderModel::updateFinished, this, &ScanModFolders::coreModsDone);
|
||||
disconnect(m_inst->nilModList(), &ModFolderModel::updateFinished, this, &ScanModFolders::nilModsDone);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -22,10 +22,12 @@ class ScanModFolders : public LaunchStep {
|
|||
Q_OBJECT
|
||||
public:
|
||||
explicit ScanModFolders(LaunchTask* parent) : LaunchStep(parent) {};
|
||||
virtual ~ScanModFolders() {};
|
||||
virtual ~ScanModFolders() = default;
|
||||
|
||||
virtual void executeTask() override;
|
||||
virtual bool canAbort() const override { return false; }
|
||||
virtual void finalize() override;
|
||||
|
||||
private slots:
|
||||
void coreModsDone();
|
||||
void modsDone();
|
||||
|
|
|
|||
125
launcher/minecraft/update/ModUpdateTask.cpp
Normal file
125
launcher/minecraft/update/ModUpdateTask.cpp
Normal file
|
|
@ -0,0 +1,125 @@
|
|||
#include "ModUpdateTask.h"
|
||||
|
||||
#include <ui/dialogs/ProgressDialog.h>
|
||||
#include <ui/dialogs/ResourceUpdateDialog.h>
|
||||
#include "Application.h"
|
||||
#include "BuildConfig.h"
|
||||
#include "launch/LaunchStep.h"
|
||||
#include "minecraft/AssetsUtils.h"
|
||||
#include "minecraft/MinecraftInstance.h"
|
||||
#include "minecraft/PackProfile.h"
|
||||
#include "minecraft/mod/Mod.h"
|
||||
#include "minecraft/mod/ModDetails.h"
|
||||
#include "minecraft/mod/ModFolderModel.h"
|
||||
#include "net/ApiDownload.h"
|
||||
#include "net/ChecksumValidator.h"
|
||||
#include "ui/dialogs/CustomMessageBox.h"
|
||||
|
||||
ModUpdateTask::ModUpdateTask(MinecraftInstance* inst, bool enabledModsOnly)
|
||||
{
|
||||
m_instance = inst;
|
||||
m_enabledModsOnly = enabledModsOnly;
|
||||
}
|
||||
|
||||
void ModUpdateTask::executeTask()
|
||||
{
|
||||
setStatus(tr("Updating mods..."));
|
||||
qDebug() << "Updating mods...";
|
||||
|
||||
if (m_instance->typeName() != "Minecraft") {
|
||||
return; // this is a null instance or a legacy instance
|
||||
}
|
||||
|
||||
auto* profile = static_cast<MinecraftInstance*>(m_instance)->getPackProfile();
|
||||
if (!profile->getModLoaders().has_value()) {
|
||||
emitFailed(tr("Mod updates are unavailable when mod loader is missing!"));
|
||||
return;
|
||||
}
|
||||
|
||||
if (APPLICATION->settings()->get("ModMetadataDisabled").toBool()) {
|
||||
emitFailed(tr("Mod updates are unavailable when metadata is disabled!"));
|
||||
return;
|
||||
}
|
||||
|
||||
// ResourceUpdateDialog only accepts Resource,
|
||||
// so we convert the Mod* list to a Resource* list with a simple static_cast
|
||||
auto model = m_instance->loaderModList();
|
||||
auto _modsList = model->allMods();
|
||||
QList<Resource*> modsList;
|
||||
modsList.reserve(_modsList.size());
|
||||
for (auto mod : _modsList) {
|
||||
modsList.append(static_cast<Resource*>(mod));
|
||||
}
|
||||
|
||||
// Filter out disabled mods if "AutomaticallyUpdateModsEnabled" is true
|
||||
if (m_enabledModsOnly) {
|
||||
modsList.erase(std::remove_if(modsList.begin(), modsList.end(), [](Resource* resource) { return !resource->enabled(); }),
|
||||
modsList.end());
|
||||
}
|
||||
|
||||
// Spawn ResourceUpdateDialog to handle mod updates
|
||||
// 99% copied from ModFolderPage.cpp
|
||||
auto parent = QApplication::activeWindow();
|
||||
ResourceUpdateDialog updateDialog =
|
||||
ResourceUpdateDialog(parent, m_instance, model, modsList, m_includeDeps, profile->getModLoadersList());
|
||||
updateDialog.checkCandidates();
|
||||
|
||||
if (updateDialog.aborted()) {
|
||||
CustomMessageBox::selectable(parent, tr("Aborted"), tr("The mod updater was aborted!"), QMessageBox::Warning)->show();
|
||||
emitAborted();
|
||||
return;
|
||||
}
|
||||
if (updateDialog.noUpdates()) {
|
||||
QString message{ tr("'%1' is up-to-date! :)").arg(modsList.front()->name()) };
|
||||
if (modsList.size() > 1) {
|
||||
if (!m_enabledModsOnly) {
|
||||
message = tr("All mods are up-to-date! :)");
|
||||
} else {
|
||||
message = tr("All enabled mods are up-to-date! :)");
|
||||
}
|
||||
}
|
||||
CustomMessageBox::selectable(parent, tr("Update checker"), message)->exec();
|
||||
emitSucceeded();
|
||||
return;
|
||||
}
|
||||
|
||||
if (updateDialog.exec() != 0) {
|
||||
auto* tasks = new ConcurrentTask("Download Mods", APPLICATION->settings()->get("NumberOfConcurrentDownloads").toInt());
|
||||
connect(tasks, &Task::failed, [this, parent, tasks](const QString& reason) {
|
||||
CustomMessageBox::selectable(parent, tr("Error"), reason, QMessageBox::Critical)->show();
|
||||
tasks->deleteLater();
|
||||
});
|
||||
connect(tasks, &Task::aborted, [this, parent, tasks]() {
|
||||
CustomMessageBox::selectable(parent, tr("Aborted"), tr("Download stopped by user."), QMessageBox::Information)->show();
|
||||
tasks->deleteLater();
|
||||
});
|
||||
connect(tasks, &Task::succeeded, [this, parent, tasks]() {
|
||||
QStringList warnings = tasks->warnings();
|
||||
if (warnings.count()) {
|
||||
CustomMessageBox::selectable(parent, tr("Warnings"), warnings.join('\n'), QMessageBox::Warning)->show();
|
||||
}
|
||||
tasks->deleteLater();
|
||||
});
|
||||
|
||||
for (const auto& task : updateDialog.getTasks()) {
|
||||
tasks->addTask(task);
|
||||
}
|
||||
|
||||
ProgressDialog loadDialog(parent);
|
||||
loadDialog.setSkipButton(true, tr("Abort"));
|
||||
loadDialog.execWithTask(tasks);
|
||||
}
|
||||
model->update();
|
||||
qDebug() << "Finished updating mods...";
|
||||
emitSucceeded();
|
||||
}
|
||||
|
||||
bool ModUpdateTask::canAbort() const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ModUpdateTask::abort()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
27
launcher/minecraft/update/ModUpdateTask.h
Normal file
27
launcher/minecraft/update/ModUpdateTask.h
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
#pragma once
|
||||
#include "net/NetJob.h"
|
||||
#include "tasks/Task.h"
|
||||
class MinecraftInstance;
|
||||
|
||||
class ModUpdateTask : public Task {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
ModUpdateTask(MinecraftInstance* inst, bool enabled);
|
||||
virtual ~ModUpdateTask() = default;
|
||||
|
||||
void executeTask() override;
|
||||
|
||||
bool canAbort() const override;
|
||||
|
||||
public:
|
||||
static QString resourceUrl();
|
||||
|
||||
public slots:
|
||||
bool abort() override;
|
||||
|
||||
private:
|
||||
MinecraftInstance* m_instance;
|
||||
bool m_enabledModsOnly;
|
||||
bool m_includeDeps = true;
|
||||
};
|
||||
|
|
@ -61,6 +61,7 @@ MinecraftSettingsWidget::MinecraftSettingsWidget(MinecraftInstance* instance, QW
|
|||
m_ui->serverJoinGroupBox->hide();
|
||||
m_ui->globalDataPacksGroupBox->hide();
|
||||
m_ui->loaderGroup->hide();
|
||||
m_ui->autoModUpdateGroup->hide();
|
||||
} else {
|
||||
m_javaSettings = new JavaSettingsWidget(m_instance, this);
|
||||
m_ui->javaScrollArea->setWidget(m_javaSettings);
|
||||
|
|
@ -120,6 +121,18 @@ MinecraftSettingsWidget::MinecraftSettingsWidget(MinecraftInstance* instance, QW
|
|||
m_ui->legacyFabric, m_ui->ornithe, m_ui->rift }) {
|
||||
connect(c, &QCheckBox::stateChanged, this, &MinecraftSettingsWidget::saveSelectedLoaders);
|
||||
}
|
||||
|
||||
connect(m_ui->autoModUpdateGroup, &QGroupBox::toggled, this, [this](bool value) {
|
||||
m_instance->settings()->set("AutomaticallyUpdateMods", value);
|
||||
// if (!value) {
|
||||
// m_instance->settings()->reset("AutomaticallyUpdateModsAll");
|
||||
// m_instance->settings()->reset("AutomaticallyUpdateModsEnabled");
|
||||
// }
|
||||
});
|
||||
connect(m_ui->allMods, &QAbstractButton::toggled, this,
|
||||
[this](bool value) { m_instance->settings()->set("AutomaticallyUpdateModsAll", value); });
|
||||
connect(m_ui->enabledMods, &QAbstractButton::toggled, this,
|
||||
[this](bool value) { m_instance->settings()->set("AutomaticallyUpdateModsEnabled", value); });
|
||||
}
|
||||
|
||||
m_ui->maximizedWarning->hide();
|
||||
|
|
@ -248,6 +261,10 @@ void MinecraftSettingsWidget::loadSettings()
|
|||
|
||||
m_ui->serverJoinGroupBox->setChecked(settings->get("JoinServerOnLaunch").toBool());
|
||||
|
||||
m_ui->autoModUpdateGroup->setChecked(settings->get("AutomaticallyUpdateMods").toBool());
|
||||
m_ui->allMods->setChecked(settings->get("AutomaticallyUpdateModsAll").toBool());
|
||||
m_ui->enabledMods->setChecked(settings->get("AutomaticallyUpdateModsEnabled").toBool());
|
||||
|
||||
m_ui->instanceAccountGroupBox->setChecked(settings->get("UseAccountForInstance").toBool());
|
||||
updateAccountsMenu(*settings);
|
||||
|
||||
|
|
@ -455,6 +472,21 @@ void MinecraftSettingsWidget::saveSettings()
|
|||
settings->reset("JoinWorldOnLaunch");
|
||||
}
|
||||
|
||||
bool automaticallyUpdateMods = m_ui->autoModUpdateGroup->isChecked();
|
||||
settings->set("AutomaticallyUpdateMods", automaticallyUpdateMods);
|
||||
// if (automaticallyUpdateMods) {
|
||||
if (m_ui->allMods->isChecked()) {
|
||||
settings->set("AutomaticallyUpdateModsAll", true);
|
||||
settings->set("AutomaticallyUpdateModsEnabled", false);
|
||||
} else {
|
||||
settings->set("AutomaticallyUpdateModsAll", false);
|
||||
settings->set("AutomaticallyUpdateModsEnabled", true);
|
||||
}
|
||||
// } else {
|
||||
// settings->reset("AutomaticallyUpdateModsAll");
|
||||
// settings->reset("AutomaticallyUpdateModsEnabled");
|
||||
// }
|
||||
|
||||
// Use an account for this instance
|
||||
bool useAccountForInstance = m_ui->instanceAccountGroupBox->isChecked();
|
||||
settings->set("UseAccountForInstance", useAccountForInstance);
|
||||
|
|
|
|||
|
|
@ -268,7 +268,7 @@
|
|||
<widget class="QLabel" name="label_3">
|
||||
<property name="text">
|
||||
<string>Allows installing data packs across all worlds if an applicable mod is installed.
|
||||
It is most likely you will need to change the path - please refer to the mod's website.</string>
|
||||
It is most likely you will need to change the path - please refer to the mod's website.</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
|
|
@ -554,6 +554,35 @@ It is most likely you will need to change the path - please refer to the mod's w
|
|||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="autoModUpdateGroup">
|
||||
<property name="title">
|
||||
<string>Automatically Update Mods</string>
|
||||
</property>
|
||||
<property name="checkable">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="checked">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_19">
|
||||
<item>
|
||||
<widget class="QRadioButton" name="allMods">
|
||||
<property name="text">
|
||||
<string>All mods</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QRadioButton" name="enabledMods">
|
||||
<property name="text">
|
||||
<string>Enabled mods only</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="verticalSpacer_2">
|
||||
<property name="orientation">
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue