From bd49dc4e7b6b85cc160bd58a78a9474a898b995b Mon Sep 17 00:00:00 2001 From: Marco von Rosenberg Date: Mon, 6 Oct 2025 21:56:19 +0900 Subject: [PATCH 1/9] fix: prioritize .ftbapp/version.json in FTB App import Newer versions of FTB App create a stub version.json in the instance root with only a comment directing to .ftbapp/version.json. The old logic would find this stub file first and fail to parse it, causing modpacks to not be detected. This fix checks .ftbapp/version.json first (newer location) before falling back to the root version.json (older location). Signed-off-by: Marco von Rosenberg Signed-off-by: Charlie --- launcher/modplatform/import_ftb/PackHelpers.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/launcher/modplatform/import_ftb/PackHelpers.cpp b/launcher/modplatform/import_ftb/PackHelpers.cpp index 089b5fff2..22d1242e9 100644 --- a/launcher/modplatform/import_ftb/PackHelpers.cpp +++ b/launcher/modplatform/import_ftb/PackHelpers.cpp @@ -79,9 +79,9 @@ Modpack parseDirectory(QString path) return {}; } - auto versionsFile = QFileInfo(FS::PathCombine(path, "version.json")); + auto versionsFile = QFileInfo(FS::PathCombine(path, ".ftbapp", "version.json")); if (!versionsFile.exists() || !versionsFile.isFile()) { - versionsFile = QFileInfo(FS::PathCombine(path, ".ftbapp", "version.json")); + versionsFile = QFileInfo(FS::PathCombine(path, "version.json")); } if (!versionsFile.exists() || !versionsFile.isFile()) { return {}; From b43226739fc091c39b587528970c22b365eadf49 Mon Sep 17 00:00:00 2001 From: Charlie Date: Fri, 17 Oct 2025 14:29:50 +1100 Subject: [PATCH 2/9] Gathering and filtering all released vanilla minecraft version for grouping major versions, made static so only called once to reduce computations Signed-off-by: Charlie --- launcher/minecraft/mod/Mod.cpp | 47 +++++++++++++++++++++++++++++++++- launcher/minecraft/mod/Mod.h | 1 + 2 files changed, 47 insertions(+), 1 deletion(-) diff --git a/launcher/minecraft/mod/Mod.cpp b/launcher/minecraft/mod/Mod.cpp index e9ca2e682..dc5d8f197 100644 --- a/launcher/minecraft/mod/Mod.cpp +++ b/launcher/minecraft/mod/Mod.cpp @@ -49,6 +49,10 @@ #include "minecraft/mod/ModDetails.h" #include "minecraft/mod/tasks/LocalModParseTask.h" #include "modplatform/ModIndex.h" +#include "Application.h" +#include "meta/Index.h" +#include "ui/widgets/VersionSelectWidget.h" +#include "ui/widgets/VersionListView.h" Mod::Mod(const QFileInfo& file) : Resource(file), m_local_details() { @@ -187,11 +191,52 @@ auto Mod::side() const -> QString auto Mod::mcVersions() const -> QString { if (metadata()) - return metadata()->mcVersions.join(", "); + return groupMcVersions(); + //return metadata()->mcVersions.join(", "); return {}; } +auto Mod::groupMcVersions() const -> QString +{ + + static QStringList s_realeasedMcVersions = []() { + // Gets all of minecrafts vanilla versions + auto vlist = APPLICATION->metadataIndex()->get("net.minecraft"); + VersionSelectWidget* versionList = new VersionSelectWidget(nullptr); + versionList->initialize(vlist.get()); + //Filters to only main released versions (like 1.19.2, 1.8.9) + versionList->setFilter(BaseVersionList::TypeRole, Filters::regexp(QRegularExpression("(release)"))); + auto model = versionList->view()->model(); + QAbstractItemModel* proxyModel = model; + // Versions get ordered latest to oldest + QStringList filteredVersions; + // extracts each version number from model + for (int row = 0; row < proxyModel->rowCount(); ++row) { + QModelIndex index = proxyModel->index(row, 0); + QVariant data = proxyModel->data(index, BaseVersionList::VersionRole); + filteredVersions << data.toString(); + } + return filteredVersions; + }(); + + // gets existing list of minecraft versions + // goes through current modpacks mcVersions in sequence checking if the next in the real minecraft versions exists + + QStringList filteredVersions = s_realeasedMcVersions; + QStringList groupedVersions; + + if (metadata()) { + for (int i = 0; i < metadata()->mcVersions.size(); ++i) { + + } + } + + return groupedVersions.join(", "); + + +} + auto Mod::releaseType() const -> QString { if (metadata()) diff --git a/launcher/minecraft/mod/Mod.h b/launcher/minecraft/mod/Mod.h index eceb8c256..43dc8e7c3 100644 --- a/launcher/minecraft/mod/Mod.h +++ b/launcher/minecraft/mod/Mod.h @@ -71,6 +71,7 @@ class Mod : public Resource { auto side() const -> QString; auto loaders() const -> QString; auto mcVersions() const -> QString; + auto groupMcVersions() const -> QString; auto releaseType() const -> QString; /** Get the intneral path to the mod's icon file*/ From 956843525b7e46dcd5870eb2637fcaf198b83f2f Mon Sep 17 00:00:00 2001 From: Charlie Date: Sat, 18 Oct 2025 10:08:29 +1100 Subject: [PATCH 3/9] grouping of versions Currently breaks without properly sorted mod mcVersions as some mod have and no current workaround for snapshots Signed-off-by: Charlie --- launcher/minecraft/mod/Mod.cpp | 65 ++++++++++++++++++++++++++++------ 1 file changed, 55 insertions(+), 10 deletions(-) diff --git a/launcher/minecraft/mod/Mod.cpp b/launcher/minecraft/mod/Mod.cpp index dc5d8f197..4accf6d5c 100644 --- a/launcher/minecraft/mod/Mod.cpp +++ b/launcher/minecraft/mod/Mod.cpp @@ -191,15 +191,18 @@ auto Mod::side() const -> QString auto Mod::mcVersions() const -> QString { if (metadata()) - return groupMcVersions(); - //return metadata()->mcVersions.join(", "); + // incase toggelable feature + if (0) { + return groupMcVersions(); + } else { + return metadata()->mcVersions.join(", "); + } return {}; } auto Mod::groupMcVersions() const -> QString { - static QStringList s_realeasedMcVersions = []() { // Gets all of minecrafts vanilla versions auto vlist = APPLICATION->metadataIndex()->get("net.minecraft"); @@ -219,20 +222,62 @@ auto Mod::groupMcVersions() const -> QString } return filteredVersions; }(); - - // gets existing list of minecraft versions - // goes through current modpacks mcVersions in sequence checking if the next in the real minecraft versions exists QStringList filteredVersions = s_realeasedMcVersions; - QStringList groupedVersions; + QStringList *groupedVersions = new QStringList(); if (metadata()) { - for (int i = 0; i < metadata()->mcVersions.size(); ++i) { - + QStringList ungroupedVersions = metadata()->mcVersions; + QString first = ungroupedVersions[0]; + int count = 0; + int ungroupedSize = ungroupedVersions.size(); + bool grouping = false; + for (int i = filteredVersions.size() - 1; i >= 0; --i) { + if (grouping) { + // traversing the ungrouped versions and checking if they match the order of releases + if (! filteredVersions[i].compare(ungroupedVersions[count])) { + count += 1; + if (count >= ungroupedSize) { + break; + } + } + // next version doesnt match, break grouping, append and update next grouping + else { + grouping = false; + // check if grouping occured + if (! first.compare(ungroupedVersions[count - 1])) { + (*groupedVersions).append(first); + } else { + QString groupBuff = first.append('-').append(ungroupedVersions[count - 1]); + (*groupedVersions).append(groupBuff); + } + // set up next grouping + first = ungroupedVersions[count]; + } + } else { + // traverses all oldest to newest versions until modded version starts + if (! filteredVersions.at(i).compare(first)) { + grouping = true; + count += 1; + if (count >= ungroupedSize) { + break; + } + } + } } + // case for last version included in mod + if (grouping) { + if (! first.compare(ungroupedVersions[count - 1])) { + (*groupedVersions).append(first); + } else { + QString groupBuff = first.append('-').append(ungroupedVersions[count - 1]); + (*groupedVersions).append(groupBuff); + } + } + return (*groupedVersions).join(", "); } - return groupedVersions.join(", "); + return {}; } From f1ac6832a30395298f82c389025f941a939adb46 Mon Sep 17 00:00:00 2001 From: Charlie Date: Sat, 18 Oct 2025 14:02:52 +1100 Subject: [PATCH 4/9] fixed string sorted versions bug and snapshots breaking grouping currently there is no showing of snapshot but can be easily added by storing the removed snapshots and appending them on the end Signed-off-by: Charlie --- launcher/minecraft/mod/Mod.cpp | 48 +++++++++++++++++++++++++++++++--- launcher/minecraft/mod/Mod.h | 1 + 2 files changed, 46 insertions(+), 3 deletions(-) diff --git a/launcher/minecraft/mod/Mod.cpp b/launcher/minecraft/mod/Mod.cpp index 4accf6d5c..ca34f54a7 100644 --- a/launcher/minecraft/mod/Mod.cpp +++ b/launcher/minecraft/mod/Mod.cpp @@ -53,6 +53,7 @@ #include "meta/Index.h" #include "ui/widgets/VersionSelectWidget.h" #include "ui/widgets/VersionListView.h" +#include Mod::Mod(const QFileInfo& file) : Resource(file), m_local_details() { @@ -192,7 +193,7 @@ auto Mod::mcVersions() const -> QString { if (metadata()) // incase toggelable feature - if (0) { + if (1) { return groupMcVersions(); } else { return metadata()->mcVersions.join(", "); @@ -204,7 +205,7 @@ auto Mod::mcVersions() const -> QString auto Mod::groupMcVersions() const -> QString { static QStringList s_realeasedMcVersions = []() { - // Gets all of minecrafts vanilla versions + // Gets all of minecrafts vanilla versions auto vlist = APPLICATION->metadataIndex()->get("net.minecraft"); VersionSelectWidget* versionList = new VersionSelectWidget(nullptr); versionList->initialize(vlist.get()); @@ -224,10 +225,22 @@ auto Mod::groupMcVersions() const -> QString }(); QStringList filteredVersions = s_realeasedMcVersions; + QStringList *groupedVersions = new QStringList(); if (metadata()) { - QStringList ungroupedVersions = metadata()->mcVersions; + std::vector myvector; + for (QString i : metadata()->mcVersions) { + if (i.size() >= 10) { + // snapshot get filtered out, can add separte control fro them here + } else { + myvector.push_back(i); + } + } + std::sort(myvector.begin(), myvector.end(), versionsSort); + QStringList ungroupedVersions(myvector.begin(), myvector.end()); + //QStringList ungroupedVersions = metadata()->mcVersions; + QString first = ungroupedVersions[0]; int count = 0; int ungroupedSize = ungroupedVersions.size(); @@ -282,6 +295,35 @@ auto Mod::groupMcVersions() const -> QString } +// return false if a > b +bool Mod::versionsSort(QString a, QString b) +{ + std::string stringA = a.toStdString(); + std::string stringB = b.toStdString(); + std::stringstream streamA(stringA); + std::stringstream streamB(stringB); + std::string bufA; + std::string bufB; + + while (getline(streamA, bufA, '.') && getline(streamB, bufB, '.')) { + int intA = atoi(bufA.c_str()); + int intB = atoi(bufB.c_str()); + if (intA == intB) { + continue; + } else if (intA > intB) { + return false; + } else { + return true; + } + } + // one is an 1.x instead of 1.x.y so the small length string is the lower version + if (stringA.size() > stringB.size()) { + return false; + } else { + return true; + } +} + auto Mod::releaseType() const -> QString { if (metadata()) diff --git a/launcher/minecraft/mod/Mod.h b/launcher/minecraft/mod/Mod.h index 43dc8e7c3..b2e873ac9 100644 --- a/launcher/minecraft/mod/Mod.h +++ b/launcher/minecraft/mod/Mod.h @@ -72,6 +72,7 @@ class Mod : public Resource { auto loaders() const -> QString; auto mcVersions() const -> QString; auto groupMcVersions() const -> QString; + static bool versionsSort(QString a, QString b); auto releaseType() const -> QString; /** Get the intneral path to the mod's icon file*/ From 3dacc533ce22b49b24decedbb04e37237a4cd3b1 Mon Sep 17 00:00:00 2001 From: DarkBRogers <122955001+DarkBrogers@users.noreply.github.com> Date: Sat, 18 Oct 2025 16:24:41 +1100 Subject: [PATCH 5/9] Formatting for Mod.cpp Some small contributions guidelines Signed-off-by: William Rogers u7941469@anu.edu.au Signed-off-by: DarkBRogers <122955001+DarkBrogers@users.noreply.github.com> Signed-off-by: Charlie --- launcher/minecraft/mod/Mod.cpp | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/launcher/minecraft/mod/Mod.cpp b/launcher/minecraft/mod/Mod.cpp index ca34f54a7..724fcf95a 100644 --- a/launcher/minecraft/mod/Mod.cpp +++ b/launcher/minecraft/mod/Mod.cpp @@ -192,19 +192,13 @@ auto Mod::side() const -> QString auto Mod::mcVersions() const -> QString { if (metadata()) - // incase toggelable feature - if (1) { return groupMcVersions(); - } else { - return metadata()->mcVersions.join(", "); - } - return {}; } auto Mod::groupMcVersions() const -> QString { - static QStringList s_realeasedMcVersions = []() { + static QStringList s_releasedMcVersions = []() { // Gets all of minecrafts vanilla versions auto vlist = APPLICATION->metadataIndex()->get("net.minecraft"); VersionSelectWidget* versionList = new VersionSelectWidget(nullptr); @@ -224,7 +218,7 @@ auto Mod::groupMcVersions() const -> QString return filteredVersions; }(); - QStringList filteredVersions = s_realeasedMcVersions; + QStringList filteredVersions = s_releasedMcVersions; QStringList *groupedVersions = new QStringList(); @@ -239,7 +233,6 @@ auto Mod::groupMcVersions() const -> QString } std::sort(myvector.begin(), myvector.end(), versionsSort); QStringList ungroupedVersions(myvector.begin(), myvector.end()); - //QStringList ungroupedVersions = metadata()->mcVersions; QString first = ungroupedVersions[0]; int count = 0; @@ -289,7 +282,6 @@ auto Mod::groupMcVersions() const -> QString } return (*groupedVersions).join(", "); } - return {}; From 8d98e407f931fa2e6adfc1d9929847b227de2055 Mon Sep 17 00:00:00 2001 From: DarkBRogers <122955001+DarkBrogers@users.noreply.github.com> Date: Sat, 18 Oct 2025 16:40:01 +1100 Subject: [PATCH 6/9] Removed the pointers Removed the pointers Signed-off-by: William Rogers u7941469@anu.edu.au Signed-off-by: DarkBRogers <122955001+DarkBrogers@users.noreply.github.com> Signed-off-by: Charlie --- launcher/minecraft/mod/Mod.cpp | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/launcher/minecraft/mod/Mod.cpp b/launcher/minecraft/mod/Mod.cpp index 724fcf95a..aa35ad8ff 100644 --- a/launcher/minecraft/mod/Mod.cpp +++ b/launcher/minecraft/mod/Mod.cpp @@ -201,18 +201,18 @@ auto Mod::groupMcVersions() const -> QString static QStringList s_releasedMcVersions = []() { // Gets all of minecrafts vanilla versions auto vlist = APPLICATION->metadataIndex()->get("net.minecraft"); - VersionSelectWidget* versionList = new VersionSelectWidget(nullptr); + VersionSelectWidget versionList(nullptr); versionList->initialize(vlist.get()); //Filters to only main released versions (like 1.19.2, 1.8.9) versionList->setFilter(BaseVersionList::TypeRole, Filters::regexp(QRegularExpression("(release)"))); auto model = versionList->view()->model(); - QAbstractItemModel* proxyModel = model; + // Versions get ordered latest to oldest QStringList filteredVersions; // extracts each version number from model - for (int row = 0; row < proxyModel->rowCount(); ++row) { - QModelIndex index = proxyModel->index(row, 0); - QVariant data = proxyModel->data(index, BaseVersionList::VersionRole); + for (int row = 0; row < model->rowCount(); ++row) { + QModelIndex index = model->index(row, 0); + QVariant data = model->data(index, BaseVersionList::VersionRole); filteredVersions << data.toString(); } return filteredVersions; @@ -220,7 +220,7 @@ auto Mod::groupMcVersions() const -> QString QStringList filteredVersions = s_releasedMcVersions; - QStringList *groupedVersions = new QStringList(); + QStringList groupedVersions; if (metadata()) { std::vector myvector; @@ -252,10 +252,10 @@ auto Mod::groupMcVersions() const -> QString grouping = false; // check if grouping occured if (! first.compare(ungroupedVersions[count - 1])) { - (*groupedVersions).append(first); + (groupedVersions).append(first); } else { QString groupBuff = first.append('-').append(ungroupedVersions[count - 1]); - (*groupedVersions).append(groupBuff); + (groupedVersions).append(groupBuff); } // set up next grouping first = ungroupedVersions[count]; @@ -274,13 +274,13 @@ auto Mod::groupMcVersions() const -> QString // case for last version included in mod if (grouping) { if (! first.compare(ungroupedVersions[count - 1])) { - (*groupedVersions).append(first); + (groupedVersions).append(first); } else { QString groupBuff = first.append('-').append(ungroupedVersions[count - 1]); - (*groupedVersions).append(groupBuff); + (groupedVersions).append(groupBuff); } } - return (*groupedVersions).join(", "); + return (groupedVersions).join(", "); } return {}; From afbc81bc38693fc70f2d4728a27b9805192ca0ab Mon Sep 17 00:00:00 2001 From: Charlie Date: Sun, 19 Oct 2025 10:46:13 +1100 Subject: [PATCH 7/9] error from VersionSelectWidget* not being a pointer Signed-off-by: Charlie --- launcher/minecraft/mod/Mod.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/launcher/minecraft/mod/Mod.cpp b/launcher/minecraft/mod/Mod.cpp index aa35ad8ff..97ab3803f 100644 --- a/launcher/minecraft/mod/Mod.cpp +++ b/launcher/minecraft/mod/Mod.cpp @@ -201,7 +201,7 @@ auto Mod::groupMcVersions() const -> QString static QStringList s_releasedMcVersions = []() { // Gets all of minecrafts vanilla versions auto vlist = APPLICATION->metadataIndex()->get("net.minecraft"); - VersionSelectWidget versionList(nullptr); + VersionSelectWidget* versionList(nullptr); versionList->initialize(vlist.get()); //Filters to only main released versions (like 1.19.2, 1.8.9) versionList->setFilter(BaseVersionList::TypeRole, Filters::regexp(QRegularExpression("(release)"))); From 29363db4a568abfaf65be9378725b53b6b498064 Mon Sep 17 00:00:00 2001 From: Charlie Date: Sun, 19 Oct 2025 11:31:30 +1100 Subject: [PATCH 8/9] pointer not being initialized Signed-off-by: Charlie --- launcher/minecraft/mod/Mod.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/launcher/minecraft/mod/Mod.cpp b/launcher/minecraft/mod/Mod.cpp index 97ab3803f..a5b9ffff8 100644 --- a/launcher/minecraft/mod/Mod.cpp +++ b/launcher/minecraft/mod/Mod.cpp @@ -192,7 +192,7 @@ auto Mod::side() const -> QString auto Mod::mcVersions() const -> QString { if (metadata()) - return groupMcVersions(); + return groupMcVersions(); return {}; } @@ -201,7 +201,7 @@ auto Mod::groupMcVersions() const -> QString static QStringList s_releasedMcVersions = []() { // Gets all of minecrafts vanilla versions auto vlist = APPLICATION->metadataIndex()->get("net.minecraft"); - VersionSelectWidget* versionList(nullptr); + VersionSelectWidget* versionList = new VersionSelectWidget(nullptr); versionList->initialize(vlist.get()); //Filters to only main released versions (like 1.19.2, 1.8.9) versionList->setFilter(BaseVersionList::TypeRole, Filters::regexp(QRegularExpression("(release)"))); From 7dc59bc4d4f44edf382d80af1ebad3d2448bdc5c Mon Sep 17 00:00:00 2001 From: Charlie Date: Thu, 23 Oct 2025 09:00:41 +1100 Subject: [PATCH 9/9] Revert "fix: prioritize .ftbapp/version.json in FTB App import" Accidentally put this commit in my branch This reverts commit bd49dc4e7b6b85cc160bd58a78a9474a898b995b. --- launcher/modplatform/import_ftb/PackHelpers.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/launcher/modplatform/import_ftb/PackHelpers.cpp b/launcher/modplatform/import_ftb/PackHelpers.cpp index 22d1242e9..089b5fff2 100644 --- a/launcher/modplatform/import_ftb/PackHelpers.cpp +++ b/launcher/modplatform/import_ftb/PackHelpers.cpp @@ -79,9 +79,9 @@ Modpack parseDirectory(QString path) return {}; } - auto versionsFile = QFileInfo(FS::PathCombine(path, ".ftbapp", "version.json")); + auto versionsFile = QFileInfo(FS::PathCombine(path, "version.json")); if (!versionsFile.exists() || !versionsFile.isFile()) { - versionsFile = QFileInfo(FS::PathCombine(path, "version.json")); + versionsFile = QFileInfo(FS::PathCombine(path, ".ftbapp", "version.json")); } if (!versionsFile.exists() || !versionsFile.isFile()) { return {};