Merge bd570aa5d1d371675ecedcf8df1437bf155853e7 into 79b7e277f1f06f6b315e293b029423fe35e57431

This commit is contained in:
Alexandru Ionut Tripon 2025-08-01 21:19:51 +02:00 committed by GitHub
commit ae4136ddd3
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
8 changed files with 136 additions and 98 deletions

View File

@ -1,9 +1,7 @@
#pragma once
#include "minecraft/mod/Mod.h"
#include "minecraft/mod/tasks/GetModDependenciesTask.h"
#include "modplatform/ModIndex.h"
#include "modplatform/ResourceAPI.h"
#include "tasks/Task.h"
class ResourceDownloadTask;
@ -19,9 +17,9 @@ class CheckUpdateTask : public Task {
std::shared_ptr<ResourceFolderModel> resourceModel)
: Task()
, m_resources(resources)
, m_game_versions(mcVersions)
, m_loaders_list(std::move(loadersList))
, m_resource_model(std::move(resourceModel))
, m_gameVersions(mcVersions)
, m_loadersList(std::move(loadersList))
, m_resourceModel(std::move(resourceModel))
{}
struct Update {
@ -71,9 +69,9 @@ class CheckUpdateTask : public Task {
protected:
QList<Resource*>& m_resources;
std::list<Version>& m_game_versions;
QList<ModPlatform::ModLoaderType> m_loaders_list;
std::shared_ptr<ResourceFolderModel> m_resource_model;
std::list<Version>& m_gameVersions;
QList<ModPlatform::ModLoaderType> m_loadersList;
std::shared_ptr<ResourceFolderModel> m_resourceModel;
std::vector<Update> m_updates;
QList<std::shared_ptr<GetModDependenciesTask::PackDependency>> m_deps;

View File

@ -218,9 +218,19 @@ QList<ModPlatform::Category> FlameAPI::loadModCategories(std::shared_ptr<QByteAr
std::optional<ModPlatform::IndexedVersion> FlameAPI::getLatestVersion(QList<ModPlatform::IndexedVersion> versions,
QList<ModPlatform::ModLoaderType> instanceLoaders,
ModPlatform::ModLoaderTypes modLoaders)
ModPlatform::ModLoaderTypes modLoaders,
bool checkLoaders)
{
static const auto noLoader = ModPlatform::ModLoaderType(0);
if (!checkLoaders) {
std::optional<ModPlatform::IndexedVersion> ver;
for (auto file_tmp : versions) {
if (!ver.has_value() || file_tmp.date > ver->date) {
ver = file_tmp;
}
}
return ver;
}
QHash<ModPlatform::ModLoaderType, ModPlatform::IndexedVersion> bestMatch;
auto checkVersion = [&bestMatch](const ModPlatform::IndexedVersion& version, const ModPlatform::ModLoaderType& loader) {
if (bestMatch.contains(loader)) {

View File

@ -18,7 +18,8 @@ class FlameAPI : public NetworkResourceAPI {
std::optional<ModPlatform::IndexedVersion> getLatestVersion(QList<ModPlatform::IndexedVersion> versions,
QList<ModPlatform::ModLoaderType> instanceLoaders,
ModPlatform::ModLoaderTypes fallback);
ModPlatform::ModLoaderTypes fallback,
bool checkLoaders);
Task::Ptr getProjects(QStringList addonIds, std::shared_ptr<QByteArray> response) const override;
Task::Ptr matchFingerprints(const QList<uint>& fingerprints, std::shared_ptr<QByteArray> response);

View File

@ -46,12 +46,12 @@ void FlameCheckUpdate::executeTask()
connect(netJob, &Task::stepProgress, this, &FlameCheckUpdate::propagateStepProgress);
connect(netJob, &Task::details, this, &FlameCheckUpdate::setDetails);
for (auto* resource : m_resources) {
auto versions_url_optional = api.getVersionsURL({ { resource->metadata()->project_id.toString() }, m_game_versions });
if (!versions_url_optional.has_value())
auto versionsUrlOptional = api.getVersionsURL({ { resource->metadata()->project_id.toString() }, m_gameVersions });
if (!versionsUrlOptional.has_value())
continue;
auto response = std::make_shared<QByteArray>();
auto task = Net::ApiDownload::makeByteArray(versions_url_optional.value(), response);
auto task = Net::ApiDownload::makeByteArray(versionsUrlOptional.value(), response);
connect(task.get(), &Task::succeeded, this, [this, resource, response] { getLatestVersionCallback(resource, response); });
netJob->addNetAction(task);
@ -87,7 +87,7 @@ void FlameCheckUpdate::getLatestVersionCallback(Resource* resource, std::shared_
qCritical() << e.what();
qDebug() << doc;
}
auto latest_ver = api.getLatestVersion(pack->versions, m_loaders_list, resource->metadata()->loaders);
auto latest_ver = api.getLatestVersion(pack->versions, m_loadersList, resource->metadata()->loaders, !m_loadersList.isEmpty());
setStatus(tr("Parsing the API response from CurseForge for '%1'...").arg(resource->name()));
@ -119,7 +119,7 @@ void FlameCheckUpdate::getLatestVersionCallback(Resource* resource, std::shared_
old_version = tr("Unknown");
}
auto download_task = makeShared<ResourceDownloadTask>(pack, latest_ver.value(), m_resource_model);
auto download_task = makeShared<ResourceDownloadTask>(pack, latest_ver.value(), m_resourceModel);
m_updates.emplace_back(pack->name, resource->metadata()->hash, old_version, latest_ver->version, latest_ver->version_type,
api.getModFileChangelog(latest_ver->addonId.toInt(), latest_ver->fileId.toInt()),
ModPlatform::ResourceProvider::FLAME, download_task, resource->enabled());

View File

@ -15,6 +15,26 @@
static ModrinthAPI api;
ModrinthCheckUpdate::ModrinthCheckUpdate(QList<Resource*>& resources,
std::list<Version>& mcVersions,
QList<ModPlatform::ModLoaderType> loadersList,
std::shared_ptr<ResourceFolderModel> resourceModel)
: CheckUpdateTask(resources, mcVersions, std::move(loadersList), std::move(resourceModel))
, m_hashType(ModPlatform::ProviderCapabilities::hashType(ModPlatform::ResourceProvider::MODRINTH).first())
{
if (!m_loadersList.isEmpty()) { // this is for mods so append all the other posible loaders to the initial list
m_initialSize = m_loadersList.length();
ModPlatform::ModLoaderTypes modLoaders;
for (auto m : resources) {
modLoaders |= m->metadata()->loaders;
}
for (auto l : m_loadersList) {
modLoaders &= ~l;
}
m_loadersList.append(ModPlatform::modLoaderTypesToList(modLoaders));
}
}
bool ModrinthCheckUpdate::abort()
{
if (m_job)
@ -30,45 +50,61 @@ bool ModrinthCheckUpdate::abort()
void ModrinthCheckUpdate::executeTask()
{
setStatus(tr("Preparing resources for Modrinth..."));
setProgress(0, (m_loaders_list.isEmpty() ? 1 : m_loaders_list.length()) * 2 + 1);
setProgress(0, (m_loadersList.isEmpty() ? 1 : m_loadersList.length()) * 2 + 1);
auto hashing_task =
makeShared<ConcurrentTask>("MakeModrinthHashesTask", APPLICATION->settings()->get("NumberOfConcurrentTasks").toInt());
bool startHasing = false;
for (auto* resource : m_resources) {
auto hash = resource->metadata()->hash;
// Sadly the API can only handle one hash type per call, se we
// need to generate a new hash if the current one is innadequate
// (though it will rarely happen, if at all)
if (resource->metadata()->hash_format != m_hash_type) {
if (resource->metadata()->hash_format != m_hashType) {
auto hash_task = Hashing::createHasher(resource->fileinfo().absoluteFilePath(), ModPlatform::ResourceProvider::MODRINTH);
connect(hash_task.get(), &Hashing::Hasher::resultsReady, [this, resource](QString hash) { m_mappings.insert(hash, resource); });
connect(hash_task.get(), &Task::failed, [this] { failed("Failed to generate hash"); });
hashing_task->addTask(hash_task);
startHasing = true;
} else {
m_mappings.insert(hash, resource);
}
}
connect(hashing_task.get(), &Task::finished, this, &ModrinthCheckUpdate::checkNextLoader);
m_job = hashing_task;
hashing_task->start();
if (startHasing) {
connect(hashing_task.get(), &Task::finished, this, &ModrinthCheckUpdate::checkNextLoader);
m_job = hashing_task;
hashing_task->start();
} else {
checkNextLoader();
}
}
void ModrinthCheckUpdate::getUpdateModsForLoader(std::optional<ModPlatform::ModLoaderTypes> loader)
void ModrinthCheckUpdate::getUpdateModsForLoader(std::optional<ModPlatform::ModLoaderTypes> loader, bool forceModLoaderCheck)
{
setStatus(tr("Waiting for the API response from Modrinth..."));
setProgress(m_progress + 1, m_progressTotal);
auto response = std::make_shared<QByteArray>();
QStringList hashes = m_mappings.keys();
auto job = api.latestVersions(hashes, m_hash_type, m_game_versions, loader, response);
QStringList hashes;
if (forceModLoaderCheck && loader.has_value()) {
for (auto hash : m_mappings.keys()) {
if (m_mappings[hash]->metadata()->loaders & loader.value()) {
hashes.append(hash);
}
}
} else {
hashes = m_mappings.keys();
}
auto job = api.latestVersions(hashes, m_hashType, m_gameVersions, loader, response);
connect(job.get(), &Task::succeeded, this, [this, response, loader] { checkVersionsResponse(response, loader); });
connect(job.get(), &Task::failed, this, &ModrinthCheckUpdate::checkNextLoader);
m_job = job;
m_loaderIdx++;
job->start();
}
@ -121,7 +157,7 @@ void ModrinthCheckUpdate::checkVersionsResponse(std::shared_ptr<QByteArray> resp
// - The version reported by the JAR is different from the version reported by the indexed version (it's usually the case)
// Such is the pain of having arbitrary files for a given version .-.
auto project_ver = Modrinth::loadIndexedPackVersion(project_obj, m_hash_type, loader_filter);
auto project_ver = Modrinth::loadIndexedPackVersion(project_obj, m_hashType, loader_filter);
if (project_ver.downloadUrl.isEmpty()) {
qCritical() << "Modrinth mod without download url!" << project_ver.fileName;
++iter;
@ -135,7 +171,7 @@ void ModrinthCheckUpdate::checkVersionsResponse(std::shared_ptr<QByteArray> resp
pack->addonId = resource->metadata()->project_id;
pack->provider = ModPlatform::ResourceProvider::MODRINTH;
if ((project_ver.hash != hash && project_ver.is_preferred) || (resource->status() == ResourceStatus::NOT_INSTALLED)) {
auto download_task = makeShared<ResourceDownloadTask>(pack, project_ver, m_resource_model);
auto download_task = makeShared<ResourceDownloadTask>(pack, project_ver, m_resourceModel);
QString old_version = resource->metadata()->version_number;
if (old_version.isEmpty()) {
@ -165,16 +201,11 @@ void ModrinthCheckUpdate::checkNextLoader()
emitSucceeded();
return;
}
if (m_loaders_list.isEmpty() && m_loader_idx == 0) {
getUpdateModsForLoader({});
m_loader_idx++;
if (m_loaderIdx < m_loadersList.size()) { // this are mods so check with loades
getUpdateModsForLoader(m_loadersList.at(m_loaderIdx), m_loaderIdx > m_initialSize);
return;
}
if (m_loader_idx < m_loaders_list.size()) {
getUpdateModsForLoader(m_loaders_list.at(m_loader_idx));
m_loader_idx++;
} else if (m_loadersList.isEmpty() && m_loaderIdx == 0) { // this are other resources no need to check more than once with empty loader
getUpdateModsForLoader();
return;
}
@ -192,4 +223,4 @@ void ModrinthCheckUpdate::checkNextLoader()
}
emitSucceeded();
}
}

View File

@ -9,23 +9,21 @@ class ModrinthCheckUpdate : public CheckUpdateTask {
ModrinthCheckUpdate(QList<Resource*>& resources,
std::list<Version>& mcVersions,
QList<ModPlatform::ModLoaderType> loadersList,
std::shared_ptr<ResourceFolderModel> resourceModel)
: CheckUpdateTask(resources, mcVersions, std::move(loadersList), std::move(resourceModel))
, m_hash_type(ModPlatform::ProviderCapabilities::hashType(ModPlatform::ResourceProvider::MODRINTH).first())
{}
std::shared_ptr<ResourceFolderModel> resourceModel);
public slots:
bool abort() override;
protected slots:
void executeTask() override;
void getUpdateModsForLoader(std::optional<ModPlatform::ModLoaderTypes> loader);
void getUpdateModsForLoader(std::optional<ModPlatform::ModLoaderTypes> loader = {}, bool forceModLoaderCheck = false);
void checkVersionsResponse(std::shared_ptr<QByteArray> response, std::optional<ModPlatform::ModLoaderTypes> loader);
void checkNextLoader();
private:
Task::Ptr m_job = nullptr;
QHash<QString, Resource*> m_mappings;
QString m_hash_type;
int m_loader_idx = 0;
QString m_hashType;
int m_loaderIdx = 0;
int m_initialSize = 0;
};

View File

@ -34,17 +34,17 @@ static std::list<Version> mcVersions(BaseInstance* inst)
ResourceUpdateDialog::ResourceUpdateDialog(QWidget* parent,
BaseInstance* instance,
const std::shared_ptr<ResourceFolderModel> resource_model,
QList<Resource*>& search_for,
bool include_deps,
const std::shared_ptr<ResourceFolderModel> resourceModel,
QList<Resource*>& searchFor,
bool includeDeps,
QList<ModPlatform::ModLoaderType> loadersList)
: ReviewMessageBox(parent, tr("Confirm resources to update"), "")
, m_parent(parent)
, m_resource_model(resource_model)
, m_candidates(search_for)
, m_second_try_metadata(new ConcurrentTask("Second Metadata Search", APPLICATION->settings()->get("NumberOfConcurrentTasks").toInt()))
, m_resourceModel(resourceModel)
, m_candidates(searchFor)
, m_secondTryMetadata(new ConcurrentTask("Second Metadata Search", APPLICATION->settings()->get("NumberOfConcurrentTasks").toInt()))
, m_instance(instance)
, m_include_deps(include_deps)
, m_includeDeps(includeDeps)
, m_loadersList(std::move(loadersList))
{
ReviewMessageBox::setGeometry(0, 0, 800, 600);
@ -63,9 +63,9 @@ void ResourceUpdateDialog::checkCandidates()
}
// Report failed metadata generation
if (!m_failed_metadata.empty()) {
if (!m_failedMetadata.empty()) {
QString text;
for (const auto& failed : m_failed_metadata) {
for (const auto& failed : m_failedMetadata) {
const auto& mod = std::get<0>(failed);
const auto& reason = std::get<1>(failed);
text += tr("Mod name: %1<br>File name: %2<br>Reason: %3<br><br>").arg(mod->name(), mod->fileinfo().fileName(), reason);
@ -84,24 +84,24 @@ void ResourceUpdateDialog::checkCandidates()
}
auto versions = mcVersions(m_instance);
SequentialTask check_task(tr("Checking for updates"));
if (!m_modrinth_to_update.empty()) {
m_modrinth_check_task.reset(new ModrinthCheckUpdate(m_modrinth_to_update, versions, m_loadersList, m_resource_model));
connect(m_modrinth_check_task.get(), &CheckUpdateTask::checkFailed, this,
if (!m_modrinthToUpdate.empty()) {
m_modrinthCheckTask.reset(new ModrinthCheckUpdate(m_modrinthToUpdate, versions, m_loadersList, m_resourceModel));
connect(m_modrinthCheckTask.get(), &CheckUpdateTask::checkFailed, this,
[this](Resource* resource, QString reason, QUrl recover_url) {
m_failed_check_update.append({ resource, reason, recover_url });
m_failedCheckUpdate.append({ resource, reason, recover_url });
});
check_task.addTask(m_modrinth_check_task);
check_task.addTask(m_modrinthCheckTask);
}
if (!m_flame_to_update.empty()) {
m_flame_check_task.reset(new FlameCheckUpdate(m_flame_to_update, versions, m_loadersList, m_resource_model));
connect(m_flame_check_task.get(), &CheckUpdateTask::checkFailed, this,
[this](Resource* resource, QString reason, QUrl recover_url) {
m_failed_check_update.append({ resource, reason, recover_url });
});
check_task.addTask(m_flame_check_task);
if (!m_flameToUpdate.empty()) {
m_flameCheckTask.reset(new FlameCheckUpdate(m_flameToUpdate, versions, m_loadersList, m_resourceModel));
connect(m_flameCheckTask.get(), &CheckUpdateTask::checkFailed, this, [this](Resource* resource, QString reason, QUrl recover_url) {
m_failedCheckUpdate.append({ resource, reason, recover_url });
});
check_task.addTask(m_flameCheckTask);
}
connect(&check_task, &Task::failed, this,
@ -130,33 +130,33 @@ void ResourceUpdateDialog::checkCandidates()
QList<std::shared_ptr<GetModDependenciesTask::PackDependency>> selectedVers;
// Add found updates for Modrinth
if (m_modrinth_check_task) {
auto modrinth_updates = m_modrinth_check_task->getUpdates();
if (m_modrinthCheckTask) {
auto modrinth_updates = m_modrinthCheckTask->getUpdates();
for (auto& updatable : modrinth_updates) {
qDebug() << QString("Mod %1 has an update available!").arg(updatable.name);
appendResource(updatable);
m_tasks.insert(updatable.name, updatable.download);
}
selectedVers.append(m_modrinth_check_task->getDependencies());
selectedVers.append(m_modrinthCheckTask->getDependencies());
}
// Add found updated for Flame
if (m_flame_check_task) {
auto flame_updates = m_flame_check_task->getUpdates();
if (m_flameCheckTask) {
auto flame_updates = m_flameCheckTask->getUpdates();
for (auto& updatable : flame_updates) {
qDebug() << QString("Mod %1 has an update available!").arg(updatable.name);
appendResource(updatable);
m_tasks.insert(updatable.name, updatable.download);
}
selectedVers.append(m_flame_check_task->getDependencies());
selectedVers.append(m_flameCheckTask->getDependencies());
}
// Report failed update checking
if (!m_failed_check_update.empty()) {
if (!m_failedCheckUpdate.empty()) {
QString text;
for (const auto& failed : m_failed_check_update) {
for (const auto& failed : m_failedCheckUpdate) {
const auto& mod = std::get<0>(failed);
const auto& reason = std::get<1>(failed);
const auto& recover_url = std::get<2>(failed);
@ -185,8 +185,8 @@ void ResourceUpdateDialog::checkCandidates()
}
}
if (m_include_deps && !APPLICATION->settings()->get("ModDependenciesDisabled").toBool()) { // dependencies
auto* mod_model = dynamic_cast<ModFolderModel*>(m_resource_model.get());
if (m_includeDeps && !APPLICATION->settings()->get("ModDependenciesDisabled").toBool()) { // dependencies
auto* mod_model = dynamic_cast<ModFolderModel*>(m_resourceModel.get());
if (mod_model != nullptr) {
auto depTask = makeShared<GetModDependenciesTask>(m_instance, mod_model, selectedVers);
@ -224,7 +224,7 @@ void ResourceUpdateDialog::checkCandidates()
auto changelog = dep->version.changelog;
if (dep->pack->provider == ModPlatform::ResourceProvider::FLAME)
changelog = api.getModFileChangelog(dep->version.addonId.toInt(), dep->version.fileId.toInt());
auto download_task = makeShared<ResourceDownloadTask>(dep->pack, dep->version, m_resource_model);
auto download_task = makeShared<ResourceDownloadTask>(dep->pack, dep->version, m_resourceModel);
auto extraInfo = dependencyExtraInfo.value(dep->version.addonId.toString());
CheckUpdateTask::Update updatable = {
dep->pack->name, dep->version.hash, tr("Not installed"), dep->version.version, dep->version.version_type,
@ -239,7 +239,7 @@ void ResourceUpdateDialog::checkCandidates()
// If there's no resource to be updated
if (ui->modTreeWidget->topLevelItemCount() == 0) {
m_no_updates = true;
m_noUpdates = true;
} else {
// FIXME: Find a more efficient way of doing this!
@ -254,7 +254,7 @@ void ResourceUpdateDialog::checkCandidates()
}
}
if (m_aborted || m_no_updates)
if (m_aborted || m_noUpdates)
QMetaObject::invokeMethod(this, "reject", Qt::QueuedConnection);
}
@ -362,7 +362,7 @@ auto ResourceUpdateDialog::ensureMetadata() -> bool
seq.addTask(flame_task);
}
seq.addTask(m_second_try_metadata);
seq.addTask(m_secondTryMetadata);
// execute all the tasks
ProgressDialog checking_dialog(m_parent);
@ -381,10 +381,10 @@ void ResourceUpdateDialog::onMetadataEnsured(Resource* resource)
switch (resource->metadata()->provider) {
case ModPlatform::ResourceProvider::MODRINTH:
m_modrinth_to_update.push_back(resource);
m_modrinthToUpdate.push_back(resource);
break;
case ModPlatform::ResourceProvider::FLAME:
m_flame_to_update.push_back(resource);
m_flameToUpdate.push_back(resource);
break;
}
}
@ -415,14 +415,14 @@ void ResourceUpdateDialog::onMetadataFailed(Resource* resource, bool try_others,
auto seq = makeShared<SequentialTask>();
seq->addTask(task->getHashingTask());
seq->addTask(task);
m_second_try_metadata->addTask(seq);
m_secondTryMetadata->addTask(seq);
} else {
m_second_try_metadata->addTask(task);
m_secondTryMetadata->addTask(task);
}
} else {
QString reason{ tr("Couldn't find a valid version on the selected mod provider(s)") };
m_failed_metadata.append({ resource, reason });
m_failedMetadata.append({ resource, reason });
}
}

View File

@ -18,9 +18,9 @@ class ResourceUpdateDialog final : public ReviewMessageBox {
public:
explicit ResourceUpdateDialog(QWidget* parent,
BaseInstance* instance,
std::shared_ptr<ResourceFolderModel> resource_model,
QList<Resource*>& search_for,
bool include_deps,
std::shared_ptr<ResourceFolderModel> resourceModel,
QList<Resource*>& searchFor,
bool includeDeps,
QList<ModPlatform::ModLoaderType> loadersList = {});
void checkCandidates();
@ -28,9 +28,9 @@ class ResourceUpdateDialog final : public ReviewMessageBox {
void appendResource(const CheckUpdateTask::Update& info, QStringList requiredBy = {});
const QList<ResourceDownloadTask::Ptr> getTasks();
auto indexDir() const -> QDir { return m_resource_model->indexDir(); }
auto indexDir() const -> QDir { return m_resourceModel->indexDir(); }
auto noUpdates() const -> bool { return m_no_updates; };
auto noUpdates() const -> bool { return m_noUpdates; };
auto aborted() const -> bool { return m_aborted; };
private:
@ -40,29 +40,29 @@ class ResourceUpdateDialog final : public ReviewMessageBox {
void onMetadataEnsured(Resource* resource);
void onMetadataFailed(Resource* resource,
bool try_others = false,
ModPlatform::ResourceProvider first_choice = ModPlatform::ResourceProvider::MODRINTH);
ModPlatform::ResourceProvider firstChoice = ModPlatform::ResourceProvider::MODRINTH);
private:
QWidget* m_parent;
shared_qobject_ptr<ModrinthCheckUpdate> m_modrinth_check_task;
shared_qobject_ptr<FlameCheckUpdate> m_flame_check_task;
shared_qobject_ptr<ModrinthCheckUpdate> m_modrinthCheckTask;
shared_qobject_ptr<FlameCheckUpdate> m_flameCheckTask;
const std::shared_ptr<ResourceFolderModel> m_resource_model;
const std::shared_ptr<ResourceFolderModel> m_resourceModel;
QList<Resource*>& m_candidates;
QList<Resource*> m_modrinth_to_update;
QList<Resource*> m_flame_to_update;
QList<Resource*> m_modrinthToUpdate;
QList<Resource*> m_flameToUpdate;
ConcurrentTask::Ptr m_second_try_metadata;
QList<std::tuple<Resource*, QString>> m_failed_metadata;
QList<std::tuple<Resource*, QString, QUrl>> m_failed_check_update;
ConcurrentTask::Ptr m_secondTryMetadata;
QList<std::tuple<Resource*, QString>> m_failedMetadata;
QList<std::tuple<Resource*, QString, QUrl>> m_failedCheckUpdate;
QHash<QString, ResourceDownloadTask::Ptr> m_tasks;
BaseInstance* m_instance;
bool m_no_updates = false;
bool m_noUpdates = false;
bool m_aborted = false;
bool m_include_deps = false;
bool m_includeDeps = false;
QList<ModPlatform::ModLoaderType> m_loadersList;
};