diff options
Diffstat (limited to 'launcher/ui')
-rw-r--r-- | launcher/ui/MainWindow.cpp | 101 | ||||
-rw-r--r-- | launcher/ui/MainWindow.h | 2 | ||||
-rw-r--r-- | launcher/ui/dialogs/NewInstanceDialog.cpp | 7 | ||||
-rw-r--r-- | launcher/ui/dialogs/NewInstanceDialog.h | 43 | ||||
-rw-r--r-- | launcher/ui/pages/modplatform/ImportPage.cpp | 92 | ||||
-rw-r--r-- | launcher/ui/pages/modplatform/ImportPage.h | 3 | ||||
-rw-r--r-- | launcher/ui/pages/modplatform/ImportPage.ui | 2 |
7 files changed, 200 insertions, 50 deletions
diff --git a/launcher/ui/MainWindow.cpp b/launcher/ui/MainWindow.cpp index e342e833..dd383b23 100644 --- a/launcher/ui/MainWindow.cpp +++ b/launcher/ui/MainWindow.cpp @@ -118,11 +118,15 @@ #include "minecraft/mod/ShaderPackFolderModel.h" #include "minecraft/mod/tasks/LocalResourceParse.h" +#include "modplatform/flame/FlameAPI.h" + #include "KonamiCode.h" #include "InstanceCopyTask.h" #include "InstanceImportTask.h" +#include "Json.h" + #include "MMCTime.h" namespace { @@ -929,7 +933,7 @@ void MainWindow::finalizeInstance(InstancePtr inst) } } -void MainWindow::addInstance(QString url) +void MainWindow::addInstance(const QString& url, const QMap<QString, QString>& extra_info) { QString groupName; do { @@ -949,7 +953,7 @@ void MainWindow::addInstance(QString url) groupName = APPLICATION->settings()->get("LastUsedGroupForNewInstance").toString(); } - NewInstanceDialog newInstDlg(groupName, url, this); + NewInstanceDialog newInstDlg(groupName, url, extra_info, this); if (!newInstDlg.exec()) return; @@ -976,18 +980,101 @@ void MainWindow::processURLs(QList<QUrl> urls) if (url.scheme().isEmpty()) url.setScheme("file"); - if (!url.isLocalFile()) { // probably instance/modpack - addInstance(url.toString()); - break; + QMap<QString, QString> extra_info; + QUrl local_url; + if (!url.isLocalFile()) { // download the remote resource and identify + QUrl dl_url; + if(url.scheme() == "curseforge") { + // need to find the download link for the modpack / resource + // format of url curseforge://install?addonId=IDHERE&fileId=IDHERE + QUrlQuery query(url); + + auto addonId = query.allQueryItemValues("addonId")[0]; + auto fileId = query.allQueryItemValues("fileId")[0]; + + extra_info.insert("pack_id", addonId); + extra_info.insert("pack_version_id", fileId); + + auto array = std::make_shared<QByteArray>(); + + auto api = FlameAPI(); + auto job = api.getFile(addonId, fileId, array); + + QString resource_name; + + connect(job.get(), &Task::failed, this, + [this](QString reason) { CustomMessageBox::selectable(this, tr("Error"), reason, QMessageBox::Critical)->show(); }); + connect(job.get(), &Task::succeeded, this, [this, array, addonId, fileId, &dl_url, &resource_name] { + qDebug() << "Returned CFURL Json:\n" << array->toStdString().c_str(); + auto doc = Json::requireDocument(*array); + auto data = Json::ensureObject(Json::ensureObject(doc.object()), "data"); + // No way to find out if it's a mod or a modpack before here + // And also we need to check if it ends with .zip, instead of any better way + auto fileName = Json::ensureString(data, "fileName"); + + // Have to use ensureString then use QUrl to get proper url encoding + dl_url = QUrl(Json::ensureString(data, "downloadUrl", "", "downloadUrl")); + if (!dl_url.isValid()) { + CustomMessageBox::selectable( + this, tr("Error"), + tr("The modpack, mod, or resource %1 is blocked for third-parties! Please download it manually.").arg(fileName), + QMessageBox::Critical) + ->show(); + return; + } + + QFileInfo dl_file(dl_url.fileName()); + resource_name = Json::ensureString(data, "displayName", dl_file.completeBaseName(), "displayName"); + }); + + { // drop stack + ProgressDialog dlUrlDialod(this); + dlUrlDialod.setSkipButton(true, tr("Abort")); + dlUrlDialod.execWithTask(job.get()); + } + + + } else { + dl_url = url; + } + + if (!dl_url.isValid()) { + continue; // no valid url to download this resource + } + + const QString path = dl_url.host() + '/' + dl_url.path(); + auto entry = APPLICATION->metacache()->resolveEntry("general", path); + entry->setStale(true); + auto dl_job = unique_qobject_ptr<NetJob>(new NetJob(tr("Modpack download"), APPLICATION->network())); + dl_job->addNetAction(Net::Download::makeCached(dl_url, entry)); + auto archivePath = entry->getFullPath(); + + bool dl_success = false; + connect(dl_job.get(), &Task::failed, this, [this](QString reason){CustomMessageBox::selectable(this, tr("Error"), reason, QMessageBox::Critical)->show(); }); + connect(dl_job.get(), &Task::succeeded, this, [&dl_success]{dl_success = true;}); + + { // drop stack + ProgressDialog dlUrlDialod(this); + dlUrlDialod.setSkipButton(true, tr("Abort")); + dlUrlDialod.execWithTask(dl_job.get()); + } + + if (!dl_success) { + continue; // no local file to identify + } + local_url = QUrl::fromLocalFile(archivePath); + + } else { + local_url = url; } - auto localFileName = QDir::toNativeSeparators(url.toLocalFile()); + auto localFileName = QDir::toNativeSeparators(local_url.toLocalFile()); QFileInfo localFileInfo(localFileName); auto type = ResourceUtils::identify(localFileInfo); if (ResourceUtils::ValidResourceTypes.count(type) == 0) { // probably instance/modpack - addInstance(localFileName); + addInstance(localFileName, extra_info); continue; } diff --git a/launcher/ui/MainWindow.h b/launcher/ui/MainWindow.h index 27c2756f..7fab3fe3 100644 --- a/launcher/ui/MainWindow.h +++ b/launcher/ui/MainWindow.h @@ -217,7 +217,7 @@ private slots: private: void retranslateUi(); - void addInstance(QString url = QString()); + void addInstance(const QString& url = QString(), const QMap<QString, QString>& extra_info = {}); void activateInstance(InstancePtr instance); void setCatBackground(bool enabled); void updateInstanceToolIcon(QString new_icon); diff --git a/launcher/ui/dialogs/NewInstanceDialog.cpp b/launcher/ui/dialogs/NewInstanceDialog.cpp index 2f1854d8..935f095e 100644 --- a/launcher/ui/dialogs/NewInstanceDialog.cpp +++ b/launcher/ui/dialogs/NewInstanceDialog.cpp @@ -62,8 +62,10 @@ #include "ui/pages/modplatform/modrinth/ModrinthPage.h" #include "ui/pages/modplatform/technic/TechnicPage.h" #include "ui/widgets/PageContainer.h" - -NewInstanceDialog::NewInstanceDialog(const QString& initialGroup, const QString& url, QWidget* parent) +NewInstanceDialog::NewInstanceDialog(const QString& initialGroup, + const QString& url, + const QMap<QString, QString>& extra_info, + QWidget* parent) : QDialog(parent), ui(new Ui::NewInstanceDialog) { ui->setupUi(this); @@ -127,6 +129,7 @@ NewInstanceDialog::NewInstanceDialog(const QString& initialGroup, const QString& QUrl actualUrl(url); m_container->selectPage("import"); importPage->setUrl(url); + importPage->setExtraInfo(extra_info); } updateDialogState(); diff --git a/launcher/ui/dialogs/NewInstanceDialog.h b/launcher/ui/dialogs/NewInstanceDialog.h index 961f512e..6a6ad89e 100644 --- a/launcher/ui/dialogs/NewInstanceDialog.h +++ b/launcher/ui/dialogs/NewInstanceDialog.h @@ -37,11 +37,10 @@ #include <QDialog> -#include "ui/pages/BasePageProvider.h" #include "InstanceTask.h" +#include "ui/pages/BasePageProvider.h" -namespace Ui -{ +namespace Ui { class NewInstanceDialog; } @@ -50,45 +49,47 @@ class QDialogButtonBox; class ImportPage; class FlamePage; -class NewInstanceDialog : public QDialog, public BasePageProvider -{ +class NewInstanceDialog : public QDialog, public BasePageProvider { Q_OBJECT -public: - explicit NewInstanceDialog(const QString & initialGroup, const QString & url = QString(), QWidget *parent = 0); + public: + explicit NewInstanceDialog(const QString& initialGroup, + const QString& url = QString(), + const QMap<QString, QString>& extra_info = {}, + QWidget* parent = 0); ~NewInstanceDialog(); void updateDialogState(); - void setSuggestedPack(const QString& name = QString(), InstanceTask * task = nullptr); - void setSuggestedPack(const QString& name, QString version, InstanceTask * task = nullptr); - void setSuggestedIconFromFile(const QString &path, const QString &name); - void setSuggestedIcon(const QString &key); + void setSuggestedPack(const QString& name = QString(), InstanceTask* task = nullptr); + void setSuggestedPack(const QString& name, QString version, InstanceTask* task = nullptr); + void setSuggestedIconFromFile(const QString& path, const QString& name); + void setSuggestedIcon(const QString& key); - InstanceTask * extractTask(); + InstanceTask* extractTask(); QString dialogTitle() override; - QList<BasePage *> getPages() override; + QList<BasePage*> getPages() override; QString instName() const; QString instGroup() const; QString iconKey() const; -public slots: + public slots: void accept() override; void reject() override; -private slots: + private slots: void on_iconButton_clicked(); - void on_instNameTextBox_textChanged(const QString &arg1); + void on_instNameTextBox_textChanged(const QString& arg1); -private: - Ui::NewInstanceDialog *ui = nullptr; - PageContainer * m_container = nullptr; - QDialogButtonBox * m_buttons = nullptr; + private: + Ui::NewInstanceDialog* ui = nullptr; + PageContainer* m_container = nullptr; + QDialogButtonBox* m_buttons = nullptr; QString InstIconKey; - ImportPage *importPage = nullptr; + ImportPage* importPage = nullptr; std::unique_ptr<InstanceTask> creationTask; bool importIcon = false; diff --git a/launcher/ui/pages/modplatform/ImportPage.cpp b/launcher/ui/pages/modplatform/ImportPage.cpp index 30196aad..8250193a 100644 --- a/launcher/ui/pages/modplatform/ImportPage.cpp +++ b/launcher/ui/pages/modplatform/ImportPage.cpp @@ -35,12 +35,20 @@ */ #include "ImportPage.h" + +#include "ui/dialogs/ProgressDialog.h" #include "ui_ImportPage.h" #include <QFileDialog> #include <QValidator> +#include <utility> #include "ui/dialogs/NewInstanceDialog.h" +#include "ui/dialogs/CustomMessageBox.h" + +#include "modplatform/flame/FlameAPI.h" + +#include "Json.h" #include "InstanceImportTask.h" @@ -98,16 +106,13 @@ void ImportPage::openedImpl() void ImportPage::updateState() { - if(!isOpened) - { + if (!isOpened) { return; } - if(ui->modpackEdit->hasAcceptableInput()) - { + if (ui->modpackEdit->hasAcceptableInput()) { QString input = ui->modpackEdit->text(); auto url = QUrl::fromUserInput(input); - if(url.isLocalFile()) - { + if (url.isLocalFile()) { // FIXME: actually do some validation of what's inside here... this is fake AF QFileInfo fi(input); @@ -116,28 +121,76 @@ void ImportPage::updateState() // mrpack is a modrinth pack bool isMRPack = fi.suffix() == "mrpack"; - if(fi.exists() && (isZip || isMRPack)) - { + if (fi.exists() && (isZip || isMRPack)) { QFileInfo fi(url.fileName()); - dialog->setSuggestedPack(fi.completeBaseName(), new InstanceImportTask(url,this)); + auto extra_info = QMap(m_extra_info); + qDebug() << "Pack Extra Info" << extra_info << m_extra_info; + dialog->setSuggestedPack(fi.completeBaseName(), new InstanceImportTask(url, this, std::move(extra_info))); dialog->setSuggestedIcon("default"); } - } - else - { - if(input.endsWith("?client=y")) { + } else if (url.scheme() == "curseforge") { + // need to find the download link for the modpack + // format of url curseforge://install?addonId=IDHERE&fileId=IDHERE + QUrlQuery query(url); + auto addonId = query.allQueryItemValues("addonId")[0]; + auto fileId = query.allQueryItemValues("fileId")[0]; + auto array = std::make_shared<QByteArray>(); + + auto api = FlameAPI(); + auto job = api.getFile(addonId, fileId, array); + + connect(job.get(), &NetJob::failed, this, + [this](QString reason) { CustomMessageBox::selectable(this, tr("Error"), reason, QMessageBox::Critical)->show(); }); + connect(job.get(), &NetJob::succeeded, this, [this, array, addonId, fileId] { + qDebug() << "Returned CFURL Json:\n" << array->toStdString().c_str(); + auto doc = Json::requireDocument(*array); + auto data = Json::ensureObject(Json::ensureObject(doc.object()), "data"); + // No way to find out if it's a mod or a modpack before here + // And also we need to check if it ends with .zip, instead of any better way + auto fileName = Json::ensureString(data, "fileName"); + if (fileName.endsWith(".zip")) { + // Have to use ensureString then use QUrl to get proper url encoding + auto dl_url = QUrl(Json::ensureString(data, "downloadUrl", "", "downloadUrl")); + if (!dl_url.isValid()) { + CustomMessageBox::selectable( + this, tr("Error"), + tr("The modpack %1 is blocked for third-parties! Please download it manually.").arg(fileName), + QMessageBox::Critical) + ->show(); + return; + } + + QFileInfo dl_file(dl_url.fileName()); + QString pack_name = Json::ensureString(data, "displayName", dl_file.completeBaseName(), "displayName"); + + QMap<QString, QString> extra_info; + extra_info.insert("pack_id", addonId); + extra_info.insert("pack_version_id", fileId); + + dialog->setSuggestedPack(pack_name, new InstanceImportTask(dl_url, this, std::move(extra_info))); + dialog->setSuggestedIcon("default"); + + } else { + CustomMessageBox::selectable(this, tr("Error"), tr("This url isn't a valid modpack !"), QMessageBox::Critical)->show(); + } + }); + ProgressDialog dlUrlDialod(this); + dlUrlDialod.setSkipButton(true, tr("Abort")); + dlUrlDialod.execWithTask(job.get()); + return; + } else { + if (input.endsWith("?client=y")) { input.chop(9); input.append("/file"); url = QUrl::fromUserInput(input); } // hook, line and sinker. QFileInfo fi(url.fileName()); - dialog->setSuggestedPack(fi.completeBaseName(), new InstanceImportTask(url,this)); + auto extra_info = QMap(m_extra_info); + dialog->setSuggestedPack(fi.completeBaseName(), new InstanceImportTask(url, this, std::move(extra_info))); dialog->setSuggestedIcon("default"); } - } - else - { + } else { dialog->setSuggestedPack(); } } @@ -148,6 +201,11 @@ void ImportPage::setUrl(const QString& url) updateState(); } +void ImportPage::setExtraInfo(const QMap<QString, QString>& extra_info) { + m_extra_info = extra_info; + updateState(); +} + void ImportPage::on_modpackBtn_clicked() { auto filter = QMimeDatabase().mimeTypeForName("application/zip").filterString(); diff --git a/launcher/ui/pages/modplatform/ImportPage.h b/launcher/ui/pages/modplatform/ImportPage.h index c2acb92d..54640752 100644 --- a/launcher/ui/pages/modplatform/ImportPage.h +++ b/launcher/ui/pages/modplatform/ImportPage.h @@ -76,7 +76,7 @@ public: void setUrl(const QString & url); void openedImpl() override; - + void setExtraInfo(const QMap<QString, QString>& extra_info); private slots: void on_modpackBtn_clicked(); void updateState(); @@ -87,5 +87,6 @@ private: private: Ui::ImportPage *ui = nullptr; NewInstanceDialog* dialog = nullptr; + QMap<QString, QString> m_extra_info = {}; }; diff --git a/launcher/ui/pages/modplatform/ImportPage.ui b/launcher/ui/pages/modplatform/ImportPage.ui index 3583cf90..9a9736b8 100644 --- a/launcher/ui/pages/modplatform/ImportPage.ui +++ b/launcher/ui/pages/modplatform/ImportPage.ui @@ -40,7 +40,7 @@ <item> <widget class="QLabel" name="label_5"> <property name="text"> - <string>- CurseForge modpacks (ZIP)</string> + <string>- CurseForge modpacks (ZIP / curseforge:// URL)</string> </property> <property name="alignment"> <set>Qt::AlignCenter</set> |