diff --git a/launcher/AssertHelpers.h b/launcher/AssertHelpers.h new file mode 100644 index 000000000..0b1cdb742 --- /dev/null +++ b/launcher/AssertHelpers.h @@ -0,0 +1,25 @@ +// SPDX-License-Identifier: GPL-3.0-only +/* + * Prism Launcher - Minecraft Launcher + * Copyright (C) 2025 Octol1ttle + * + * 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 + * the Free Software Foundation, version 3. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#pragma once + +#if defined(ASSERT_NEVER) +#error ASSERT_NEVER already defined +#else +#define ASSERT_NEVER(cond) (Q_ASSERT((cond) == false), (cond)) +#endif diff --git a/launcher/CMakeLists.txt b/launcher/CMakeLists.txt index b89a49186..9b4d0d130 100644 --- a/launcher/CMakeLists.txt +++ b/launcher/CMakeLists.txt @@ -102,6 +102,9 @@ set(CORE_SOURCES MMCTime.cpp MTPixmapCache.h + + # Assertion helper + AssertHelpers.h ) if (UNIX AND NOT CYGWIN AND NOT APPLE) set(CORE_SOURCES @@ -1614,7 +1617,7 @@ if(WIN32 OR (UNIX AND APPLE)) ) # FIXME: remove this crap once we stop using msys2 if(MINGW) - # i've not found a solution better than injecting the config vars like this... + # i've not found a solution better than injecting the config vars like this... # with install(CODE" for everything everything just breaks install(CODE " set(QT_PLUGINS_DIR \"${QT_PLUGINS_DIR}\") @@ -1622,7 +1625,7 @@ if(WIN32 OR (UNIX AND APPLE)) set(QT_LIBEXECS_DIR \"${QT_LIBEXECS_DIR}\") set(CMAKE_SYSTEM_LIBRARY_PATH \"${CMAKE_SYSTEM_LIBRARY_PATH}\") set(CMAKE_INSTALL_PREFIX \"${CMAKE_INSTALL_PREFIX}\") - " + " COMPONENT bundle) install(CODE [[ diff --git a/launcher/minecraft/mod/ResourceFolderModel.cpp b/launcher/minecraft/mod/ResourceFolderModel.cpp index b0082653d..3473379e3 100644 --- a/launcher/minecraft/mod/ResourceFolderModel.cpp +++ b/launcher/minecraft/mod/ResourceFolderModel.cpp @@ -38,9 +38,12 @@ ResourceFolderModel::ResourceFolderModel(const QDir& dir, BaseInstance* instance m_dir.setSorting(QDir::Name | QDir::IgnoreCase | QDir::LocaleAware); connect(&m_watcher, &QFileSystemWatcher::directoryChanged, this, &ResourceFolderModel::directoryChanged); - connect(&m_helper_thread_task, &ConcurrentTask::finished, this, [this] { m_helper_thread_task.clear(); }); + connect(&m_resourceResolver, &ConcurrentTask::finished, this, [this] { + m_resourceResolver.clear(); + m_resourceResolverRunning = false; + }); if (APPLICATION_DYN) { // in tests the application macro doesn't work - m_helper_thread_task.setMaxConcurrent(APPLICATION->settings()->get("NumberOfConcurrentTasks").toInt()); + m_resourceResolver.setMaxConcurrent(APPLICATION->settings()->get("NumberOfConcurrentTasks").toInt()); } } @@ -382,10 +385,11 @@ void ResourceFolderModel::resolveResource(Resource::Ptr res) }, Qt::ConnectionType::QueuedConnection); - m_helper_thread_task.addTask(task); + m_resourceResolver.addTask(task); - if (!m_helper_thread_task.isRunning()) { - QThreadPool::globalInstance()->start(&m_helper_thread_task); + if (!m_resourceResolverRunning) { + QThreadPool::globalInstance()->start(&m_resourceResolver); + m_resourceResolverRunning = true; } } diff --git a/launcher/minecraft/mod/ResourceFolderModel.h b/launcher/minecraft/mod/ResourceFolderModel.h index 0526b5bbf..b6343a807 100644 --- a/launcher/minecraft/mod/ResourceFolderModel.h +++ b/launcher/minecraft/mod/ResourceFolderModel.h @@ -261,7 +261,10 @@ class ResourceFolderModel : public QAbstractListModel { // Represents the relationship between a resource's internal ID and it's row position on the model. QMap m_resources_index; - ConcurrentTask m_helper_thread_task; + // Runs off-thread + ConcurrentTask m_resourceResolver; + bool m_resourceResolverRunning = false; + QMap m_active_parse_tasks; std::atomic m_next_resolution_ticket = 0; }; diff --git a/launcher/tasks/Task.cpp b/launcher/tasks/Task.cpp index 92b345c8d..4c809c651 100644 --- a/launcher/tasks/Task.cpp +++ b/launcher/tasks/Task.cpp @@ -38,6 +38,8 @@ #include +#include "AssertHelpers.h" + Q_LOGGING_CATEGORY(taskLogC, "launcher.task") Task::Task(bool show_debug) : m_show_debug(show_debug) @@ -96,7 +98,7 @@ void Task::start() break; } case State::Running: { - if (m_show_debug) + if (ASSERT_NEVER(isRunning()) && m_show_debug) qCWarning(taskLogC) << "The launcher tried to start task" << describe() << "while it was already running!"; return; } @@ -110,7 +112,7 @@ void Task::start() void Task::emitFailed(QString reason) { // Don't fail twice. - if (!isRunning()) { + if (ASSERT_NEVER(!isRunning())) { qCCritical(taskLogC) << "Task" << describe() << "failed while not running!!!!: " << reason; return; } @@ -124,7 +126,7 @@ void Task::emitFailed(QString reason) void Task::emitAborted() { // Don't abort twice. - if (!isRunning()) { + if (ASSERT_NEVER(!isRunning())) { qCCritical(taskLogC) << "Task" << describe() << "aborted while not running!!!!"; return; } @@ -139,7 +141,7 @@ void Task::emitAborted() void Task::emitSucceeded() { // Don't succeed twice. - if (!isRunning()) { + if (ASSERT_NEVER(!isRunning())) { qCCritical(taskLogC) << "Task" << describe() << "succeeded while not running!!!!"; return; }