diff --git a/launcher/LaunchController.cpp b/launcher/LaunchController.cpp index 60aea9ce..adc6cf12 100644 --- a/launcher/LaunchController.cpp +++ b/launcher/LaunchController.cpp @@ -40,7 +40,6 @@ void LaunchController::login() { // Find an account to use. std::shared_ptr accounts = MMC->accounts(); - AccountPtr account = accounts->activeAccount(); if (accounts->count() <= 0) { // Tell the user they need to log in at least one account in order to play. diff --git a/launcher/MainWindow.cpp b/launcher/MainWindow.cpp index 142f7330..d2593ee8 100644 --- a/launcher/MainWindow.cpp +++ b/launcher/MainWindow.cpp @@ -1050,7 +1050,7 @@ void MainWindow::repopulateAccountsMenu() accountMenu->clear(); std::shared_ptr accounts = MMC->accounts(); - AccountPtr active_account = accounts->activeAccount(); + MinecraftAccountPtr active_account = accounts->activeAccount(); QString active_profileId = ""; if (active_account != nullptr) @@ -1059,7 +1059,7 @@ void MainWindow::repopulateAccountsMenu() // this can be called before accountMenuButton exists if (accountMenuButton) { - auto profileLabel = formatProfile(profile->name, active_account->provider()->displayName(), active_account->isInUse()); + auto profileLabel = profileInUseFilter(active_account->profileName(), active_account->isInUse()); accountMenuButton->setText(profileLabel); } } @@ -1075,21 +1075,14 @@ void MainWindow::repopulateAccountsMenu() // TODO: Nicer way to iterate? for (int i = 0; i < accounts->count(); i++) { - AccountPtr account = accounts->at(i); - for (auto profile : account->profiles()) + MinecraftAccountPtr account = accounts->at(i); + auto profileLabel = profileInUseFilter(account->profileName(), account->isInUse()); + QAction *action = new QAction(profileLabel, this); + action->setData(account->profileId()); + action->setCheckable(true); + if (active_profileId == account->profileId()) { - auto profileLabel = formatProfile(profile.name, account->provider()->displayName(), account->isInUse()); - QAction *action = new QAction(profileLabel, this); - action->setData(account->username()); - action->setCheckable(true); - if (active_username == account->username()) - { - action->setChecked(true); - } - - action->setIcon(SkinUtils::getFaceFromCache(profile.id)); - accountMenu->addAction(action); - connect(action, SIGNAL(triggered(bool)), SLOT(changeActiveAccount())); + action->setChecked(true); } action->setIcon(account->getFace()); @@ -1151,19 +1144,15 @@ void MainWindow::activeAccountChanged() { repopulateAccountsMenu(); - AccountPtr account = MMC->accounts()->activeAccount(); + MinecraftAccountPtr account = MMC->accounts()->activeAccount(); // FIXME: this needs adjustment for MSA if (account != nullptr && account->profileName() != "") { - const AccountProfile *profile = account->currentProfile(); - if (profile != nullptr) - { - auto profileLabel = formatProfile(profile->name, account->provider()->displayName(), account->isInUse()); - accountMenuButton->setIcon(SkinUtils::getFaceFromCache(profile->id)); - accountMenuButton->setText(profileLabel); - return; - } + auto profileLabel = profileInUseFilter(account->profileName(), account->isInUse()); + accountMenuButton->setText(profileLabel); + accountMenuButton->setIcon(account->getFace()); + return; } // Set the icon to the "no account" icon. diff --git a/launcher/MainWindow.h b/launcher/MainWindow.h index 16dd7cbc..67dec8cf 100644 --- a/launcher/MainWindow.h +++ b/launcher/MainWindow.h @@ -22,7 +22,7 @@ #include #include "BaseInstance.h" -#include "minecraft/auth/Account.h" +#include "minecraft/auth/MinecraftAccount.h" #include "net/NetJob.h" #include "updater/GoUpdate.h" diff --git a/launcher/dialogs/LoginDialog.cpp b/launcher/dialogs/LoginDialog.cpp index 562da05f..33013f70 100644 --- a/launcher/dialogs/LoginDialog.cpp +++ b/launcher/dialogs/LoginDialog.cpp @@ -129,7 +129,7 @@ void LoginDialog::onTaskProgress(qint64 current, qint64 total) } // Public interface -AccountPtr LoginDialog::newAccount(QWidget *parent, QString msg) +MinecraftAccountPtr LoginDialog::newAccount(QWidget *parent, QString msg) { LoginDialog dlg(parent); dlg.ui->label->setText(msg); diff --git a/launcher/dialogs/LoginDialog.h b/launcher/dialogs/LoginDialog.h index 50be0f2d..9d5064a5 100644 --- a/launcher/dialogs/LoginDialog.h +++ b/launcher/dialogs/LoginDialog.h @@ -19,7 +19,7 @@ #include #include -#include "minecraft/auth/Account.h" +#include "minecraft/auth/MinecraftAccount.h" namespace Ui { @@ -33,7 +33,7 @@ class LoginDialog : public QDialog public: ~LoginDialog(); - static AccountPtr newAccount(QWidget *parent, QString message); + static MinecraftAccountPtr newAccount(QWidget *parent, QString message); private: explicit LoginDialog(QWidget *parent = 0); @@ -54,7 +54,6 @@ slots: private: Ui::LoginDialog *ui; - AccountPtr m_account; - QMap m_radioButtons; + MinecraftAccountPtr m_account; std::shared_ptr m_loginTask; }; diff --git a/launcher/dialogs/ProfileSelectDialog.cpp b/launcher/dialogs/ProfileSelectDialog.cpp index 3ddcfa80..e2ad73e4 100644 --- a/launcher/dialogs/ProfileSelectDialog.cpp +++ b/launcher/dialogs/ProfileSelectDialog.cpp @@ -48,19 +48,10 @@ ProfileSelectDialog::ProfileSelectDialog(const QString &message, int flags, QWid QList items; for (int i = 0; i < m_accounts->count(); i++) { - AccountPtr account = m_accounts->at(i); - for (auto profile : account->profiles()) - { - auto profileLabel = profile.name; - if(account->isInUse()) - { - profileLabel += tr(" (in use)"); - } - auto item = new QTreeWidgetItem(view); - item->setText(0, profileLabel); - item->setIcon(0, SkinUtils::getFaceFromCache(profile.id)); - item->setData(0, AccountList::PointerRole, QVariant::fromValue(account)); - items.append(item); + MinecraftAccountPtr account = m_accounts->at(i); + QString profileLabel; + if(account->isInUse()) { + profileLabel = tr("%1 (in use)").arg(account->profileName()); } else { profileLabel = account->profileName(); @@ -93,7 +84,7 @@ ProfileSelectDialog::~ProfileSelectDialog() delete ui; } -AccountPtr ProfileSelectDialog::selectedAccount() const +MinecraftAccountPtr ProfileSelectDialog::selectedAccount() const { return m_selected; } @@ -114,7 +105,7 @@ void ProfileSelectDialog::on_buttonBox_accepted() if (selection.size() > 0) { QModelIndex selected = selection.first(); - m_selected = selected.data(AccountList::PointerRole).value(); + m_selected = selected.data(AccountList::PointerRole).value(); } close(); } diff --git a/launcher/dialogs/ProfileSelectDialog.h b/launcher/dialogs/ProfileSelectDialog.h index 1147494f..a4acd9a1 100644 --- a/launcher/dialogs/ProfileSelectDialog.h +++ b/launcher/dialogs/ProfileSelectDialog.h @@ -59,7 +59,7 @@ public: * Gets a pointer to the account that the user selected. * This is null if the user clicked cancel or hasn't clicked OK yet. */ - AccountPtr selectedAccount() const; + MinecraftAccountPtr selectedAccount() const; /*! * Returns true if the user checked the "use as global default" checkbox. @@ -83,7 +83,7 @@ protected: std::shared_ptr m_accounts; //! The account that was selected when the user clicked OK. - AccountPtr m_selected; + MinecraftAccountPtr m_selected; private: Ui::ProfileSelectDialog *ui; diff --git a/launcher/dialogs/SkinUploadDialog.cpp b/launcher/dialogs/SkinUploadDialog.cpp index c58f0bb2..97478f4b 100644 --- a/launcher/dialogs/SkinUploadDialog.cpp +++ b/launcher/dialogs/SkinUploadDialog.cpp @@ -117,7 +117,7 @@ void SkinUploadDialog::on_skinBrowseBtn_clicked() ui->skinPathTextBox->setText(cooked_path); } -SkinUploadDialog::SkinUploadDialog(AccountPtr acct, QWidget *parent) +SkinUploadDialog::SkinUploadDialog(MinecraftAccountPtr acct, QWidget *parent) :QDialog(parent), m_acct(acct), ui(new Ui::SkinUploadDialog) { ui->setupUi(this); diff --git a/launcher/dialogs/SkinUploadDialog.h b/launcher/dialogs/SkinUploadDialog.h index 38bde275..84d17dc6 100644 --- a/launcher/dialogs/SkinUploadDialog.h +++ b/launcher/dialogs/SkinUploadDialog.h @@ -1,7 +1,7 @@ #pragma once #include -#include +#include namespace Ui { @@ -11,7 +11,7 @@ namespace Ui class SkinUploadDialog : public QDialog { Q_OBJECT public: - explicit SkinUploadDialog(AccountPtr acct, QWidget *parent = 0); + explicit SkinUploadDialog(MinecraftAccountPtr acct, QWidget *parent = 0); virtual ~SkinUploadDialog() {}; public slots: @@ -22,7 +22,7 @@ public slots: void on_skinBrowseBtn_clicked(); protected: - AccountPtr m_acct; + MinecraftAccountPtr m_acct; private: Ui::SkinUploadDialog *ui; diff --git a/launcher/minecraft/auth/Account.cpp b/launcher/minecraft/auth/Account.cpp deleted file mode 100644 index d3b99fda..00000000 --- a/launcher/minecraft/auth/Account.cpp +++ /dev/null @@ -1,333 +0,0 @@ -#include "Account.h" -#include "AuthProviders.h" -#include "flows/RefreshTask.h" -#include "flows/AuthenticateTask.h" - -#include -#include -#include -#include -#include -#include - -#include - -#include - -AccountPtr Account::loadFromJson(const QJsonObject &object) -{ - // The JSON object must at least have a username for it to be valid. - if (!object.value("username").isString()) - { - qCritical() << "Can't load Mojang account info from JSON object. Username field is " - "missing or of the wrong type."; - return nullptr; - } - - QString provider = object.value("loginType").toString("dummy"); - QString username = object.value("username").toString(""); - QString clientToken = object.value("clientToken").toString(""); - QString accessToken = object.value("accessToken").toString(""); - - QJsonArray profileArray = object.value("profiles").toArray(); - if (profileArray.size() < 1) - { - qCritical() << "Can't load Mojang account with username \"" << username - << "\". No profiles found."; - return nullptr; - } - - QList profiles; - for (QJsonValue profileVal : profileArray) - { - QJsonObject profileObject = profileVal.toObject(); - QString id = profileObject.value("id").toString(""); - QString name = profileObject.value("name").toString(""); - bool legacy = profileObject.value("legacy").toBool(false); - if (id.isEmpty() || name.isEmpty()) - { - qWarning() << "Unable to load a profile because it was missing an ID or a name."; - continue; - } - profiles.append({id, name, legacy}); - } - - AccountPtr account(new Account()); - if (object.value("user").isObject()) - { - User u; - QJsonObject userStructure = object.value("user").toObject(); - u.id = userStructure.value("id").toString(); - /* - QJsonObject propMap = userStructure.value("properties").toObject(); - for(auto key: propMap.keys()) - { - auto values = propMap.operator[](key).toArray(); - for(auto value: values) - u.properties.insert(key, value.toString()); - } - */ - account->m_user = u; - } - account->m_provider = AuthProviders::lookup(provider); - account->m_username = username; - account->m_clientToken = clientToken; - account->m_accessToken = accessToken; - account->m_profiles = profiles; - - // Get the currently selected profile. - QString currentProfile = object.value("activeProfile").toString(""); - if (!currentProfile.isEmpty()) - account->setCurrentProfile(currentProfile); - - return account; -} - -AccountPtr Account::createFromUsername(const QString &username) -{ - AccountPtr account(new Account()); - account->m_clientToken = QUuid::createUuid().toString().remove(QRegExp("[{}-]")); - account->m_username = username; - return account; -} - -QJsonObject Account::saveToJson() const -{ - QJsonObject json; - json.insert("loginType", m_provider->id()); - json.insert("username", m_username); - json.insert("clientToken", m_clientToken); - json.insert("accessToken", m_accessToken); - - QJsonArray profileArray; - for (AccountProfile profile : m_profiles) - { - QJsonObject profileObj; - profileObj.insert("id", profile.id); - profileObj.insert("name", profile.name); - profileObj.insert("legacy", profile.legacy); - profileArray.append(profileObj); - } - json.insert("profiles", profileArray); - - QJsonObject userStructure; - { - userStructure.insert("id", m_user.id); - /* - QJsonObject userAttrs; - for(auto key: m_user.properties.keys()) - { - auto array = QJsonArray::fromStringList(m_user.properties.values(key)); - userAttrs.insert(key, array); - } - userStructure.insert("properties", userAttrs); - */ - } - json.insert("user", userStructure); - - if (m_currentProfile != -1) - json.insert("activeProfile", currentProfile()->id); - - return json; -} - -bool Account::setProvider(AuthProviderPtr provider) -{ - if (provider == nullptr) - return false; - m_provider = provider; - return true; -} - -bool Account::setCurrentProfile(const QString &profileId) -{ - for (int i = 0; i < m_profiles.length(); i++) - { - if (m_profiles[i].id == profileId) - { - m_currentProfile = i; - return true; - } - } - return false; -} - -const AccountProfile *Account::currentProfile() const -{ - if (m_currentProfile == -1) - return nullptr; - return &m_profiles[m_currentProfile]; -} - -AccountStatus Account::accountStatus() const -{ - if (m_accessToken.isEmpty()) - return NotVerified; - else - return Verified; -} - -std::shared_ptr Account::login(AuthSessionPtr session, QString password) -{ - Q_ASSERT(m_currentTask.get() == nullptr); - - // Handling alternative account types - if (m_provider->dummyAuth()) - { - if (session) - { - session->status = AuthSession::PlayableOnline; - session->auth_server_online = false; - fillSession(session); - } - if (!currentProfile()) - { - // TODO: Proper profile support (idk how) - auto dummyProfile = AccountProfile(); - dummyProfile.name = m_username; - dummyProfile.id = QUuid::createUuid().toString().remove(QRegExp("[{}]")); - m_profiles.append(dummyProfile); - m_currentProfile = 0; - } - return nullptr; - } - - // take care of the true offline status - if (accountStatus() == NotVerified && password.isEmpty()) - { - if (session) - { - session->status = AuthSession::RequiresPassword; - fillSession(session); - } - return nullptr; - } - - if(accountStatus() == Verified && !session->wants_online) - { - session->status = AuthSession::PlayableOffline; - session->auth_server_online = false; - fillSession(session); - return nullptr; - } - else - { - if (password.isEmpty()) - { - m_currentTask.reset(new RefreshTask(this)); - } - else - { - m_currentTask.reset(new AuthenticateTask(this, password)); - } - m_currentTask->assignSession(session); - - connect(m_currentTask.get(), SIGNAL(succeeded()), SLOT(authSucceeded())); - connect(m_currentTask.get(), SIGNAL(failed(QString)), SLOT(authFailed(QString))); - } - return m_currentTask; -} - -void Account::authSucceeded() -{ - auto session = m_currentTask->getAssignedSession(); - if (session) - { - session->status = - session->wants_online ? AuthSession::PlayableOnline : AuthSession::PlayableOffline; - fillSession(session); - session->auth_server_online = true; - } - m_currentTask.reset(); - emit changed(); -} - -void Account::authFailed(QString reason) -{ - auto session = m_currentTask->getAssignedSession(); - // This is emitted when the yggdrasil tasks time out or are cancelled. - // -> we treat the error as no-op - if (m_currentTask->state() == YggdrasilTask::STATE_FAILED_SOFT) - { - if (session) - { - session->status = accountStatus() == Verified ? AuthSession::PlayableOffline - : AuthSession::RequiresPassword; - session->auth_server_online = false; - fillSession(session); - } - } - else - { - m_accessToken = QString(); - emit changed(); - if (session) - { - session->status = AuthSession::RequiresPassword; - session->auth_server_online = true; - fillSession(session); - } - } - m_currentTask.reset(); -} - -void Account::fillSession(AuthSessionPtr session) -{ - // the user name. you have to have an user name - session->username = m_username; - // volatile auth token - session->access_token = m_accessToken; - // the semi-permanent client token - session->client_token = m_clientToken; - if (currentProfile()) - { - // profile name - session->player_name = currentProfile()->name; - // profile ID - session->uuid = currentProfile()->id; - // 'legacy' or 'mojang', depending on account type - session->user_type = currentProfile()->legacy ? "legacy" : "mojang"; - if (!session->access_token.isEmpty()) - { - session->session = "token:" + m_accessToken + ":" + m_profiles[m_currentProfile].id; - } - else - { - session->session = "-"; - } - } - else - { - session->player_name = m_username; - session->session = "-"; - } - session->u = user(); - session->m_accountPtr = shared_from_this(); -} - -void Account::decrementUses() -{ - Usable::decrementUses(); - if(!isInUse()) - { - emit changed(); - qWarning() << "Account" << m_username << "is no longer in use."; - } -} - -void Account::incrementUses() -{ - bool wasInUse = isInUse(); - Usable::incrementUses(); - if(!wasInUse) - { - emit changed(); - qWarning() << "Account" << m_username << "is now in use."; - } -} - -void Account::invalidateClientToken() -{ - m_clientToken = QUuid::createUuid().toString().remove(QRegExp("[{}-]")); - emit changed(); -} diff --git a/launcher/minecraft/auth/Account.h b/launcher/minecraft/auth/Account.h deleted file mode 100644 index c94ac67f..00000000 --- a/launcher/minecraft/auth/Account.h +++ /dev/null @@ -1,168 +0,0 @@ -#pragma once - -#include -#include -#include -#include -#include -#include - -#include -#include "AuthSession.h" -#include "AccountProfile.h" -#include "Usable.h" -#include "providers/BaseAuthProvider.h" - -class Task; -class YggdrasilTask; -class Account; - -typedef std::shared_ptr AccountPtr; -Q_DECLARE_METATYPE(AccountPtr) - -enum AccountStatus -{ - NotVerified, - Verified -}; - -/** - * Object that stores information about a certain Mojang account. - * - * Said information may include things such as that account's username, client token, and access - * token if the user chose to stay logged in. - */ -class MojangAccount : - public QObject, - public Usable, - public std::enable_shared_from_this -{ - Q_OBJECT -public: /* construction */ - //! Do not copy accounts. ever. - explicit Account(const Account &other, QObject *parent) = delete; - - //! Default constructor - explicit Account(QObject *parent = 0) : QObject(parent) {}; - - //! Creates an empty account for the specified user name. - static AccountPtr createFromUsername(const QString &username); - - //! Loads a Account from the given JSON object. - static AccountPtr loadFromJson(const QJsonObject &json); - - //! Saves a Account to a JSON object and returns it. - QJsonObject saveToJson() const; - -public: /* manipulation */ - /** - * Overrides the login type on the account. - */ - bool setProvider(AuthProviderPtr provider); - - /** - * Sets the currently selected profile to the profile with the given ID string. - * If profileId is not in the list of available profiles, the function will simply return - * false. - */ - bool setCurrentProfile(const QString &profileId); - - /** - * Attempt to login. Empty password means we use the token. - * If the attempt fails because we already are performing some task, it returns false. - */ - std::shared_ptr login(AuthSessionPtr session, QString password = QString()); - void invalidateClientToken(); - -public: /* queries */ - const AuthProviderPtr provider() const - { - return m_provider; - } - - const QString &username() const - { - return m_username; - } - - const QString &clientToken() const - { - return m_clientToken; - } - - const QString &accessToken() const - { - return m_accessToken; - } - - const QList &profiles() const - { - return m_profiles; - } - - const User &user() - { - return m_user; - } - - //! Returns the currently selected profile (if none, returns nullptr) - const AccountProfile *currentProfile() const; - - //! Returns whether the account is NotVerified, Verified or Online - AccountStatus accountStatus() const; - -signals: - /** - * This signal is emitted when the account changes - */ - void changed(); - - // TODO: better signalling for the various possible state changes - especially errors - -protected: /* variables */ - // Authentication system used. - // Usable values: "mojang", "dummy", "elyby" - AuthProviderPtr m_provider; - - // Username taken by account. - QString m_username; - - // Used to identify the client - the user can have multiple clients for the same account - // Think: different launchers, all connecting to the same account/profile - QString m_clientToken; - - // Blank if not logged in. - QString m_accessToken; - - // Index of the selected profile within the list of available - // profiles. -1 if nothing is selected. - int m_currentProfile = -1; - - // List of available profiles. - QList m_profiles; - - // the user structure, whatever it is. - User m_user; - - // current task we are executing here - std::shared_ptr m_currentTask; - -protected: /* methods */ - - void incrementUses() override; - void decrementUses() override; - -private -slots: - void authSucceeded(); - void authFailed(QString reason); - -private: - void fillSession(AuthSessionPtr session); - -public: - friend class YggdrasilTask; - friend class AuthenticateTask; - friend class ValidateTask; - friend class RefreshTask; -}; diff --git a/launcher/minecraft/auth/AccountList.cpp b/launcher/minecraft/auth/AccountList.cpp index b76f9026..197ae6ea 100644 --- a/launcher/minecraft/auth/AccountList.cpp +++ b/launcher/minecraft/auth/AccountList.cpp @@ -15,8 +15,6 @@ #include "AccountList.h" #include "AccountData.h" -#include "AccountList.h" -#include "Account.h" #include #include @@ -39,15 +37,14 @@ enum AccountListVersion { AccountList::AccountList(QObject *parent) : QAbstractListModel(parent) { } -AccountPtr AccountList::findAccount(const QString &username) const -{ - for (int i = 0; i < count(); i++) - { - AccountPtr account = at(i); - if (account->username() == username) - return account; +int AccountList::findAccountByProfileId(const QString& profileId) const { + for (int i = 0; i < count(); i++) { + MinecraftAccountPtr account = at(i); + if (account->profileId() == profileId) { + return i; + } } - return nullptr; + return -1; } const MinecraftAccountPtr AccountList::at(int i) const @@ -56,12 +53,6 @@ const MinecraftAccountPtr AccountList::at(int i) const } void AccountList::addAccount(const MinecraftAccountPtr account) -const AccountPtr AccountList::at(int i) const -{ - return AccountPtr(m_accounts.at(i)); -} - -void AccountList::addAccount(const AccountPtr account) { // We only ever want accounts with valid profiles. // Keeping profile-less accounts is pointless and serves no purpose. @@ -88,23 +79,6 @@ void AccountList::addAccount(const AccountPtr account) onListChanged(); } -void AccountList::removeAccount(const QString &username) -{ - int idx = 0; - for (auto account : m_accounts) - { - if (account->username() == username) - { - beginRemoveRows(QModelIndex(), idx, idx); - m_accounts.removeOne(account); - endRemoveRows(); - return; - } - idx++; - } - onListChanged(); -} - void AccountList::removeAccount(QModelIndex index) { int row = index.row(); @@ -123,7 +97,7 @@ void AccountList::removeAccount(QModelIndex index) } } -AccountPtr AccountList::activeAccount() const +MinecraftAccountPtr AccountList::activeAccount() const { return m_activeAccount; } @@ -135,7 +109,7 @@ void AccountList::setActiveAccount(const QString &profileId) int idx = 0; auto prevActiveAcc = m_activeAccount; m_activeAccount = nullptr; - for (AccountPtr account : m_accounts) + for (MinecraftAccountPtr account : m_accounts) { if (account == prevActiveAcc) { @@ -152,7 +126,7 @@ void AccountList::setActiveAccount(const QString &profileId) auto newActiveAccount = m_activeAccount; int newActiveAccountIdx = -1; int idx = 0; - for (AccountPtr account : m_accounts) + for (MinecraftAccountPtr account : m_accounts) { if (account->profileId() == profileId) { @@ -211,15 +185,7 @@ QVariant AccountList::data(const QModelIndex &index, int role) const if (index.row() > count()) return QVariant(); - AccountPtr account = at(index.row()); - - switch (role) - { - case Qt::DisplayRole: - switch (index.column()) - { - case NameColumn: - return account->username(); + MinecraftAccountPtr account = at(index.row()); switch (role) { @@ -234,28 +200,7 @@ QVariant AccountList::data(const QModelIndex &index, int role) const typeStr[0] = typeStr[0].toUpper(); return typeStr; } - case TypeColumn: - return account->provider()->displayName(); - default: - return QVariant(); - } - - case Qt::ToolTipRole: - return account->username(); - - case PointerRole: - return qVariantFromValue(account); - - case Qt::CheckStateRole: - switch (index.column()) - { - case ActiveColumn: - return account == m_activeAccount ? Qt::Checked : Qt::Unchecked; - } - - default: - return QVariant(); case ProfileNameColumn: { return account->profileName(); } @@ -301,9 +246,6 @@ QVariant AccountList::headerData(int section, Qt::Orientation orientation, int r case Qt::DisplayRole: switch (section) { - case ActiveColumn: - return tr("Active?"); - case NameColumn: return tr("Account"); case TypeColumn: @@ -312,10 +254,6 @@ QVariant AccountList::headerData(int section, Qt::Orientation orientation, int r return tr("Can Migrate?"); case ProfileNameColumn: return tr("Profile"); - - case TypeColumn: - return tr("Account type"); - default: return QVariant(); } @@ -372,8 +310,8 @@ bool AccountList::setData(const QModelIndex &index, const QVariant &value, int r { if(value == Qt::Checked) { - AccountPtr account = this->at(index.row()); - this->setActiveAccount(account->username()); + MinecraftAccountPtr account = at(index.row()); + setActiveAccount(account->profileId()); } } @@ -381,19 +319,9 @@ bool AccountList::setData(const QModelIndex &index, const QVariant &value, int r return true; } -void AccountList::updateListData(QList versions) +bool AccountList::loadList() { - beginResetModel(); - m_accounts = versions; - endResetModel(); -} - -bool AccountList::loadList(const QString &filePath) -{ - QString path = filePath; - if (path.isEmpty()) - path = m_listFilePath; - if (path.isEmpty()) + if (m_listFilePath.isEmpty()) { qCritical() << "Can't load Mojang account list. No file path given and no default set."; return false; @@ -493,11 +421,7 @@ bool AccountList::loadV3(QJsonObject& root) { for (QJsonValue accountVal : accounts) { QJsonObject accountObj = accountVal.toObject(); - AccountPtr account = Account::loadFromJson(accountObj); - if (account.get() != nullptr) - { - connect(account.get(), SIGNAL(changed()), SLOT(accountChanged())); - m_accounts.append(account); + MinecraftAccountPtr account = MinecraftAccount::loadFromJsonV3(accountObj); if (account.get() != nullptr) { auto profileId = account->profileId(); @@ -518,13 +442,11 @@ bool AccountList::loadV3(QJsonObject& root) { qWarning() << "Failed to load an account."; } } - // Load the active account. - m_activeAccount = findAccount(root.value("activeAccount").toString("")); endResetModel(); return true; } -bool AccountList::saveList(const QString &filePath) +bool AccountList::saveList() { if (m_listFilePath.isEmpty()) { @@ -555,7 +477,7 @@ bool AccountList::saveList(const QString &filePath) // Build a list of accounts. qDebug() << "Building account array."; QJsonArray accounts; - for (AccountPtr account : m_accounts) + for (MinecraftAccountPtr account : m_accounts) { QJsonObject accountObj = account->saveToJson(); if(m_activeAccount == account) { @@ -567,12 +489,6 @@ bool AccountList::saveList(const QString &filePath) // Insert the account list into the root object. root.insert("accounts", accounts); - if(m_activeAccount) - { - // Save the active account. - root.insert("activeAccount", m_activeAccount->username()); - } - // Create a JSON document object to convert our JSON to bytes. QJsonDocument doc(root); diff --git a/launcher/minecraft/auth/AccountList.h b/launcher/minecraft/auth/AccountList.h deleted file mode 100644 index 0e3ff722..00000000 --- a/launcher/minecraft/auth/AccountList.h +++ /dev/null @@ -1,212 +0,0 @@ -/* 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 "MinecraftAccount.h" - -#include -#include -#include -#include - -/*! - * List of available Mojang accounts. - * This should be loaded in the background by MultiMC on startup. - */ -class AccountList : public QAbstractListModel -{ - Q_OBJECT -public: - enum ModelRoles - { - PointerRole = 0x34B1CB48 - }; - - enum VListColumns - { - // TODO: Add icon column. - NameColumn = 0, - ProfileNameColumn, - MigrationColumn, - TypeColumn, - - NUM_COLUMNS - }; - - explicit AccountList(QObject *parent = 0); - - //! Gets the account at the given index. - virtual const AccountPtr at(int i) const; - - //! Returns the number of accounts in the list. - virtual int count() const; - - //////// List Model Functions //////// - virtual QVariant data(const QModelIndex &index, int role) const; - virtual QVariant headerData(int section, Qt::Orientation orientation, int role) const; - virtual int rowCount(const QModelIndex &parent) const; - virtual int columnCount(const QModelIndex &parent) const; - virtual Qt::ItemFlags flags(const QModelIndex &index) const; - virtual bool setData(const QModelIndex &index, const QVariant &value, int role); - - /*! - * Adds a the given Mojang account to the account list. - */ - virtual void addAccount(const AccountPtr account); - - /*! - * Removes the mojang account with the given username from the account list. - */ - virtual void removeAccount(const QString &username); - - /*! - * Removes the account at the given QModelIndex. - */ - virtual void removeAccount(QModelIndex index); - - /*! - * \brief Finds an account by its username. - * \param The username of the account to find. - * \return A const pointer to the account with the given username. NULL if - * one doesn't exist. - */ - virtual AccountPtr findAccount(const QString &username) const; - - /*! - * Sets the default path to save the list file to. - * If autosave is true, this list will automatically save to the given path whenever it changes. - * THIS FUNCTION DOES NOT LOAD THE LIST. If you set autosave, be sure to call loadList() immediately - * after calling this function to ensure an autosaved change doesn't overwrite the list you intended - * to load. - */ - virtual void setListFilePath(QString path, bool autosave = false); - - /*! - * \brief Loads the account list from the given file path. - * If the given file is an empty string (default), will load from the default account list file. - * \return True if successful, otherwise false. - */ - virtual bool loadList(const QString &file = ""); - - /*! - * \brief Saves the account list to the given file. - * If the given file is an empty string (default), will save from the default account list file. - * \return True if successful, otherwise false. - */ - virtual bool saveList(const QString &file = ""); - - /*! - * \brief Gets a pointer to the account that the user has selected as their "active" account. - * Which account is active can be overridden on a per-instance basis, but this will return the one that - * is set as active globally. - * \return The currently active Account. If there isn't an active account, returns a null pointer. - */ - virtual AccountPtr activeAccount() const; - - /*! - * Sets the given account as the current active account. - * If the username given is an empty string, sets the active account to nothing. - */ - virtual void setActiveAccount(const QString &username); - - /*! - * Returns true if any of the account is at least Validated - */ - bool anyAccountIsValid(); - -signals: - /*! - * Signal emitted to indicate that the account list has changed. - * This will also fire if the value of an element in the list changes (will be implemented - * later). - */ - void listChanged(); - - /*! - * Signal emitted to indicate that the active account has changed. - */ - void activeAccountChanged(); - -public -slots: -======= - void setListFilePath(QString path, bool autosave = false); - - bool loadList(); - bool loadV2(QJsonObject &root); - bool loadV3(QJsonObject &root); - bool saveList(); - - MinecraftAccountPtr activeAccount() const; - void setActiveAccount(const QString &profileId); - bool anyAccountIsValid(); - -signals: - void listChanged(); - void activeAccountChanged(); - -public slots: ->>>>>>> e2355eb276bf355ca4acf526a0f3cc390aa88f8b - /** - * This is called when one of the accounts changes and the list needs to be updated - */ - void accountChanged(); - -protected: - /*! - * Called whenever the list changes. - * This emits the listChanged() signal and autosaves the list (if autosave is enabled). - */ - void onListChanged(); - - /*! - * Called whenever the active account changes. - * Emits the activeAccountChanged() signal and autosaves the list if enabled. - */ - void onActiveChanged(); - - QList m_accounts; - - /*! - * Account that is currently active. - */ - AccountPtr m_activeAccount; - - //! Path to the account list file. Empty string if there isn't one. - QString m_listFilePath; - - /*! - * If true, the account list will automatically save to the account list path when it changes. - * Ignored if m_listFilePath is blank. - */ - bool m_autosave = false; - -protected -slots: - /*! - * Updates this list with the given list of accounts. - * This is done by copying each account in the given list and inserting it - * into this one. - * We need to do this so that we can set the parents of the accounts are set to this - * account list. This can't be done in the load task, because the accounts the load - * task creates are on the load task's thread and Qt won't allow their parents - * to be set to something created on another thread. - * To get around that problem, we invoke this method on the GUI thread, which - * then copies the accounts and sets their parents correctly. - * \param accounts List of accounts whose parents should be set. - */ - virtual void updateListData(QList versions); -}; diff --git a/launcher/minecraft/auth/AccountTask.h b/launcher/minecraft/auth/AccountTask.h index ce4f0477..4f3bd52a 100644 --- a/launcher/minecraft/auth/AccountTask.h +++ b/launcher/minecraft/auth/AccountTask.h @@ -22,7 +22,7 @@ #include #include -#include "Account.h" +#include "MinecraftAccount.h" class QNetworkReply; @@ -31,8 +31,8 @@ class AccountTask : public Task friend class AuthContext; Q_OBJECT public: - explicit YggdrasilTask(Account * account, QObject *parent = 0); - virtual ~YggdrasilTask() {}; + explicit AccountTask(AccountData * data, QObject *parent = 0); + virtual ~AccountTask() {}; /** * assign a session to this task. the session will be filled with required infomration @@ -102,8 +102,7 @@ protected slots: protected: // FIXME: segfault disaster waiting to happen - Account *m_account = nullptr; - QNetworkReply *m_netReply = nullptr; + AccountData *m_data = nullptr; std::shared_ptr m_error; AuthSessionPtr m_session; }; diff --git a/launcher/minecraft/auth/AuthSession.h b/launcher/minecraft/auth/AuthSession.h index 388675c3..f609d5d3 100644 --- a/launcher/minecraft/auth/AuthSession.h +++ b/launcher/minecraft/auth/AuthSession.h @@ -40,7 +40,7 @@ struct AuthSession bool auth_server_online = false; // Did the user request online mode? bool wants_online = true; - std::shared_ptr m_accountPtr; + std::shared_ptr m_accountPtr; }; typedef std::shared_ptr AuthSessionPtr; diff --git a/launcher/minecraft/auth/MinecraftAccount.h b/launcher/minecraft/auth/MinecraftAccount.h index 3def37fd..e4579a20 100644 --- a/launcher/minecraft/auth/MinecraftAccount.h +++ b/launcher/minecraft/auth/MinecraftAccount.h @@ -50,37 +50,27 @@ enum AccountStatus class MinecraftAccount : public QObject, public Usable, - public std::enable_shared_from_this + public std::enable_shared_from_this { Q_OBJECT public: /* construction */ //! Do not copy accounts. ever. - explicit Account(const Account &other, QObject *parent) = delete; + explicit MinecraftAccount(const MinecraftAccount &other, QObject *parent) = delete; //! Default constructor - explicit Account(QObject *parent = 0) : QObject(parent) {}; + explicit MinecraftAccount(QObject *parent = 0) : QObject(parent) {}; - //! Creates an empty account for the specified user name. - static AccountPtr createFromUsername(const QString &username); + static MinecraftAccountPtr createFromUsername(const QString &username); - //! Loads a Account from the given JSON object. - static AccountPtr loadFromJson(const QJsonObject &json); + static MinecraftAccountPtr createBlankMSA(); - //! Saves a Account to a JSON object and returns it. + static MinecraftAccountPtr loadFromJsonV2(const QJsonObject &json); + static MinecraftAccountPtr loadFromJsonV3(const QJsonObject &json); + + //! Saves a MinecraftAccount to a JSON object and returns it. QJsonObject saveToJson() const; public: /* manipulation */ - /** - * Overrides the login type on the account. - */ - bool setProvider(AuthProviderPtr provider); - - /** - * Sets the currently selected profile to the profile with the given ID string. - * If profileId is not in the list of available profiles, the function will simply return - * false. - */ - bool setCurrentProfile(const QString &profileId); /** * Attempt to login. Empty password means we use the token. @@ -93,28 +83,26 @@ public: /* manipulation */ std::shared_ptr refresh(AuthSessionPtr session); public: /* queries */ - const AuthProviderPtr provider() const - { - return m_provider; + QString accountDisplayString() const { + return data.accountDisplayString(); } - const QString &username() const - { - return m_username; + QString mojangUserName() const { + return data.userName(); + } + + QString accessToken() const { + return data.accessToken(); + } + + QString profileId() const { + return data.profileId(); } QString profileName() const { return data.profileName(); } - bool canMigrate() const { - return data.canMigrateToMSA; - } - - bool isMSA() const { - return data.type == AccountType::MSA; - } - QString typeString() const { switch(data.type) { case AccountType::Mojang: { @@ -152,29 +140,7 @@ signals: // TODO: better signalling for the various possible state changes - especially errors protected: /* variables */ - // Authentication system used. - // Usable values: "mojang", "dummy", "elyby" - AuthProviderPtr m_provider; - - // Username taken by account. - QString m_username; - - // Used to identify the client - the user can have multiple clients for the same account - // Think: different launchers, all connecting to the same account/profile - QString m_clientToken; - - // Blank if not logged in. - QString m_accessToken; - - // Index of the selected profile within the list of available - // profiles. -1 if nothing is selected. - int m_currentProfile = -1; - - // List of available profiles. - QList m_profiles; - - // the user structure, whatever it is. - User m_user; + AccountData data; // current task we are executing here std::shared_ptr m_currentTask; diff --git a/launcher/minecraft/launch/ClaimAccount.h b/launcher/minecraft/launch/ClaimAccount.h index 7dd2fdaa..cb4de23f 100644 --- a/launcher/minecraft/launch/ClaimAccount.h +++ b/launcher/minecraft/launch/ClaimAccount.h @@ -16,7 +16,7 @@ #pragma once #include -#include +#include class ClaimAccount: public LaunchStep { @@ -33,5 +33,5 @@ public: } private: std::unique_ptr lock; - AccountPtr m_account; + MinecraftAccountPtr m_account; }; diff --git a/launcher/pages/global/AccountListPage.cpp b/launcher/pages/global/AccountListPage.cpp index e4bf4728..74537712 100644 --- a/launcher/pages/global/AccountListPage.cpp +++ b/launcher/pages/global/AccountListPage.cpp @@ -59,8 +59,6 @@ AccountListPage::AccountListPage(QWidget *parent) ui->listView->setSelectionMode(QAbstractItemView::SingleSelection); // Expand the account column - ui->listView->header()->setSectionResizeMode(1, QHeaderView::Stretch); - ui->listView->header()->setSectionResizeMode(2, QHeaderView::Stretch); QItemSelectionModel *selectionModel = ui->listView->selectionModel(); @@ -188,9 +186,8 @@ void AccountListPage::on_actionSetDefault_triggered() if (selection.size() > 0) { QModelIndex selected = selection.first(); - AccountPtr account = - selected.data(AccountList::PointerRole).value(); - m_accounts->setActiveAccount(account->username()); + MinecraftAccountPtr account = selected.data(AccountList::PointerRole).value(); + m_accounts->setActiveAccount(account->profileId()); } } @@ -210,10 +207,6 @@ void AccountListPage::updateButtonStates() ui->actionDeleteSkin->setEnabled(selection.size() > 0); ui->actionRefresh->setEnabled(selection.size() > 0); - bool enableSkins = selection.size() > 0 && selection.first().data(AccountList::PointerRole).value()->provider()->canChangeSkin(); - ui->actionUploadSkin->setEnabled(enableSkins); - ui->actionDeleteSkin->setEnabled(enableSkins); - if(m_accounts->activeAccount().get() == nullptr) { ui->actionNoDefault->setEnabled(false); ui->actionNoDefault->setChecked(true); @@ -225,39 +218,13 @@ void AccountListPage::updateButtonStates() } -void AccountListPage::addAccount(const QString &errMsg) -{ - // TODO: The login dialog isn't quite done yet - AccountPtr account = LoginDialog::newAccount(this, errMsg); - - if (account != nullptr) - { - m_accounts->addAccount(account); - if (m_accounts->count() == 1) - m_accounts->setActiveAccount(account->username()); - - // Grab associated player skins - auto job = new NetJob("Player skins: " + account->username()); - - for (AccountProfile profile : account->profiles()) - { - auto meta = Env::getInstance().metacache()->resolveEntry("skins", profile.id + ".png"); - auto action = Net::Download::makeCached(account->provider()->resolveSkinUrl(profile), meta); - job->addNetAction(action); - meta->setStale(true); - } - - job->start(); - } -} - void AccountListPage::on_actionUploadSkin_triggered() { QModelIndexList selection = ui->listView->selectionModel()->selectedIndexes(); if (selection.size() > 0) { QModelIndex selected = selection.first(); - AccountPtr account = selected.data(AccountList::PointerRole).value(); + MinecraftAccountPtr account = selected.data(AccountList::PointerRole).value(); SkinUploadDialog dialog(account, this); dialog.exec(); } @@ -271,8 +238,8 @@ void AccountListPage::on_actionDeleteSkin_triggered() QModelIndex selected = selection.first(); AuthSessionPtr session = std::make_shared(); - AccountPtr account = selected.data(AccountList::PointerRole).value(); - auto login = account->login(session); + MinecraftAccountPtr account = selected.data(AccountList::PointerRole).value(); + auto login = account->refresh(session); ProgressDialog prog(this); if (prog.execWithTask((Task*)login.get()) != QDialog::Accepted) { CustomMessageBox::selectable(this, tr("Skin Delete"), tr("Failed to login!"), QMessageBox::Warning)->exec();