From d44fa416ca556de678def8d2846349ff190e641e Mon Sep 17 00:00:00 2001 From: Jamie Mansfield Date: Fri, 24 Dec 2021 15:00:36 +0000 Subject: Technic: Allow pack API urls to be used in search This mimics the behaviour that the Technic launcher has, and their website displays API URLs for. The big benefit of this, is to be able to install private packs now :) --- .../ui/pages/modplatform/technic/TechnicModel.cpp | 121 ++++++++++++++++----- .../ui/pages/modplatform/technic/TechnicModel.h | 44 ++++++-- 2 files changed, 125 insertions(+), 40 deletions(-) (limited to 'launcher/ui') diff --git a/launcher/ui/pages/modplatform/technic/TechnicModel.cpp b/launcher/ui/pages/modplatform/technic/TechnicModel.cpp index 0167f746..37db839c 100644 --- a/launcher/ui/pages/modplatform/technic/TechnicModel.cpp +++ b/launcher/ui/pages/modplatform/technic/TechnicModel.cpp @@ -1,16 +1,36 @@ -/* Copyright 2020-2021 MultiMC Contributors +// SPDX-License-Identifier: GPL-3.0-only +/* + * PolyMC - Minecraft Launcher + * Copyright (c) 2021 Jamie Mansfield * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at + * 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. * - * http://www.apache.org/licenses/LICENSE-2.0 + * 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. * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * This file incorporates work covered by the following copyright and + * permission notice: + * + * Copyright 2020-2021 MultiMC Contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ #include "TechnicModel.h" @@ -95,12 +115,21 @@ void Technic::ListModel::performSearch() QString searchUrl = ""; if (currentSearchTerm.isEmpty()) { searchUrl = "https://api.technicpack.net/trending?build=multimc"; + searchMode = List; } - else - { + else if (currentSearchTerm.startsWith("http://api.technicpack.net/modpack/")) { + searchUrl = QString("https://%1?build=multimc").arg(currentSearchTerm.mid(7)); + searchMode = Single; + } + else if (currentSearchTerm.startsWith("https://api.technicpack.net/modpack/")) { + searchUrl = QString("%1?build=multimc").arg(currentSearchTerm); + searchMode = Single; + } + else { searchUrl = QString( "https://api.technicpack.net/search?build=multimc&q=%1" ).arg(currentSearchTerm); + searchMode = List; } netJob->addNetAction(Net::Download::makeByteArray(QUrl(searchUrl), &response)); jobPtr = netJob; @@ -125,26 +154,58 @@ void Technic::ListModel::searchRequestFinished() QList newList; try { auto root = Json::requireObject(doc); - auto objs = Json::requireArray(root, "modpacks"); - for (auto technicPack: objs) { - Modpack pack; - auto technicPackObject = Json::requireObject(technicPack); - pack.name = Json::requireString(technicPackObject, "name"); - pack.slug = Json::requireString(technicPackObject, "slug"); - if (pack.slug == "vanilla") - continue; - - auto rawURL = Json::ensureString(technicPackObject, "iconUrl", "null"); - if(rawURL == "null") { - pack.logoUrl = "null"; - pack.logoName = "null"; + + switch (searchMode) { + case List: { + auto objs = Json::requireArray(root, "modpacks"); + for (auto technicPack: objs) { + Modpack pack; + auto technicPackObject = Json::requireObject(technicPack); + pack.name = Json::requireString(technicPackObject, "name"); + pack.slug = Json::requireString(technicPackObject, "slug"); + if (pack.slug == "vanilla") + continue; + + auto rawURL = Json::ensureString(technicPackObject, "iconUrl", "null"); + if(rawURL == "null") { + pack.logoUrl = "null"; + pack.logoName = "null"; + } + else { + pack.logoUrl = rawURL; + pack.logoName = rawURL.section(QLatin1Char('/'), -1).section(QLatin1Char('.'), 0, 0); + } + pack.broken = false; + newList.append(pack); + } + break; } - else { - pack.logoUrl = rawURL; - pack.logoName = rawURL.section(QLatin1Char('/'), -1).section(QLatin1Char('.'), 0, 0); + case Single: { + if (root.contains("error")) { + // Invalid API url + break; + } + + Modpack pack; + pack.name = Json::requireString(root, "displayName"); + pack.slug = Json::requireString(root, "name"); + + if (root.contains("icon")) { + auto iconObj = Json::requireObject(root, "icon"); + auto iconUrl = Json::requireString(iconObj, "url"); + + pack.logoUrl = iconUrl; + pack.logoName = iconUrl.section(QLatin1Char('/'), -1).section(QLatin1Char('.'), 0, 0); + } + else { + pack.logoUrl = "null"; + pack.logoName = "null"; + } + + pack.broken = false; + newList.append(pack); + break; } - pack.broken = false; - newList.append(pack); } } catch (const JSONValidationError &err) diff --git a/launcher/ui/pages/modplatform/technic/TechnicModel.h b/launcher/ui/pages/modplatform/technic/TechnicModel.h index e80e6e7c..5eea124c 100644 --- a/launcher/ui/pages/modplatform/technic/TechnicModel.h +++ b/launcher/ui/pages/modplatform/technic/TechnicModel.h @@ -1,16 +1,36 @@ -/* Copyright 2020-2021 MultiMC Contributors +// SPDX-License-Identifier: GPL-3.0-only +/* + * PolyMC - Minecraft Launcher + * Copyright (c) 2021 Jamie Mansfield * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at + * 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. * - * http://www.apache.org/licenses/LICENSE-2.0 + * 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. * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * This file incorporates work covered by the following copyright and + * permission notice: + * + * Copyright 2020-2021 MultiMC Contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ #pragma once @@ -63,6 +83,10 @@ private: ResetRequested, Finished } searchState = None; + enum SearchMode { + List, + Single, + } searchMode = List; NetJob::Ptr jobPtr; QByteArray response; }; -- cgit From f267375ac2d0086bf7cde7512b34ab324da375d4 Mon Sep 17 00:00:00 2001 From: Jamie Mansfield Date: Fri, 24 Dec 2021 15:20:34 +0000 Subject: Technic: Prevent potential HTML injection --- launcher/ui/pages/modplatform/technic/TechnicPage.cpp | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) (limited to 'launcher/ui') diff --git a/launcher/ui/pages/modplatform/technic/TechnicPage.cpp b/launcher/ui/pages/modplatform/technic/TechnicPage.cpp index c3807269..25b6fd44 100644 --- a/launcher/ui/pages/modplatform/technic/TechnicPage.cpp +++ b/launcher/ui/pages/modplatform/technic/TechnicPage.cpp @@ -202,14 +202,12 @@ void TechnicPage::metadataLoaded() QString name = current.name; if (current.websiteUrl.isEmpty()) - // This allows injecting HTML here. - text = name; + text = name.toHtmlEscaped(); else - // URL not properly escaped for inclusion in HTML. The name allows for injecting HTML. - text = "" + name + ""; + text = "" + name.toHtmlEscaped() + ""; + if (!current.author.isEmpty()) { - // This allows injecting HTML here - text += tr(" by ") + current.author; + text += tr(" by ") + current.author.toHtmlEscaped(); } ui->frame->setModText(text); -- cgit From 9d88f0795594f3f01d35bab4eb3767566b36c45c Mon Sep 17 00:00:00 2001 From: Jamie Mansfield Date: Fri, 24 Dec 2021 15:10:42 +0000 Subject: Technic: Include the modpack version in instance title --- launcher/ui/pages/modplatform/technic/TechnicData.h | 1 + launcher/ui/pages/modplatform/technic/TechnicPage.cpp | 5 +++-- 2 files changed, 4 insertions(+), 2 deletions(-) (limited to 'launcher/ui') diff --git a/launcher/ui/pages/modplatform/technic/TechnicData.h b/launcher/ui/pages/modplatform/technic/TechnicData.h index 50fd75e8..4a374a6b 100644 --- a/launcher/ui/pages/modplatform/technic/TechnicData.h +++ b/launcher/ui/pages/modplatform/technic/TechnicData.h @@ -36,6 +36,7 @@ struct Modpack { QString websiteUrl; QString author; QString description; + QString currentVersion; }; } diff --git a/launcher/ui/pages/modplatform/technic/TechnicPage.cpp b/launcher/ui/pages/modplatform/technic/TechnicPage.cpp index 25b6fd44..c68021d8 100644 --- a/launcher/ui/pages/modplatform/technic/TechnicPage.cpp +++ b/launcher/ui/pages/modplatform/technic/TechnicPage.cpp @@ -189,6 +189,7 @@ void TechnicPage::suggestCurrent() current.websiteUrl = Json::ensureString(obj, "platformUrl", QString(), "__placeholder__"); current.author = Json::ensureString(obj, "user", QString(), "__placeholder__"); current.description = Json::ensureString(obj, "description", QString(), "__placeholder__"); + current.currentVersion = Json::ensureString(obj, "version", QString(), "__placeholder__"); current.metadataLoaded = true; metadataLoaded(); }); @@ -214,11 +215,11 @@ void TechnicPage::metadataLoaded() ui->frame->setModDescription(current.description); if (!current.isSolder) { - dialog->setSuggestedPack(current.name, new Technic::SingleZipPackInstallTask(current.url, current.minecraftVersion)); + dialog->setSuggestedPack(current.name + " " + current.currentVersion, new Technic::SingleZipPackInstallTask(current.url, current.minecraftVersion)); } else { while (current.url.endsWith('/')) current.url.chop(1); - dialog->setSuggestedPack(current.name, new Technic::SolderPackInstallTask(APPLICATION->network(), current.url + "/modpack/" + current.slug, current.minecraftVersion)); + dialog->setSuggestedPack(current.name + " " + current.currentVersion, new Technic::SolderPackInstallTask(APPLICATION->network(), current.url + "/modpack/" + current.slug, current.minecraftVersion)); } } -- cgit From c8092269baf92c05a8b2433fc644f1039a041bfa Mon Sep 17 00:00:00 2001 From: Jamie Mansfield Date: Mon, 27 Dec 2021 03:55:08 +0000 Subject: Technic: Match CurseForge pack description format --- launcher/ui/pages/modplatform/technic/TechnicPage.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'launcher/ui') diff --git a/launcher/ui/pages/modplatform/technic/TechnicPage.cpp b/launcher/ui/pages/modplatform/technic/TechnicPage.cpp index c68021d8..49682904 100644 --- a/launcher/ui/pages/modplatform/technic/TechnicPage.cpp +++ b/launcher/ui/pages/modplatform/technic/TechnicPage.cpp @@ -208,7 +208,7 @@ void TechnicPage::metadataLoaded() text = "" + name.toHtmlEscaped() + ""; if (!current.author.isEmpty()) { - text += tr(" by ") + current.author.toHtmlEscaped(); + text += "
" + tr(" by ") + current.author.toHtmlEscaped(); } ui->frame->setModText(text); -- cgit From a232c2d50994d1e16b34ee84fbc24dcca80a4d9e Mon Sep 17 00:00:00 2001 From: Jamie Mansfield Date: Mon, 27 Dec 2021 03:52:54 +0000 Subject: Technic: Display available versions for Solder packs --- .../modplatform/technic/SolderPackInstallTask.cpp | 53 ++------- .../modplatform/technic/SolderPackInstallTask.h | 47 ++++++-- .../ui/pages/modplatform/technic/TechnicData.h | 45 +++++-- .../ui/pages/modplatform/technic/TechnicPage.cpp | 131 ++++++++++++++++++-- .../ui/pages/modplatform/technic/TechnicPage.h | 11 +- .../ui/pages/modplatform/technic/TechnicPage.ui | 132 ++++++++++----------- 6 files changed, 270 insertions(+), 149 deletions(-) (limited to 'launcher/ui') diff --git a/launcher/modplatform/technic/SolderPackInstallTask.cpp b/launcher/modplatform/technic/SolderPackInstallTask.cpp index aef87d78..abdfcd9e 100644 --- a/launcher/modplatform/technic/SolderPackInstallTask.cpp +++ b/launcher/modplatform/technic/SolderPackInstallTask.cpp @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-3.0-only /* * PolyMC - Minecraft Launcher - * Copyright (c) 2022 Jamie Mansfield + * Copyright (c) 2021-2022 Jamie Mansfield * * 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 @@ -45,12 +45,16 @@ Technic::SolderPackInstallTask::SolderPackInstallTask( shared_qobject_ptr network, - const QUrl &sourceUrl, + const QUrl &solderUrl, + const QString &pack, + const QString &version, const QString &minecraftVersion ) { - m_sourceUrl = sourceUrl; - m_minecraftVersion = minecraftVersion; + m_solderUrl = solderUrl; + m_pack = pack; + m_version = version; m_network = network; + m_minecraftVersion = minecraftVersion; } bool Technic::SolderPackInstallTask::abort() { @@ -62,45 +66,13 @@ bool Technic::SolderPackInstallTask::abort() { } void Technic::SolderPackInstallTask::executeTask() -{ - setStatus(tr("Finding recommended version")); - - m_filesNetJob = new NetJob(tr("Finding recommended version"), m_network); - m_filesNetJob->addNetAction(Net::Download::makeByteArray(m_sourceUrl, &m_response)); - - auto job = m_filesNetJob.get(); - connect(job, &NetJob::succeeded, this, &Technic::SolderPackInstallTask::versionSucceeded); - connect(job, &NetJob::failed, this, &Technic::SolderPackInstallTask::downloadFailed); - m_filesNetJob->start(); -} - -void Technic::SolderPackInstallTask::versionSucceeded() { setStatus(tr("Resolving modpack files")); - QJsonParseError parse_error {}; - QJsonDocument doc = QJsonDocument::fromJson(m_response, &parse_error); - if (parse_error.error != QJsonParseError::NoError) { - qWarning() << "Error while parsing JSON response from Solder at " << parse_error.offset << " reason: " << parse_error.errorString(); - qWarning() << m_response; - return; - } - auto obj = doc.object(); - - TechnicSolder::Pack pack; - try { - TechnicSolder::loadPack(pack, obj); - } - catch (const JSONValidationError& e) { - emitFailed(tr("Could not understand pack manifest:\n") + e.cause()); - m_filesNetJob.reset(); - return; - } - - m_sourceUrl = m_sourceUrl.toString() + '/' + pack.recommended; - m_filesNetJob = new NetJob(tr("Resolving modpack files"), m_network); - m_filesNetJob->addNetAction(Net::Download::makeByteArray(m_sourceUrl, &m_response)); + auto sourceUrl = QString("%1/modpack/%2/%3").arg(m_solderUrl.toString(), m_pack, m_version); + m_filesNetJob->addNetAction(Net::Download::makeByteArray(sourceUrl, &m_response)); + auto job = m_filesNetJob.get(); connect(job, &NetJob::succeeded, this, &Technic::SolderPackInstallTask::fileListSucceeded); connect(job, &NetJob::failed, this, &Technic::SolderPackInstallTask::downloadFailed); @@ -136,8 +108,7 @@ void Technic::SolderPackInstallTask::fileListSucceeded() m_filesNetJob = new NetJob(tr("Downloading modpack"), m_network); int i = 0; - for (const auto &mod : build.mods) - { + for (const auto &mod : build.mods) { auto path = FS::PathCombine(m_outputDir.path(), QString("%1").arg(i)); m_filesNetJob->addNetAction(Net::Download::makeFile(mod.url, path)); i++; diff --git a/launcher/modplatform/technic/SolderPackInstallTask.h b/launcher/modplatform/technic/SolderPackInstallTask.h index 9b2058d8..117a7bd6 100644 --- a/launcher/modplatform/technic/SolderPackInstallTask.h +++ b/launcher/modplatform/technic/SolderPackInstallTask.h @@ -1,16 +1,36 @@ -/* Copyright 2013-2021 MultiMC Contributors +// SPDX-License-Identifier: GPL-3.0-only +/* + * PolyMC - Minecraft Launcher + * Copyright (c) 2021-2022 Jamie Mansfield * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at + * 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. * - * http://www.apache.org/licenses/LICENSE-2.0 + * 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. * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * This file incorporates work covered by the following copyright and + * permission notice: + * + * Copyright 2013-2021 MultiMC Contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ #pragma once @@ -27,7 +47,7 @@ namespace Technic { Q_OBJECT public: - explicit SolderPackInstallTask(shared_qobject_ptr network, const QUrl &sourceUrl, const QString &minecraftVersion); + explicit SolderPackInstallTask(shared_qobject_ptr network, const QUrl &solderUrl, const QString& pack, const QString& version, const QString &minecraftVersion); bool canAbort() const override { return true; } bool abort() override; @@ -37,7 +57,6 @@ namespace Technic virtual void executeTask() override; private slots: - void versionSucceeded(); void fileListSucceeded(); void downloadSucceeded(); void downloadFailed(QString reason); @@ -51,7 +70,9 @@ namespace Technic shared_qobject_ptr m_network; NetJob::Ptr m_filesNetJob; - QUrl m_sourceUrl; + QUrl m_solderUrl; + QString m_pack; + QString m_version; QString m_minecraftVersion; QByteArray m_response; QTemporaryDir m_outputDir; diff --git a/launcher/ui/pages/modplatform/technic/TechnicData.h b/launcher/ui/pages/modplatform/technic/TechnicData.h index 4a374a6b..cd2ea8e1 100644 --- a/launcher/ui/pages/modplatform/technic/TechnicData.h +++ b/launcher/ui/pages/modplatform/technic/TechnicData.h @@ -1,22 +1,43 @@ -/* Copyright 2020-2021 MultiMC Contributors +// SPDX-License-Identifier: GPL-3.0-only +/* + * PolyMC - Minecraft Launcher + * Copyright (c) 2021-2022 Jamie Mansfield * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at + * 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. * - * http://www.apache.org/licenses/LICENSE-2.0 + * 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. * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * This file incorporates work covered by the following copyright and + * permission notice: + * + * Copyright 2020-2021 MultiMC Contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ #pragma once #include #include +#include namespace Technic { struct Modpack { @@ -37,6 +58,10 @@ struct Modpack { QString author; QString description; QString currentVersion; + + bool versionsLoaded = false; + QString recommended; + QVector versions; }; } diff --git a/launcher/ui/pages/modplatform/technic/TechnicPage.cpp b/launcher/ui/pages/modplatform/technic/TechnicPage.cpp index 49682904..776361ed 100644 --- a/launcher/ui/pages/modplatform/technic/TechnicPage.cpp +++ b/launcher/ui/pages/modplatform/technic/TechnicPage.cpp @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-3.0-only /* * PolyMC - Minecraft Launcher - * Copyright (c) 2022 Jamie Mansfield + * Copyright (c) 2021-2022 Jamie Mansfield * * 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 @@ -46,6 +46,7 @@ #include "Json.h" #include "Application.h" +#include "modplatform/technic/SolderPackManifest.h" TechnicPage::TechnicPage(NewInstanceDialog* dialog, QWidget *parent) : QWidget(parent), ui(new Ui::TechnicPage), dialog(dialog) @@ -55,7 +56,9 @@ TechnicPage::TechnicPage(NewInstanceDialog* dialog, QWidget *parent) ui->searchEdit->installEventFilter(this); model = new Technic::ListModel(this); ui->packView->setModel(model); + connect(ui->packView->selectionModel(), &QItemSelectionModel::currentChanged, this, &TechnicPage::onSelectionChanged); + connect(ui->versionSelectionBox, &QComboBox::currentTextChanged, this, &TechnicPage::onVersionSelectionChanged); } bool TechnicPage::eventFilter(QObject* watched, QEvent* event) @@ -98,13 +101,14 @@ void TechnicPage::triggerSearch() { void TechnicPage::onSelectionChanged(QModelIndex first, QModelIndex second) { + ui->versionSelectionBox->clear(); + if(!first.isValid()) { if(isOpened) { dialog->setSuggestedPack(); } - //ui->frame->clear(); return; } @@ -137,17 +141,19 @@ void TechnicPage::suggestCurrent() } NetJob *netJob = new NetJob(QString("Technic::PackMeta(%1)").arg(current.name), APPLICATION->network()); - std::shared_ptr response = std::make_shared(); QString slug = current.slug; - netJob->addNetAction(Net::Download::makeByteArray(QString("https://api.technicpack.net/modpack/%1?build=multimc").arg(slug), response.get())); - QObject::connect(netJob, &NetJob::succeeded, this, [this, response, slug] + netJob->addNetAction(Net::Download::makeByteArray(QString("https://api.technicpack.net/modpack/%1?build=multimc").arg(slug), &response)); + QObject::connect(netJob, &NetJob::succeeded, this, [this, slug] { + jobPtr.reset(); + if (current.slug != slug) { return; } - QJsonParseError parse_error; - QJsonDocument doc = QJsonDocument::fromJson(*response, &parse_error); + + QJsonParseError parse_error {}; + QJsonDocument doc = QJsonDocument::fromJson(response, &parse_error); QJsonObject obj = doc.object(); if(parse_error.error != QJsonParseError::NoError) { @@ -191,9 +197,12 @@ void TechnicPage::suggestCurrent() current.description = Json::ensureString(obj, "description", QString(), "__placeholder__"); current.currentVersion = Json::ensureString(obj, "version", QString(), "__placeholder__"); current.metadataLoaded = true; + metadataLoaded(); }); - netJob->start(); + + jobPtr = netJob; + jobPtr->start(); } // expects current.metadataLoaded to be true @@ -211,15 +220,111 @@ void TechnicPage::metadataLoaded() text += "
" + tr(" by ") + current.author.toHtmlEscaped(); } - ui->frame->setModText(text); - ui->frame->setModDescription(current.description); + text += "

"; + + ui->packDescription->setHtml(text + current.description); + + // Strip trailing forward-slashes from Solder URL's + if (current.isSolder) { + while (current.url.endsWith('/')) current.url.chop(1); + } + + // Display versions from Solder + if (!current.isSolder) { + // If the pack isn't a Solder pack, it only has the single version + ui->versionSelectionBox->addItem(current.currentVersion); + } + else if (current.versionsLoaded) { + // reverse foreach, so that the newest versions are first + for (auto i = current.versions.size(); i--;) { + ui->versionSelectionBox->addItem(current.versions.at(i)); + } + ui->versionSelectionBox->setCurrentText(current.recommended); + } + else { + // For now, until the versions are pulled from the Solder instance, display the current + // version so we can display something quicker + ui->versionSelectionBox->addItem(current.currentVersion); + + auto* netJob = new NetJob(QString("Technic::SolderMeta(%1)").arg(current.name), APPLICATION->network()); + auto url = QString("%1/modpack/%2").arg(current.url, current.slug); + netJob->addNetAction(Net::Download::makeByteArray(QUrl(url), &response)); + + QObject::connect(netJob, &NetJob::succeeded, this, &TechnicPage::onSolderLoaded); + + jobPtr = netJob; + jobPtr->start(); + } + + selectVersion(); +} + +void TechnicPage::selectVersion() { + if (!isOpened) { + return; + } + if (current.broken) { + dialog->setSuggestedPack(); + return; + } + if (!current.isSolder) { - dialog->setSuggestedPack(current.name + " " + current.currentVersion, new Technic::SingleZipPackInstallTask(current.url, current.minecraftVersion)); + dialog->setSuggestedPack(current.name + " " + selectedVersion, new Technic::SingleZipPackInstallTask(current.url, current.minecraftVersion)); } else { - while (current.url.endsWith('/')) current.url.chop(1); - dialog->setSuggestedPack(current.name + " " + current.currentVersion, new Technic::SolderPackInstallTask(APPLICATION->network(), current.url + "/modpack/" + current.slug, current.minecraftVersion)); + dialog->setSuggestedPack(current.name + " " + selectedVersion, new Technic::SolderPackInstallTask(APPLICATION->network(), current.url, current.slug, selectedVersion, current.minecraftVersion)); + } +} + +void TechnicPage::onSolderLoaded() { + jobPtr.reset(); + + auto fallback = [this]() { + current.versionsLoaded = true; + + current.versions.clear(); + current.versions.append(current.currentVersion); + }; + + current.versions.clear(); + + QJsonParseError parse_error {}; + auto doc = QJsonDocument::fromJson(response, &parse_error); + if (parse_error.error != QJsonParseError::NoError) { + qWarning() << "Error while parsing JSON response from Solder at " << parse_error.offset << " reason: " << parse_error.errorString(); + qWarning() << response; + fallback(); + return; } + auto obj = doc.object(); + + TechnicSolder::Pack pack; + try { + TechnicSolder::loadPack(pack, obj); + } + catch (const JSONValidationError& err) { + qCritical() << "Couldn't parse Solder pack metadata:" << err.cause(); + fallback(); + return; + } + + current.versionsLoaded = true; + current.recommended = pack.recommended; + current.versions.append(pack.builds); + + // Finally, let's reload :) + ui->versionSelectionBox->clear(); + metadataLoaded(); +} + +void TechnicPage::onVersionSelectionChanged(QString data) { + if (data.isNull() || data.isEmpty()) { + selectedVersion = ""; + return; + } + + selectedVersion = data; + selectVersion(); } diff --git a/launcher/ui/pages/modplatform/technic/TechnicPage.h b/launcher/ui/pages/modplatform/technic/TechnicPage.h index bf4baa58..f4a3b61d 100644 --- a/launcher/ui/pages/modplatform/technic/TechnicPage.h +++ b/launcher/ui/pages/modplatform/technic/TechnicPage.h @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-3.0-only /* * PolyMC - Minecraft Launcher - * Copyright (c) 2022 Jamie Mansfield + * Copyright (c) 2021-2022 Jamie Mansfield * * 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 @@ -39,6 +39,7 @@ #include "ui/pages/BasePage.h" #include +#include "net/NetJob.h" #include "tasks/Task.h" #include "TechnicData.h" @@ -86,14 +87,22 @@ public: private: void suggestCurrent(); void metadataLoaded(); + void selectVersion(); private slots: void triggerSearch(); void onSelectionChanged(QModelIndex first, QModelIndex second); + void onSolderLoaded(); + void onVersionSelectionChanged(QString data); private: Ui::TechnicPage *ui = nullptr; NewInstanceDialog* dialog = nullptr; Technic::ListModel* model = nullptr; + Technic::Modpack current; + QString selectedVersion; + + NetJob::Ptr jobPtr; + QByteArray response; }; diff --git a/launcher/ui/pages/modplatform/technic/TechnicPage.ui b/launcher/ui/pages/modplatform/technic/TechnicPage.ui index 62ab6154..ca6a9b7e 100644 --- a/launcher/ui/pages/modplatform/technic/TechnicPage.ui +++ b/launcher/ui/pages/modplatform/technic/TechnicPage.ui @@ -10,86 +10,76 @@ 405 - - - - - - 0 - - - 0 - - - 0 - - - 0 - - - - - Search and filter... - - - - - - - Search - - - - - + + + + + + + + + + Version selected: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + Qt::Horizontal + + + QSizePolicy::Preferred + + + + 1 + 1 + + + + + - - - - Qt::ScrollBarAlwaysOff - - - true - - - - 48 - 48 - + + + + + + true + + + + 48 + 48 + + + + + + + + + + + + + Search and filter... - - - - - 0 - 0 - - - - QFrame::StyledPanel - - - QFrame::Raised + + + + Search - - - MCModInfoFrame - QFrame -
ui/widgets/MCModInfoFrame.h
- 1 -
-
- - searchEdit - searchButton - packView - -- cgit From b6e722a048aabd35d6e2d8db3ad26e50b1f5a7fb Mon Sep 17 00:00:00 2001 From: Jamie Mansfield Date: Sun, 9 Jan 2022 23:02:32 +0000 Subject: BuildConfig: Make Technic API base URL and build constants --- buildconfig/BuildConfig.h | 6 ++++++ launcher/ui/pages/modplatform/technic/TechnicModel.cpp | 13 ++++++++----- launcher/ui/pages/modplatform/technic/TechnicPage.cpp | 3 ++- 3 files changed, 16 insertions(+), 6 deletions(-) (limited to 'launcher/ui') diff --git a/buildconfig/BuildConfig.h b/buildconfig/BuildConfig.h index 2fb71f14..6304387c 100644 --- a/buildconfig/BuildConfig.h +++ b/buildconfig/BuildConfig.h @@ -140,6 +140,12 @@ public: QString ATL_DOWNLOAD_SERVER_URL = "https://download.nodecdn.net/containers/atl/"; + QString TECHNIC_API_BASE_URL = "https://api.technicpack.net/"; + /** + * The build that is reported to the Technic API. + */ + QString TECHNIC_API_BUILD = "multimc"; + /** * \brief Converts the Version to a string. * \return The version number in string format (major.minor.revision.build). diff --git a/launcher/ui/pages/modplatform/technic/TechnicModel.cpp b/launcher/ui/pages/modplatform/technic/TechnicModel.cpp index 37db839c..9c9d1e75 100644 --- a/launcher/ui/pages/modplatform/technic/TechnicModel.cpp +++ b/launcher/ui/pages/modplatform/technic/TechnicModel.cpp @@ -35,6 +35,7 @@ #include "TechnicModel.h" #include "Application.h" +#include "BuildConfig.h" #include "Json.h" #include @@ -114,21 +115,23 @@ void Technic::ListModel::performSearch() NetJob *netJob = new NetJob("Technic::Search", APPLICATION->network()); QString searchUrl = ""; if (currentSearchTerm.isEmpty()) { - searchUrl = "https://api.technicpack.net/trending?build=multimc"; + searchUrl = QString("%1trending?build=%2") + .arg(BuildConfig.TECHNIC_API_BASE_URL, BuildConfig.TECHNIC_API_BUILD); searchMode = List; } else if (currentSearchTerm.startsWith("http://api.technicpack.net/modpack/")) { - searchUrl = QString("https://%1?build=multimc").arg(currentSearchTerm.mid(7)); + searchUrl = QString("https://%1?build=%2") + .arg(currentSearchTerm.mid(7), BuildConfig.TECHNIC_API_BUILD); searchMode = Single; } else if (currentSearchTerm.startsWith("https://api.technicpack.net/modpack/")) { - searchUrl = QString("%1?build=multimc").arg(currentSearchTerm); + searchUrl = QString("%1?build=%2").arg(currentSearchTerm, BuildConfig.TECHNIC_API_BUILD); searchMode = Single; } else { searchUrl = QString( - "https://api.technicpack.net/search?build=multimc&q=%1" - ).arg(currentSearchTerm); + "%1search?build=%2&q=%3" + ).arg(BuildConfig.TECHNIC_API_BASE_URL, BuildConfig.TECHNIC_API_BUILD, currentSearchTerm); searchMode = List; } netJob->addNetAction(Net::Download::makeByteArray(QUrl(searchUrl), &response)); diff --git a/launcher/ui/pages/modplatform/technic/TechnicPage.cpp b/launcher/ui/pages/modplatform/technic/TechnicPage.cpp index 776361ed..b8c1e00a 100644 --- a/launcher/ui/pages/modplatform/technic/TechnicPage.cpp +++ b/launcher/ui/pages/modplatform/technic/TechnicPage.cpp @@ -40,6 +40,7 @@ #include "ui/dialogs/NewInstanceDialog.h" +#include "BuildConfig.h" #include "TechnicModel.h" #include "modplatform/technic/SingleZipPackInstallTask.h" #include "modplatform/technic/SolderPackInstallTask.h" @@ -142,7 +143,7 @@ void TechnicPage::suggestCurrent() NetJob *netJob = new NetJob(QString("Technic::PackMeta(%1)").arg(current.name), APPLICATION->network()); QString slug = current.slug; - netJob->addNetAction(Net::Download::makeByteArray(QString("https://api.technicpack.net/modpack/%1?build=multimc").arg(slug), &response)); + netJob->addNetAction(Net::Download::makeByteArray(QString("%1modpack/%2?build=%3").arg(BuildConfig.TECHNIC_API_BASE_URL, slug, BuildConfig.TECHNIC_API_BUILD), &response)); QObject::connect(netJob, &NetJob::succeeded, this, [this, slug] { jobPtr.reset(); -- cgit