From 1cf48dfd850f659447ca00b7a1dfbf75c8789ab7 Mon Sep 17 00:00:00 2001 From: TheKodeToad Date: Tue, 6 Jan 2026 15:00:31 +0000 Subject: [PATCH 1/5] Don't use .index for shaderpacks Signed-off-by: TheKodeToad --- launcher/CMakeLists.txt | 1 + .../minecraft/mod/ResourceFolderModel.cpp | 13 ++++- launcher/minecraft/mod/ResourceFolderModel.h | 3 +- .../minecraft/mod/ShaderPackFolderModel.cpp | 56 +++++++++++++++++++ .../minecraft/mod/ShaderPackFolderModel.h | 11 ++++ 5 files changed, 82 insertions(+), 2 deletions(-) create mode 100644 launcher/minecraft/mod/ShaderPackFolderModel.cpp diff --git a/launcher/CMakeLists.txt b/launcher/CMakeLists.txt index fce3bb177..e5d69986c 100644 --- a/launcher/CMakeLists.txt +++ b/launcher/CMakeLists.txt @@ -346,6 +346,7 @@ set(MINECRAFT_SOURCES minecraft/mod/TexturePackFolderModel.h minecraft/mod/TexturePackFolderModel.cpp minecraft/mod/ShaderPackFolderModel.h + minecraft/mod/ShaderPackFolderModel.cpp minecraft/mod/tasks/ResourceFolderLoadTask.h minecraft/mod/tasks/ResourceFolderLoadTask.cpp minecraft/mod/tasks/LocalModParseTask.h diff --git a/launcher/minecraft/mod/ResourceFolderModel.cpp b/launcher/minecraft/mod/ResourceFolderModel.cpp index 4083a7088..b6f84adab 100644 --- a/launcher/minecraft/mod/ResourceFolderModel.cpp +++ b/launcher/minecraft/mod/ResourceFolderModel.cpp @@ -23,6 +23,7 @@ #include "modplatform/flame/FlameAPI.h" #include "modplatform/flame/FlameModIndex.h" #include "settings/Setting.h" +#include "tasks/SequentialTask.h" #include "tasks/Task.h" #include "ui/dialogs/CustomMessageBox.h" @@ -334,7 +335,17 @@ bool ResourceFolderModel::update() }, Qt::ConnectionType::QueuedConnection); - QThreadPool::globalInstance()->start(m_current_update_task.get()); + auto task = new SequentialTask("ResourceFolderModel::update"); + + Task::Ptr preUpdate(createPreUpdateTask()); + if (preUpdate != nullptr) + task->addTask(preUpdate); + + task->addTask(m_current_update_task); + + connect(task, &Task::finished, [task] { task->deleteLater(); }); + + QThreadPool::globalInstance()->start(task); return true; } diff --git a/launcher/minecraft/mod/ResourceFolderModel.h b/launcher/minecraft/mod/ResourceFolderModel.h index 5c41fc520..0526b5bbf 100644 --- a/launcher/minecraft/mod/ResourceFolderModel.h +++ b/launcher/minecraft/mod/ResourceFolderModel.h @@ -84,7 +84,7 @@ class ResourceFolderModel : public QAbstractListModel { virtual bool startWatching() { return startWatching({ indexDir().absolutePath(), m_dir.absolutePath() }); } virtual bool stopWatching() { return stopWatching({ indexDir().absolutePath(), m_dir.absolutePath() }); } - QDir indexDir() { return { QString("%1/.index").arg(dir().absolutePath()) }; } + virtual QDir indexDir() const { return { QString("%1/.index").arg(dir().absolutePath()) }; } /** Given a path in the system, install that resource, moving it to its place in the * instance file hierarchy. @@ -188,6 +188,7 @@ class ResourceFolderModel : public QAbstractListModel { void parseFinished(); protected: + [[nodiscard]] virtual Task* createPreUpdateTask() { return nullptr; } /** This creates a new update task to be executed by update(). * * The task should load and parse all resources necessary, and provide a way of accessing such results. diff --git a/launcher/minecraft/mod/ShaderPackFolderModel.cpp b/launcher/minecraft/mod/ShaderPackFolderModel.cpp new file mode 100644 index 000000000..ee236512d --- /dev/null +++ b/launcher/minecraft/mod/ShaderPackFolderModel.cpp @@ -0,0 +1,56 @@ +#include "ShaderPackFolderModel.h" + +namespace { +class ShaderPackIndexMigrateTask : public Task { + Q_OBJECT + public: + ShaderPackIndexMigrateTask(QDir resourceDir, QDir indexDir) : m_resourceDir(std::move(resourceDir)), m_indexDir(std::move(indexDir)) {} + + void executeTask() override + { + if (!m_indexDir.exists()) { + qDebug() << m_indexDir.absolutePath() << "does not exist; nothing to migrate"; + emitSucceeded(); + return; + } + + QStringList pwFiles = m_indexDir.entryList({ "*.pw.toml" }, QDir::Files); + bool movedAll = true; + + for (const auto& file : pwFiles) { + QString src = m_indexDir.filePath(file); + QString dest = m_resourceDir.filePath(file); + + if (QFile::rename(src, dest)) { + qDebug() << "Moved" << src << "to" << dest; + } else { + movedAll = false; + qDebug() << "Error moving" << src << "to" << dest; + } + } + + if (!movedAll) { + // FIXME: not shown in the UI + emitFailed(tr("Failed to migrate everything from .index")); + return; + } + + if (!m_indexDir.removeRecursively()) { + emitFailed(tr("Failed to remove old .index dir")); + return; + } + + emitSucceeded(); + } + + private: + QDir m_resourceDir, m_indexDir; +}; +} // namespace + +Task* ShaderPackFolderModel::createPreUpdateTask() +{ + return new ShaderPackIndexMigrateTask(m_dir, ResourceFolderModel::indexDir()); +} + +#include "ShaderPackFolderModel.moc" diff --git a/launcher/minecraft/mod/ShaderPackFolderModel.h b/launcher/minecraft/mod/ShaderPackFolderModel.h index cd01f6226..9b0180180 100644 --- a/launcher/minecraft/mod/ShaderPackFolderModel.h +++ b/launcher/minecraft/mod/ShaderPackFolderModel.h @@ -21,5 +21,16 @@ class ShaderPackFolderModel : public ResourceFolderModel { return new LocalShaderPackParseTask(m_next_resolution_ticket, static_cast(resource)); } + QDir indexDir() const override { return m_dir; } + + Task* createPreUpdateTask() override; + + // avoid watching twice + virtual bool startWatching() override { return ResourceFolderModel::startWatching({ m_dir.absolutePath() }); } + virtual bool stopWatching() override { return ResourceFolderModel::stopWatching({ m_dir.absolutePath() }); } + RESOURCE_HELPERS(ShaderPack); + + private: + QMutex m_migrateLock; }; From d625a281124de1dc2577e6d4829f4b801e3186c0 Mon Sep 17 00:00:00 2001 From: TheKodeToad Date: Tue, 6 Jan 2026 16:47:05 +0000 Subject: [PATCH 2/5] Properly show shaderpacks in export Signed-off-by: TheKodeToad --- launcher/FileIgnoreProxy.cpp | 16 +++++++++++++++- launcher/FileIgnoreProxy.h | 2 ++ launcher/ui/dialogs/ExportPackDialog.cpp | 16 ++++++++++++++-- 3 files changed, 31 insertions(+), 3 deletions(-) diff --git a/launcher/FileIgnoreProxy.cpp b/launcher/FileIgnoreProxy.cpp index cebe82eda..445c2a881 100644 --- a/launcher/FileIgnoreProxy.cpp +++ b/launcher/FileIgnoreProxy.cpp @@ -266,7 +266,21 @@ bool FileIgnoreProxy::filterAcceptsRow(int sourceRow, const QModelIndex& sourceP bool FileIgnoreProxy::ignoreFile(QFileInfo fileInfo) const { - return m_ignoreFiles.contains(fileInfo.fileName()) || m_ignoreFilePaths.covers(relPath(fileInfo.absoluteFilePath())); + if (m_ignoreFiles.contains(fileInfo.fileName())) { + return true; + } + + for (const auto& suffix : m_ignoreFilesSuffixes) { + if (fileInfo.fileName().endsWith(suffix)) { + return true; + } + } + + if (m_ignoreFilePaths.covers(relPath(fileInfo.absoluteFilePath()))) { + return true; + } + + return false; } bool FileIgnoreProxy::filterFile(const QFileInfo& file) const diff --git a/launcher/FileIgnoreProxy.h b/launcher/FileIgnoreProxy.h index 5184fc354..0f149ecb6 100644 --- a/launcher/FileIgnoreProxy.h +++ b/launcher/FileIgnoreProxy.h @@ -66,6 +66,7 @@ class FileIgnoreProxy : public QSortFilterProxyModel { // list of file names that need to be removed completely from model inline QStringList& ignoreFilesWithName() { return m_ignoreFiles; } + inline QStringList& ignoreFilesWithSuffix() { return m_ignoreFilesSuffixes; } // list of relative paths that need to be removed completely from model inline SeparatorPrefixTree<'/'>& ignoreFilesWithPath() { return m_ignoreFilePaths; } @@ -85,5 +86,6 @@ class FileIgnoreProxy : public QSortFilterProxyModel { const QString m_root; SeparatorPrefixTree<'/'> m_blocked; QStringList m_ignoreFiles; + QStringList m_ignoreFilesSuffixes; SeparatorPrefixTree<'/'> m_ignoreFilePaths; }; diff --git a/launcher/ui/dialogs/ExportPackDialog.cpp b/launcher/ui/dialogs/ExportPackDialog.cpp index e6c17972d..d932909c9 100644 --- a/launcher/ui/dialogs/ExportPackDialog.cpp +++ b/launcher/ui/dialogs/ExportPackDialog.cpp @@ -95,6 +95,7 @@ ExportPackDialog::ExportPackDialog(MinecraftInstancePtr instance, QWidget* paren m_proxy->ignoreFilesWithPath().insert(FS::PathCombine(prefix, path)); } m_proxy->ignoreFilesWithName().append({ ".DS_Store", "thumbs.db", "Thumbs.db" }); + m_proxy->ignoreFilesWithSuffix().append(".pw.toml"); m_proxy->setSourceModel(model); m_proxy->loadBlockedPathsFromFile(ignoreFileName()); @@ -103,8 +104,19 @@ ExportPackDialog::ExportPackDialog(MinecraftInstancePtr instance, QWidget* paren MinecraftInstance* mcInstance = dynamic_cast(instance.get()); if (mcInstance) { for (auto resourceModel : mcInstance->resourceLists()) { - if (resourceModel && resourceModel->indexDir().exists()) - m_proxy->ignoreFilesWithPath().insert(instanceRoot.relativeFilePath(resourceModel->indexDir().absolutePath())); + if (resourceModel == nullptr) { + continue; + } + + if (!resourceModel->indexDir().exists()) { + continue; + } + + if (resourceModel->indexDir() == resourceModel->indexDir()) { + continue; + } + + m_proxy->ignoreFilesWithPath().insert(instanceRoot.relativeFilePath(resourceModel->indexDir().absolutePath())); } } From 398305eb66ae269d052af436ad9bcd1f2a0b7509 Mon Sep 17 00:00:00 2001 From: TheKodeToad Date: Tue, 6 Jan 2026 17:54:16 +0000 Subject: [PATCH 3/5] Less destructive delete Signed-off-by: TheKodeToad --- launcher/minecraft/mod/ShaderPackFolderModel.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/launcher/minecraft/mod/ShaderPackFolderModel.cpp b/launcher/minecraft/mod/ShaderPackFolderModel.cpp index ee236512d..47282020a 100644 --- a/launcher/minecraft/mod/ShaderPackFolderModel.cpp +++ b/launcher/minecraft/mod/ShaderPackFolderModel.cpp @@ -35,7 +35,7 @@ class ShaderPackIndexMigrateTask : public Task { return; } - if (!m_indexDir.removeRecursively()) { + if (FS::deletePath(m_indexDir.absolutePath())) { emitFailed(tr("Failed to remove old .index dir")); return; } From e4991d81d7a234daa69c6e1f0c628e6e67cc02f3 Mon Sep 17 00:00:00 2001 From: TheKodeToad Date: Tue, 6 Jan 2026 17:55:44 +0000 Subject: [PATCH 4/5] Avoid some errors (less noisy log) Signed-off-by: TheKodeToad --- launcher/minecraft/mod/tasks/ResourceFolderLoadTask.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/launcher/minecraft/mod/tasks/ResourceFolderLoadTask.cpp b/launcher/minecraft/mod/tasks/ResourceFolderLoadTask.cpp index 98dab9abb..3b98e053b 100644 --- a/launcher/minecraft/mod/tasks/ResourceFolderLoadTask.cpp +++ b/launcher/minecraft/mod/tasks/ResourceFolderLoadTask.cpp @@ -136,6 +136,10 @@ void ResourceFolderLoadTask::getFromMetadata() { m_index_dir.refresh(); for (auto entry : m_index_dir.entryList(QDir::Files)) { + if (!entry.endsWith(".pw.toml")) { + continue; + } + auto metadata = Metadata::get(m_index_dir, entry); if (!metadata.isValid()) From 3a7366a9982e98e86ca759257130e9932d1bf861 Mon Sep 17 00:00:00 2001 From: TheKodeToad Date: Tue, 6 Jan 2026 19:21:04 +0000 Subject: [PATCH 5/5] Fix oversights and make requested changes Signed-off-by: TheKodeToad --- launcher/minecraft/mod/ResourceFolderModel.cpp | 17 ++++++++++------- .../minecraft/mod/ShaderPackFolderModel.cpp | 8 ++++---- launcher/ui/dialogs/ExportPackDialog.cpp | 2 +- 3 files changed, 15 insertions(+), 12 deletions(-) diff --git a/launcher/minecraft/mod/ResourceFolderModel.cpp b/launcher/minecraft/mod/ResourceFolderModel.cpp index b6f84adab..273a469d9 100644 --- a/launcher/minecraft/mod/ResourceFolderModel.cpp +++ b/launcher/minecraft/mod/ResourceFolderModel.cpp @@ -335,17 +335,20 @@ bool ResourceFolderModel::update() }, Qt::ConnectionType::QueuedConnection); - auto task = new SequentialTask("ResourceFolderModel::update"); + Task::Ptr preUpdate{createPreUpdateTask()}; + + if (preUpdate != nullptr) { + auto task = new SequentialTask("ResourceFolderModel::update"); - Task::Ptr preUpdate(createPreUpdateTask()); - if (preUpdate != nullptr) task->addTask(preUpdate); + task->addTask(m_current_update_task); - task->addTask(m_current_update_task); + connect(task, &Task::finished, [task] { task->deleteLater(); }); - connect(task, &Task::finished, [task] { task->deleteLater(); }); - - QThreadPool::globalInstance()->start(task); + QThreadPool::globalInstance()->start(task); + } else { + QThreadPool::globalInstance()->start(m_current_update_task.get()); + } return true; } diff --git a/launcher/minecraft/mod/ShaderPackFolderModel.cpp b/launcher/minecraft/mod/ShaderPackFolderModel.cpp index 47282020a..5cf5d2eb1 100644 --- a/launcher/minecraft/mod/ShaderPackFolderModel.cpp +++ b/launcher/minecraft/mod/ShaderPackFolderModel.cpp @@ -1,3 +1,4 @@ +#include "FileSystem.h" #include "ShaderPackFolderModel.h" namespace { @@ -21,21 +22,20 @@ class ShaderPackIndexMigrateTask : public Task { QString src = m_indexDir.filePath(file); QString dest = m_resourceDir.filePath(file); - if (QFile::rename(src, dest)) { + if (FS::move(src, dest)) { qDebug() << "Moved" << src << "to" << dest; } else { movedAll = false; - qDebug() << "Error moving" << src << "to" << dest; } } if (!movedAll) { // FIXME: not shown in the UI - emitFailed(tr("Failed to migrate everything from .index")); + emitFailed(tr("Failed to migrate shaderpack metadata from .index")); return; } - if (FS::deletePath(m_indexDir.absolutePath())) { + if (!FS::deletePath(m_indexDir.absolutePath())) { emitFailed(tr("Failed to remove old .index dir")); return; } diff --git a/launcher/ui/dialogs/ExportPackDialog.cpp b/launcher/ui/dialogs/ExportPackDialog.cpp index d932909c9..17b3ba703 100644 --- a/launcher/ui/dialogs/ExportPackDialog.cpp +++ b/launcher/ui/dialogs/ExportPackDialog.cpp @@ -112,7 +112,7 @@ ExportPackDialog::ExportPackDialog(MinecraftInstancePtr instance, QWidget* paren continue; } - if (resourceModel->indexDir() == resourceModel->indexDir()) { + if (resourceModel->dir() == resourceModel->indexDir()) { continue; }