diff options
| -rw-r--r-- | launcher/CMakeLists.txt | 6 | ||||
| -rw-r--r-- | launcher/LaunchController.cpp | 37 | ||||
| -rw-r--r-- | launcher/MainWindow.cpp | 42 | ||||
| -rw-r--r-- | launcher/dialogs/ProfileSetupDialog.cpp | 248 | ||||
| -rw-r--r-- | launcher/dialogs/ProfileSetupDialog.h | 88 | ||||
| -rw-r--r-- | launcher/dialogs/ProfileSetupDialog.ui | 74 | ||||
| -rw-r--r-- | launcher/minecraft/auth/AccountData.cpp | 45 | ||||
| -rw-r--r-- | launcher/minecraft/auth/AccountData.h | 7 | ||||
| -rw-r--r-- | launcher/minecraft/auth/AccountList.cpp | 38 | ||||
| -rw-r--r-- | launcher/minecraft/auth/AccountList.h | 2 | ||||
| -rw-r--r-- | launcher/minecraft/auth/AuthSession.h | 1 | ||||
| -rw-r--r-- | launcher/minecraft/auth/MinecraftAccount.cpp | 17 | ||||
| -rw-r--r-- | launcher/minecraft/auth/flows/AuthContext.cpp | 343 | ||||
| -rw-r--r-- | launcher/minecraft/auth/flows/AuthContext.h | 6 | ||||
| -rw-r--r-- | launcher/minecraft/auth/flows/Parsers.cpp | 315 | ||||
| -rw-r--r-- | launcher/minecraft/auth/flows/Parsers.h | 19 | ||||
| -rw-r--r-- | launcher/pages/global/AccountListPage.cpp | 8 |
17 files changed, 956 insertions, 340 deletions
diff --git a/launcher/CMakeLists.txt b/launcher/CMakeLists.txt index eba8f8a1..0aeadd51 100644 --- a/launcher/CMakeLists.txt +++ b/launcher/CMakeLists.txt @@ -228,6 +228,9 @@ set(MINECRAFT_SOURCES minecraft/auth/flows/Yggdrasil.h minecraft/auth/flows/Yggdrasil.cpp + minecraft/auth/flows/Parsers.h + minecraft/auth/flows/Parsers.cpp + minecraft/gameoptions/GameOptions.h minecraft/gameoptions/GameOptions.cpp @@ -732,6 +735,8 @@ SET(LAUNCHER_SOURCES dialogs/AboutDialog.h dialogs/ProfileSelectDialog.cpp dialogs/ProfileSelectDialog.h + dialogs/ProfileSetupDialog.cpp + dialogs/ProfileSetupDialog.h dialogs/CopyInstanceDialog.cpp dialogs/CopyInstanceDialog.h dialogs/CustomMessageBox.cpp @@ -859,6 +864,7 @@ SET(LAUNCHER_UIS dialogs/ProgressDialog.ui dialogs/IconPickerDialog.ui dialogs/ProfileSelectDialog.ui + dialogs/ProfileSetupDialog.ui dialogs/EditAccountDialog.ui dialogs/ExportInstanceDialog.ui dialogs/LoginDialog.ui diff --git a/launcher/LaunchController.cpp b/launcher/LaunchController.cpp index 1c1e41e6..9edccaf2 100644 --- a/launcher/LaunchController.cpp +++ b/launcher/LaunchController.cpp @@ -18,6 +18,7 @@ #include <QHostInfo> #include <QList> #include <QHostAddress> +#include "dialogs/ProfileSetupDialog.h" LaunchController::LaunchController(QObject *parent) : Task(parent) { @@ -79,7 +80,7 @@ void LaunchController::decideAccount() // If the user said to use the account as default, do that. if (selectDialog.useAsGlobalDefault() && m_accountToUse) { - accounts->setActiveAccount(m_accountToUse->profileId()); + accounts->setActiveAccount(m_accountToUse); } } } @@ -179,10 +180,40 @@ void LaunchController::login() { } break; } + case AuthSession::RequiresProfileSetup: { + auto entitlement = m_accountToUse->accountData()->minecraftEntitlement; + QString errorString; + if(!entitlement.canPlayMinecraft) { + errorString = tr("The account does not own Minecraft. You need to purchase the game first to play it."); + QMessageBox::warning( + nullptr, + tr("Missing Minecraft profile"), + errorString, + QMessageBox::StandardButton::Ok, + QMessageBox::StandardButton::Ok + ); + tryagain = false; + emitFailed(errorString); + return; + } + // Now handle setting up a profile name here... + ProfileSetupDialog dialog(m_accountToUse, m_parentWidget); + if (dialog.exec() == QDialog::Accepted) + { + tryagain = true; + continue; + } + else + { + tryagain = false; + emitFailed(tr("Received undetermined session status during login.")); + return; + } + } case AuthSession::RequiresOAuth: { auto errorString = tr("Microsoft account has expired and needs to be logged into manually again."); QMessageBox::warning( - nullptr, + m_parentWidget, tr("Microsoft Account refresh failed"), errorString, QMessageBox::StandardButton::Ok, @@ -195,7 +226,7 @@ void LaunchController::login() { case AuthSession::GoneOrMigrated: { auto errorString = tr("The account no longer exists on the servers. It may have been migrated, in which case please add the new account you migrated this one to."); QMessageBox::warning( - nullptr, + m_parentWidget, tr("Account gone"), errorString, QMessageBox::StandardButton::Ok, diff --git a/launcher/MainWindow.cpp b/launcher/MainWindow.cpp index 21502894..7df3e717 100644 --- a/launcher/MainWindow.cpp +++ b/launcher/MainWindow.cpp @@ -1030,7 +1030,6 @@ void MainWindow::repopulateAccountsMenu() QString active_profileId = ""; if (active_account != nullptr) { - active_profileId = active_account->profileId(); // this can be called before accountMenuButton exists if (accountMenuButton) { @@ -1053,14 +1052,20 @@ void MainWindow::repopulateAccountsMenu() MinecraftAccountPtr account = accounts->at(i); auto profileLabel = profileInUseFilter(account->profileName(), account->isInUse()); QAction *action = new QAction(profileLabel, this); - action->setData(account->profileId()); + action->setData(i); action->setCheckable(true); - if (active_profileId == account->profileId()) + if (active_account == account) { action->setChecked(true); } - action->setIcon(account->getFace()); + auto face = account->getFace(); + if(!face.isNull()) { + action->setIcon(face); + } + else { + action->setIcon(LAUNCHER->getThemedIcon("noaccount")); + } accountMenu->addAction(action); connect(action, SIGNAL(triggered(bool)), SLOT(changeActiveAccount())); } @@ -1071,8 +1076,8 @@ void MainWindow::repopulateAccountsMenu() QAction *action = new QAction(tr("No Default Account"), this); action->setCheckable(true); action->setIcon(LAUNCHER->getThemedIcon("noaccount")); - action->setData(""); - if (active_profileId.isEmpty()) { + action->setData(-1); + if (active_account == nullptr) { action->setChecked(true); } @@ -1098,20 +1103,19 @@ void MainWindow::updatesAllowedChanged(bool allowed) void MainWindow::changeActiveAccount() { QAction *sAction = (QAction *)sender(); + // Profile's associated Mojang username - // Will need to change when profiles are properly implemented - if (sAction->data().type() != QVariant::Type::String) + if (sAction->data().type() != QVariant::Type::Int) return; QVariant data = sAction->data(); - QString id = ""; - if (!data.isNull()) - { - id = data.toString(); + bool valid = false; + int index = data.toInt(&valid); + if(!valid) { + index = -1; } - - LAUNCHER->accounts()->setActiveAccount(id); - + std::shared_ptr<AccountList> accounts = LAUNCHER->accounts(); + accounts->setActiveAccount(index == -1 ? nullptr : accounts->at(index)); activeAccountChanged(); } @@ -1126,7 +1130,13 @@ void MainWindow::activeAccountChanged() { auto profileLabel = profileInUseFilter(account->profileName(), account->isInUse()); accountMenuButton->setText(profileLabel); - accountMenuButton->setIcon(account->getFace()); + auto face = account->getFace(); + if(face.isNull()) { + accountMenuButton->setIcon(LAUNCHER->getThemedIcon("noaccount")); + } + else { + accountMenuButton->setIcon(face); + } return; } diff --git a/launcher/dialogs/ProfileSetupDialog.cpp b/launcher/dialogs/ProfileSetupDialog.cpp new file mode 100644 index 00000000..e3d7aec2 --- /dev/null +++ b/launcher/dialogs/ProfileSetupDialog.cpp @@ -0,0 +1,248 @@ +/* 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. + */ + +#include "ProfileSetupDialog.h" +#include "ui_ProfileSetupDialog.h" + +#include <QPushButton> +#include <QAction> +#include <QRegExpValidator> +#include <QDebug> + +#include <dialogs/ProgressDialog.h> + +#include <Launcher.h> +#include <minecraft/auth/flows/AuthRequest.h> +#include <minecraft/auth/flows/Parsers.h> + +ProfileSetupDialog::ProfileSetupDialog(MinecraftAccountPtr accountToSetup, QWidget *parent) + : QDialog(parent), m_accountToSetup(accountToSetup), ui(new Ui::ProfileSetupDialog) +{ + ui->setupUi(this); + ui->errorLabel->setVisible(false); + + goodIcon = LAUNCHER->getThemedIcon("status-good"); + yellowIcon = LAUNCHER->getThemedIcon("status-yellow"); + badIcon = LAUNCHER->getThemedIcon("status-bad"); + + QRegExp permittedNames("[a-zA-Z0-9_]{3,16}"); + auto nameEdit = ui->nameEdit; + nameEdit->setValidator(new QRegExpValidator(permittedNames)); + nameEdit->setClearButtonEnabled(true); + validityAction = nameEdit->addAction(yellowIcon, QLineEdit::LeadingPosition); + connect(nameEdit, &QLineEdit::textEdited, this, &ProfileSetupDialog::nameEdited); + + checkStartTimer.setSingleShot(true); + connect(&checkStartTimer, &QTimer::timeout, this, &ProfileSetupDialog::startCheck); + + setNameStatus(NameStatus::NotSet, QString()); +} + +ProfileSetupDialog::~ProfileSetupDialog() +{ + delete ui; +} + +void ProfileSetupDialog::on_buttonBox_accepted() +{ + setupProfile(currentCheck); +} + +void ProfileSetupDialog::on_buttonBox_rejected() +{ + reject(); +} + +void ProfileSetupDialog::setNameStatus(ProfileSetupDialog::NameStatus status, QString errorString = QString()) +{ + nameStatus = status; + auto okButton = ui->buttonBox->button(QDialogButtonBox::Ok); + switch(nameStatus) + { + case NameStatus::Available: { + validityAction->setIcon(goodIcon); + okButton->setEnabled(true); + } + break; + case NameStatus::NotSet: + case NameStatus::Pending: + validityAction->setIcon(yellowIcon); + okButton->setEnabled(false); + break; + case NameStatus::Exists: + case NameStatus::Error: + validityAction->setIcon(badIcon); + okButton->setEnabled(false); + break; + } + if(!errorString.isEmpty()) { + ui->errorLabel->setText(errorString); + ui->errorLabel->setVisible(true); + } + else { + ui->errorLabel->setVisible(false); + } +} + +void ProfileSetupDialog::nameEdited(const QString& name) +{ + if(!ui->nameEdit->hasAcceptableInput()) { + setNameStatus(NameStatus::NotSet, tr("Name is too short - must be between 3 and 16 characters long.")); + return; + } + scheduleCheck(name); +} + +void ProfileSetupDialog::scheduleCheck(const QString& name) { + queuedCheck = name; + setNameStatus(NameStatus::Pending); + checkStartTimer.start(1000); +} + +void ProfileSetupDialog::startCheck() { + if(isChecking) { + return; + } + if(queuedCheck.isNull()) { + return; + } + checkName(queuedCheck); +} + + +void ProfileSetupDialog::checkName(const QString &name) { + if(isChecking) { + return; + } + + currentCheck = name; + isChecking = true; + + auto token = m_accountToSetup->accessToken(); + + auto url = QString("https://api.minecraftservices.com/minecraft/profile/name/%1/available").arg(name); + QNetworkRequest request = QNetworkRequest(url); + request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json"); + request.setRawHeader("Accept", "application/json"); + request.setRawHeader("Authorization", QString("Bearer %1").arg(token).toUtf8()); + + AuthRequest *requestor = new AuthRequest(this); + connect(requestor, &AuthRequest::finished, this, &ProfileSetupDialog::checkFinished); + requestor->get(request); +} + +void ProfileSetupDialog::checkFinished( + QNetworkReply::NetworkError error, + QByteArray data, + QList<QNetworkReply::RawHeaderPair> headers +) { + if(error == QNetworkReply::NoError) { + auto doc = QJsonDocument::fromJson(data); + auto root = doc.object(); + auto statusValue = root.value("status").toString("INVALID"); + if(statusValue == "AVAILABLE") { + setNameStatus(NameStatus::Available); + } + else if (statusValue == "DUPLICATE") { + setNameStatus(NameStatus::Exists, tr("Minecraft profile with name %1 already exists.").arg(currentCheck)); + } + else if (statusValue == "NOT_ALLOWED") { + setNameStatus(NameStatus::Exists, tr("The name %1 is not allowed.").arg(currentCheck)); + } + else { + setNameStatus(NameStatus::Error, tr("Unhandled profile name status: %1").arg(statusValue)); + } + } + else { + setNameStatus(NameStatus::Error, tr("Failed to check name availability.")); + } + isChecking = false; +} + +void ProfileSetupDialog::setupProfile(const QString &profileName) { + if(isWorking) { + return; + } + + auto token = m_accountToSetup->accessToken(); + + auto url = QString("https://api.minecraftservices.com/minecraft/profile"); + QNetworkRequest request = QNetworkRequest(url); + request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json"); + request.setRawHeader("Accept", "application/json"); + request.setRawHeader("Authorization", QString("Bearer %1").arg(token).toUtf8()); + + QString payloadTemplate("{\"profileName\":\"%1\"}"); + auto data = payloadTemplate.arg(profileName).toUtf8(); + + AuthRequest *requestor = new AuthRequest(this); + connect(requestor, &AuthRequest::finished, this, &ProfileSetupDialog::setupProfileFinished); + requestor->post(request, data); + isWorking = true; + + auto button = ui->buttonBox->button(QDialogButtonBox::Cancel); + button->setEnabled(false); +} + +namespace { + +struct MojangError{ + static MojangError fromJSON(QByteArray data) { + MojangError out; + out.error = QString::fromUtf8(data); + auto doc = QJsonDocument::fromJson(data, &out.parseError); + auto object = doc.object(); + + out.fullyParsed = true; + out.fullyParsed &= Parsers::getString(object.value("path"), out.path); + out.fullyParsed &= Parsers::getString(object.value("error"), out.error); + out.fullyParsed &= Parsers::getString(object.value("errorMessage"), out.errorMessage); + + return out; + } + + QString rawError; + QJsonParseError parseError; + bool fullyParsed; + + QString path; + QString error; + QString errorMessage; +}; + +} + +void ProfileSetupDialog::setupProfileFinished( + QNetworkReply::NetworkError error, + QByteArray data, + QList<QNetworkReply::RawHeaderPair> headers +) { + isWorking = false; + if(error == QNetworkReply::NoError) { + /* + * data contains the profile in the response + * ... we could parse it and update the account, but let's just return back to the normal login flow instead... + */ + accept(); + } + else { + auto parsedError = MojangError::fromJSON(data); + ui->errorLabel->setVisible(true); + ui->errorLabel->setText(tr("The server returned the following error:") + "\n\n" + parsedError.errorMessage); + qDebug() << parsedError.rawError; + auto button = ui->buttonBox->button(QDialogButtonBox::Cancel); + button->setEnabled(true); + } +} diff --git a/launcher/dialogs/ProfileSetupDialog.h b/launcher/dialogs/ProfileSetupDialog.h new file mode 100644 index 00000000..6f413ebd --- /dev/null +++ b/launcher/dialogs/ProfileSetupDialog.h @@ -0,0 +1,88 @@ +/* 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 + +#include <QDialog> +#include <QIcon> +#include <QTimer> +#include <QNetworkReply> + +#include <memory> +#include <minecraft/auth/MinecraftAccount.h> + +namespace Ui +{ +class ProfileSetupDialog; +} + +class ProfileSetupDialog : public QDialog +{ + Q_OBJECT +public: + + explicit ProfileSetupDialog(MinecraftAccountPtr accountToSetup, QWidget *parent = 0); + ~ProfileSetupDialog(); + + enum class NameStatus + { + NotSet, + Pending, + Available, + Exists, + Error + } nameStatus = NameStatus::NotSet; + +private slots: + void on_buttonBox_accepted(); + void on_buttonBox_rejected(); + + void nameEdited(const QString &name); + void checkFinished( + QNetworkReply::NetworkError error, + QByteArray data, + QList<QNetworkReply::RawHeaderPair> headers + ); + void startCheck(); + + void setupProfileFinished( + QNetworkReply::NetworkError error, + QByteArray data, + QList<QNetworkReply::RawHeaderPair> headers + ); +protected: + void scheduleCheck(const QString &name); + void checkName(const QString &name); + void setNameStatus(NameStatus status, QString errorString); + + void setupProfile(const QString & profileName); + +private: + MinecraftAccountPtr m_accountToSetup; + Ui::ProfileSetupDialog *ui; + QIcon goodIcon; + QIcon yellowIcon; + QIcon badIcon; + QAction * validityAction = nullptr; + + QString queuedCheck; + + bool isChecking = false; + bool isWorking = false; + QString currentCheck; + + QTimer checkStartTimer; +}; + diff --git a/launcher/dialogs/ProfileSetupDialog.ui b/launcher/dialogs/ProfileSetupDialog.ui new file mode 100644 index 00000000..9dbabb4b --- /dev/null +++ b/launcher/dialogs/ProfileSetupDialog.ui @@ -0,0 +1,74 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>ProfileSetupDialog</class> + <widget class="QDialog" name="ProfileSetupDialog"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>615</width> + <height>208</height> + </rect> + </property> + <property name="windowTitle"> + <string>Choose Minecraft name</string> + </property> + <layout class="QGridLayout" name="gridLayout"> + <item row="0" column="0" colspan="2"> + <widget class="QLabel" name="descriptionLabel"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Minimum" vsizetype="Minimum"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text"> + <string>You just need to take one more step to be able to play Minecraft on this account. + +Choose your name carefully:</string> + </property> + <property name="wordWrap"> + <bool>true</bool> + </property> + <property name="buddy"> + <cstring>nameEdit</cstring> + </property> + </widget> + </item> + <item row="2" column="0"> + <widget class="QLineEdit" name="nameEdit"/> + </item> + <item row="4" column="0" colspan="2"> + <widget class="QDialogButtonBox" name="buttonBox"> + <property name="standardButtons"> + <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set> + </property> + </widget> + </item> + <item row="3" column="0"> + <widget class="QLabel" name="errorLabel"> + <property name="enabled"> + <bool>true</bool> + </property> + <property name="text"> + <string notr="true">Errors go here</string> + </property> + <property name="wordWrap"> + <bool>true</bool> + </property> + <property name="openExternalLinks"> + <bool>true</bool> + </property> + <property name="textInteractionFlags"> + <set>Qt::LinksAccessibleByKeyboard|Qt::LinksAccessibleByMouse|Qt::TextBrowserInteraction|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse</set> + </property> + </widget> + </item> + </layout> + </widget> + <tabstops> + <tabstop>nameEdit</tabstop> + </tabstops> + <resources/> + <connections/> +</ui> diff --git a/launcher/minecraft/auth/AccountData.cpp b/launcher/minecraft/auth/AccountData.cpp index 5c6de9df..8aa4e37f 100644 --- a/launcher/minecraft/auth/AccountData.cpp +++ b/launcher/minecraft/auth/AccountData.cpp @@ -207,6 +207,35 @@ MinecraftProfile profileFromJSONV3(const QJsonObject &parent, const char * token return out; } +void entitlementToJSONV3(QJsonObject &parent, MinecraftEntitlement p) { + if(p.validity == Katabasis::Validity::None) { + return; + } + QJsonObject out; + out["ownsMinecraft"] = QJsonValue(p.ownsMinecraft); + out["canPlayMinecraft"] = QJsonValue(p.canPlayMinecraft); + parent["entitlement"] = out; +} + +bool entitlementFromJSONV3(const QJsonObject &parent, MinecraftEntitlement & out) { + auto entitlementObject = parent.value("entitlement").toObject(); + if(entitlementObject.isEmpty()) { + return false; + } + { + auto ownsMinecraftV = entitlementObject.value("ownsMinecraft"); + auto canPlayMinecraftV = entitlementObject.value("canPlayMinecraft"); + if(!ownsMinecraftV.isBool() || !canPlayMinecraftV.isBool()) { + qWarning() << "mandatory attributes are missing or of unexpected type"; + return false; + } + out.canPlayMinecraft = canPlayMinecraftV.toBool(false); + out.ownsMinecraft = ownsMinecraftV.toBool(false); + out.validity = Katabasis::Validity::Assumed; + } + return true; +} + } bool AccountData::resumeStateFromV2(QJsonObject data) { @@ -304,9 +333,15 @@ bool AccountData::resumeStateFromV3(QJsonObject data) { yggdrasilToken = tokenFromJSONV3(data, "ygg"); minecraftProfile = profileFromJSONV3(data, "profile"); + if(!entitlementFromJSONV3(data, minecraftEntitlement)) { + if(minecraftProfile.validity != Katabasis::Validity::None) { + minecraftEntitlement.canPlayMinecraft = true; + minecraftEntitlement.ownsMinecraft = true; + minecraftEntitlement.validity = Katabasis::Validity::Assumed; + } + } validity_ = minecraftProfile.validity; - return true; } @@ -331,6 +366,7 @@ QJsonObject AccountData::saveState() const { tokenToJSONV3(output, yggdrasilToken, "ygg"); profileToJSONV3(output, minecraftProfile, "profile"); + entitlementToJSONV3(output, minecraftEntitlement); return output; } @@ -378,7 +414,12 @@ QString AccountData::profileId() const { } QString AccountData::profileName() const { - return minecraftProfile.name; + if(minecraftProfile.name.size() == 0) { + return QObject::tr("No profile (%1)").arg(accountDisplayString()); + } + else { + return minecraftProfile.name; + } } QString AccountData::accountDisplayString() const { diff --git a/launcher/minecraft/auth/AccountData.h b/launcher/minecraft/auth/AccountData.h index cf58fb76..09cd2c73 100644 --- a/launcher/minecraft/auth/AccountData.h +++ b/launcher/minecraft/auth/AccountData.h @@ -21,6 +21,12 @@ struct Cape { QByteArray data; }; +struct MinecraftEntitlement { + bool ownsMinecraft = false; + bool canPlayMinecraft = false; + Katabasis::Validity validity = Katabasis::Validity::None; +}; + struct MinecraftProfile { QString id; QString name; @@ -69,5 +75,6 @@ struct AccountData { Katabasis::Token yggdrasilToken; MinecraftProfile minecraftProfile; + MinecraftEntitlement minecraftEntitlement; Katabasis::Validity validity_ = Katabasis::Validity::None; }; diff --git a/launcher/minecraft/auth/AccountList.cpp b/launcher/minecraft/auth/AccountList.cpp index a76cac55..4895c39c 100644 --- a/launcher/minecraft/auth/AccountList.cpp +++ b/launcher/minecraft/auth/AccountList.cpp @@ -64,21 +64,18 @@ const MinecraftAccountPtr AccountList::at(int i) const void AccountList::addAccount(const MinecraftAccountPtr account) { - // We only ever want accounts with valid profiles. - // Keeping profile-less accounts is pointless and serves no purpose. auto profileId = account->profileId(); - if(!profileId.size()) { - return; + if(profileId.size()) { + // override/replace existing account with the same profileId + auto existingAccount = findAccountByProfileId(profileId); + if(existingAccount != -1) { + m_accounts[existingAccount] = account; + emit dataChanged(index(existingAccount), index(existingAccount, columnCount(QModelIndex()) - 1)); + onListChanged(); + return; + } } - // override/replace existing account with the same profileId - auto existingAccount = findAccountByProfileId(profileId); - if(existingAccount != -1) { - m_accounts[existingAccount] = account; - emit dataChanged(index(existingAccount), index(existingAccount, columnCount(QModelIndex()) - 1)); - onListChanged(); - return; - } // if we don't have this porfileId yet, add the account to the end int row = m_accounts.count(); @@ -112,9 +109,9 @@ MinecraftAccountPtr AccountList::activeAccount() const return m_activeAccount; } -void AccountList::setActiveAccount(const QString &profileId) +void AccountList::setActiveAccount(MinecraftAccountPtr newAccount) { - if (profileId.isEmpty() && m_activeAccount) + if (!newAccount && m_activeAccount) { int idx = 0; auto prevActiveAcc = m_activeAccount; @@ -138,7 +135,7 @@ void AccountList::setActiveAccount(const QString &profileId) int idx = 0; for (MinecraftAccountPtr account : m_accounts) { - if (account->profileId() == profileId) + if (account == newAccount) { newActiveAccount = account; newActiveAccountIdx = idx; @@ -321,7 +318,7 @@ bool AccountList::setData(const QModelIndex &index, const QVariant &value, int r if(value == Qt::Checked) { MinecraftAccountPtr account = at(index.row()); - setActiveAccount(account->profileId()); + setActiveAccount(account); } } @@ -435,11 +432,10 @@ bool AccountList::loadV3(QJsonObject& root) { if (account.get() != nullptr) { auto profileId = account->profileId(); - if(!profileId.size()) { - continue; - } - if(findAccountByProfileId(profileId) != -1) { - continue; + if(profileId.size()) { + if(findAccountByProfileId(profileId) != -1) { + continue; + } } connect(account.get(), &MinecraftAccount::changed, this, &AccountList::accountChanged); m_accounts.append(account); diff --git a/launcher/minecraft/auth/AccountList.h b/launcher/minecraft/auth/AccountList.h index e275eb17..d6d72cd3 100644 --- a/launcher/minecraft/auth/AccountList.h +++ b/launcher/minecraft/auth/AccountList.h @@ -79,7 +79,7 @@ public: bool saveList(); MinecraftAccountPtr activeAccount() const; - void setActiveAccount(const QString &profileId); + void setActiveAccount(MinecraftAccountPtr profileId); bool anyAccountIsValid(); signals: diff --git a/launcher/minecraft/auth/AuthSession.h b/launcher/minecraft/auth/AuthSession.h index f609d5d3..f631a97d 100644 --- a/launcher/minecraft/auth/AuthSession.h +++ b/launcher/minecraft/auth/AuthSession.h @@ -17,6 +17,7 @@ struct AuthSession Undetermined, RequiresOAuth, RequiresPassword, + RequiresProfileSetup, PlayableOffline, PlayableOnline, GoneOrMigrated diff --git a/launcher/minecraft/auth/MinecraftAccount.cpp b/launcher/minecraft/auth/MinecraftAccount.cpp index 2d76f9ac..8e294443 100644 --- a/launcher/minecraft/auth/MinecraftAccount.cpp +++ b/launcher/minecraft/auth/MinecraftAccount.cpp @@ -213,8 +213,21 @@ void MinecraftAccount::authSucceeded() auto session = m_currentTask->getAssignedSession(); if (session) { - session->status = - session->wants_online ? AuthSession::PlayableOnline : AuthSession::PlayableOffline; + /* + session->status = AuthSession::RequiresProfileSetup; + session->auth_server_online = true; + */ + if(data.profileId().size() == 0) { + session->status = AuthSession::RequiresProfileSetup; + } + else { + if(session->wants_online) { + session->status = AuthSession::PlayableOnline; + } + else { + session->status = AuthSession::PlayableOffline; + } + } fillSession(session); session->auth_server_online = true; } diff --git a/launcher/minecraft/auth/flows/AuthContext.cpp b/launcher/minecraft/auth/flows/AuthContext.cpp index 9fb3ec48..17fcc9dc 100644 --- a/launcher/minecraft/auth/flows/AuthContext.cpp +++ b/launcher/minecraft/auth/flows/AuthContext.cpp @@ -22,6 +22,8 @@ #include "Env.h" +#include "Parsers.h" + using OAuth2 = Katabasis::OAuth2; using Activity = Katabasis::Activity; @@ -86,7 +88,7 @@ void AuthContext::initMojang() { } void AuthContext::onMoj |
