Fix conflict again

This commit is contained in:
Sebastian-byte
2021-09-12 20:52:56 -05:00
18 changed files with 83 additions and 970 deletions

View File

@@ -40,7 +40,6 @@ void LaunchController::login() {
// Find an account to use.
std::shared_ptr<AccountList> 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.

View File

@@ -1050,7 +1050,7 @@ void MainWindow::repopulateAccountsMenu()
accountMenu->clear();
std::shared_ptr<AccountList> 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.

View File

@@ -22,7 +22,7 @@
#include <QTimer>
#include "BaseInstance.h"
#include "minecraft/auth/Account.h"
#include "minecraft/auth/MinecraftAccount.h"
#include "net/NetJob.h"
#include "updater/GoUpdate.h"

View File

@@ -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);

View File

@@ -19,7 +19,7 @@
#include <QtWidgets/QRadioButton>
#include <QtCore/QEventLoop>
#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<QString, QRadioButton*> m_radioButtons;
MinecraftAccountPtr m_account;
std::shared_ptr<Task> m_loginTask;
};

View File

@@ -48,19 +48,10 @@ ProfileSelectDialog::ProfileSelectDialog(const QString &message, int flags, QWid
QList <QTreeWidgetItem *> 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<AccountPtr>();
m_selected = selected.data(AccountList::PointerRole).value<MinecraftAccountPtr>();
}
close();
}

View File

@@ -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<AccountList> m_accounts;
//! The account that was selected when the user clicked OK.
AccountPtr m_selected;
MinecraftAccountPtr m_selected;
private:
Ui::ProfileSelectDialog *ui;

View File

@@ -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);

View File

@@ -1,7 +1,7 @@
#pragma once
#include <QDialog>
#include <minecraft/auth/Account.h>
#include <minecraft/auth/MinecraftAccount.h>
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;

View File

@@ -1,333 +0,0 @@
#include "Account.h"
#include "AuthProviders.h"
#include "flows/RefreshTask.h"
#include "flows/AuthenticateTask.h"
#include <QUuid>
#include <QJsonObject>
#include <QJsonArray>
#include <QRegExp>
#include <QStringList>
#include <QJsonDocument>
#include <QDebug>
#include <BuildConfig.h>
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<AccountProfile> 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<YggdrasilTask> 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();
}

View File

@@ -1,168 +0,0 @@
#pragma once
#include <QObject>
#include <QString>
#include <QList>
#include <QJsonObject>
#include <QPair>
#include <QMap>
#include <memory>
#include "AuthSession.h"
#include "AccountProfile.h"
#include "Usable.h"
#include "providers/BaseAuthProvider.h"
class Task;
class YggdrasilTask;
class Account;
typedef std::shared_ptr<Account> 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<Account>
{
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<YggdrasilTask> 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<AccountProfile> &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<AccountProfile> m_profiles;
// the user structure, whatever it is.
User m_user;
// current task we are executing here
std::shared_ptr<YggdrasilTask> 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;
};

View File

@@ -15,8 +15,6 @@
#include "AccountList.h"
#include "AccountData.h"
#include "AccountList.h"
#include "Account.h"
#include <QIODevice>
#include <QFile>
@@ -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<AccountPtr> 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);

View File

@@ -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 <QObject>
#include <QVariant>
#include <QAbstractListModel>
#include <QSharedPointer>
/*!
* 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<AccountPtr> 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<AccountPtr> versions);
};

View File

@@ -22,7 +22,7 @@
#include <QTimer>
#include <qsslerror.h>
#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<Error> m_error;
AuthSessionPtr m_session;
};

View File

@@ -40,7 +40,7 @@ struct AuthSession
bool auth_server_online = false;
// Did the user request online mode?
bool wants_online = true;
std::shared_ptr<Account> m_accountPtr;
std::shared_ptr<MinecraftAccount> m_accountPtr;
};
typedef std::shared_ptr<AuthSession> AuthSessionPtr;

View File

@@ -50,37 +50,27 @@ enum AccountStatus
class MinecraftAccount :
public QObject,
public Usable,
public std::enable_shared_from_this<Account>
public std::enable_shared_from_this<MinecraftAccount>
{
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<AccountTask> 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<AccountProfile> m_profiles;
// the user structure, whatever it is.
User m_user;
AccountData data;
// current task we are executing here
std::shared_ptr<AccountTask> m_currentTask;

View File

@@ -16,7 +16,7 @@
#pragma once
#include <launch/LaunchStep.h>
#include <minecraft/auth/Account.h>
#include <minecraft/auth/MinecraftAccount.h>
class ClaimAccount: public LaunchStep
{
@@ -33,5 +33,5 @@ public:
}
private:
std::unique_ptr<UseLock> lock;
AccountPtr m_account;
MinecraftAccountPtr m_account;
};

View File

@@ -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<AccountPtr>();
m_accounts->setActiveAccount(account->username());
MinecraftAccountPtr account = selected.data(AccountList::PointerRole).value<MinecraftAccountPtr>();
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<AccountPtr>()->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<AccountPtr>();
MinecraftAccountPtr account = selected.data(AccountList::PointerRole).value<MinecraftAccountPtr>();
SkinUploadDialog dialog(account, this);
dialog.exec();
}
@@ -271,8 +238,8 @@ void AccountListPage::on_actionDeleteSkin_triggered()
QModelIndex selected = selection.first();
AuthSessionPtr session = std::make_shared<AuthSession>();
AccountPtr account = selected.data(AccountList::PointerRole).value<AccountPtr>();
auto login = account->login(session);
MinecraftAccountPtr account = selected.data(AccountList::PointerRole).value<MinecraftAccountPtr>();
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();