Properly implement launching and downloading
Also added a system to select an active account to log in with.
This commit is contained in:
parent
23bc195b3c
commit
75e7932607
@ -85,11 +85,6 @@ MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWi
|
|||||||
ui->setupUi(this);
|
ui->setupUi(this);
|
||||||
setWindowTitle(QString("MultiMC %1").arg(MMC->version().toString()));
|
setWindowTitle(QString("MultiMC %1").arg(MMC->version().toString()));
|
||||||
|
|
||||||
// Set the selected instance to null
|
|
||||||
m_selectedInstance = nullptr;
|
|
||||||
// Set active instance to null.
|
|
||||||
m_activeInst = nullptr;
|
|
||||||
|
|
||||||
// OSX magic.
|
// OSX magic.
|
||||||
setUnifiedTitleAndToolBarOnMac(true);
|
setUnifiedTitleAndToolBarOnMac(true);
|
||||||
|
|
||||||
@ -563,7 +558,7 @@ void MainWindow::doLogin(const QString &errorMsg)
|
|||||||
|
|
||||||
// Find an account to use.
|
// Find an account to use.
|
||||||
std::shared_ptr<MojangAccountList> accounts = MMC->accounts();
|
std::shared_ptr<MojangAccountList> accounts = MMC->accounts();
|
||||||
MojangAccountPtr account;
|
MojangAccountPtr account = accounts->activeAccount();
|
||||||
if (accounts->count() <= 0)
|
if (accounts->count() <= 0)
|
||||||
{
|
{
|
||||||
// Tell the user they need to log in at least one account in order to play.
|
// Tell the user they need to log in at least one account in order to play.
|
||||||
@ -577,44 +572,90 @@ void MainWindow::doLogin(const QString &errorMsg)
|
|||||||
// Open the account manager.
|
// Open the account manager.
|
||||||
on_actionManageAccounts_triggered();
|
on_actionManageAccounts_triggered();
|
||||||
}
|
}
|
||||||
return;
|
}
|
||||||
|
else if (account.get() == nullptr)
|
||||||
|
{
|
||||||
|
// Tell the user they need to log in at least one account in order to play.
|
||||||
|
auto reply = CustomMessageBox::selectable(this, tr("No Account Selected"),
|
||||||
|
tr("You don't have an account selected as an active account."
|
||||||
|
"Would you like to open the account manager to select one now?"),
|
||||||
|
QMessageBox::Information, QMessageBox::Yes | QMessageBox::No)->exec();
|
||||||
|
|
||||||
|
if (reply == QMessageBox::Yes)
|
||||||
|
{
|
||||||
|
// Open the account manager.
|
||||||
|
on_actionManageAccounts_triggered();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// TODO: Allow user to select different accounts.
|
|
||||||
// For now, we'll just use the first one in the list until I get arround to implementing that.
|
|
||||||
account = accounts->at(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
// We'll need to validate the access token to make sure the account is still logged in.
|
// We'll need to validate the access token to make sure the account is still logged in.
|
||||||
// TODO: Do that ^
|
// TODO: Do that ^
|
||||||
|
|
||||||
launchInstance(m_selectedInstance, account);
|
prepareLaunch(m_selectedInstance, account);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
void MainWindow::prepareLaunch(BaseInstance* instance, MojangAccountPtr account)
|
||||||
LoginDialog *loginDlg = new LoginDialog(this, errorMsg);
|
|
||||||
if (!m_selectedInstance->lastLaunch())
|
|
||||||
loginDlg->forceOnline();
|
|
||||||
|
|
||||||
loginDlg->exec();
|
|
||||||
if (loginDlg->result() == QDialog::Accepted)
|
|
||||||
{
|
{
|
||||||
if (loginDlg->isOnline())
|
BaseUpdate *updateTask = instance->doUpdate();
|
||||||
|
if (!updateTask)
|
||||||
{
|
{
|
||||||
m_activeInst = m_selectedInstance;
|
launchInstance(instance, account);
|
||||||
doLogin(loginDlg->getUsername(), loginDlg->getPassword());
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
QString user = loginDlg->getUsername();
|
ProgressDialog tDialog(this);
|
||||||
if (user.length() == 0)
|
connect(updateTask, &BaseUpdate::succeeded, [this, instance, account] { launchInstance(instance, account); });
|
||||||
user = QString("Player");
|
connect(updateTask, SIGNAL(failed(QString)), SLOT(onGameUpdateError(QString)));
|
||||||
m_activeLogin = {user, QString("Offline"), user, QString()};
|
tDialog.exec(updateTask);
|
||||||
m_activeInst = m_selectedInstance;
|
delete updateTask;
|
||||||
launchInstance(m_activeInst, m_activeLogin);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QString playerName = account->currentProfile()->name();
|
||||||
|
|
||||||
|
auto job = new NetJob("Player skin: " + playerName);
|
||||||
|
|
||||||
|
auto meta = MMC->metacache()->resolveEntry("skins", playerName + ".png");
|
||||||
|
auto action = CacheDownload::make(
|
||||||
|
QUrl("http://skins.minecraft.net/MinecraftSkins/" + playerName + ".png"),
|
||||||
|
meta);
|
||||||
|
job->addNetAction(action);
|
||||||
|
meta->stale = true;
|
||||||
|
|
||||||
|
job->start();
|
||||||
|
auto filename = MMC->metacache()->resolveEntry("skins", "skins.json")->getFullPath();
|
||||||
|
QFile listFile(filename);
|
||||||
|
|
||||||
|
// Add skin mapping
|
||||||
|
QByteArray data;
|
||||||
|
{
|
||||||
|
if (!listFile.open(QIODevice::ReadWrite))
|
||||||
|
{
|
||||||
|
QLOG_ERROR() << "Failed to open/make skins list JSON";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
data = listFile.readAll();
|
||||||
|
}
|
||||||
|
|
||||||
|
QJsonParseError jsonError;
|
||||||
|
QJsonDocument jsonDoc = QJsonDocument::fromJson(data, &jsonError);
|
||||||
|
QJsonObject root = jsonDoc.object();
|
||||||
|
QJsonObject mappings = root.value("mappings").toObject();
|
||||||
|
QJsonArray usernames = mappings.value(account->username()).toArray();
|
||||||
|
|
||||||
|
if (!usernames.contains(playerName))
|
||||||
|
{
|
||||||
|
usernames.prepend(playerName);
|
||||||
|
mappings[account->username()] = usernames;
|
||||||
|
root["mappings"] = mappings;
|
||||||
|
jsonDoc.setObject(root);
|
||||||
|
|
||||||
|
// QJson hack - shouldn't have to clear the file every time a save happens
|
||||||
|
listFile.resize(0);
|
||||||
|
listFile.write(jsonDoc.toJson());
|
||||||
}
|
}
|
||||||
*/
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::launchInstance(BaseInstance *instance, MojangAccountPtr account)
|
void MainWindow::launchInstance(BaseInstance *instance, MojangAccountPtr account)
|
||||||
@ -652,76 +693,6 @@ void MainWindow::launchInstance(BaseInstance *instance, MojangAccountPtr account
|
|||||||
proc->launch();
|
proc->launch();
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::onLoginComplete()
|
|
||||||
{
|
|
||||||
if (!m_activeInst)
|
|
||||||
return;
|
|
||||||
LoginTask *task = (LoginTask *)QObject::sender();
|
|
||||||
m_activeLogin = task->getResult();
|
|
||||||
|
|
||||||
BaseUpdate *updateTask = m_activeInst->doUpdate();
|
|
||||||
if (!updateTask)
|
|
||||||
{
|
|
||||||
//launchInstance(m_activeInst, m_activeLogin);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
ProgressDialog tDialog(this);
|
|
||||||
connect(updateTask, SIGNAL(succeeded()), SLOT(onGameUpdateComplete()));
|
|
||||||
connect(updateTask, SIGNAL(failed(QString)), SLOT(onGameUpdateError(QString)));
|
|
||||||
tDialog.exec(updateTask);
|
|
||||||
delete updateTask;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto job = new NetJob("Player skin: " + m_activeLogin.player_name);
|
|
||||||
|
|
||||||
auto meta = MMC->metacache()->resolveEntry("skins", m_activeLogin.player_name + ".png");
|
|
||||||
auto action = CacheDownload::make(
|
|
||||||
QUrl("http://skins.minecraft.net/MinecraftSkins/" + m_activeLogin.player_name + ".png"),
|
|
||||||
meta);
|
|
||||||
job->addNetAction(action);
|
|
||||||
meta->stale = true;
|
|
||||||
|
|
||||||
job->start();
|
|
||||||
auto filename = MMC->metacache()->resolveEntry("skins", "skins.json")->getFullPath();
|
|
||||||
QFile listFile(filename);
|
|
||||||
|
|
||||||
// Add skin mapping
|
|
||||||
QByteArray data;
|
|
||||||
{
|
|
||||||
if (!listFile.open(QIODevice::ReadWrite))
|
|
||||||
{
|
|
||||||
QLOG_ERROR() << "Failed to open/make skins list JSON";
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
data = listFile.readAll();
|
|
||||||
}
|
|
||||||
|
|
||||||
QJsonParseError jsonError;
|
|
||||||
QJsonDocument jsonDoc = QJsonDocument::fromJson(data, &jsonError);
|
|
||||||
QJsonObject root = jsonDoc.object();
|
|
||||||
QJsonObject mappings = root.value("mappings").toObject();
|
|
||||||
QJsonArray usernames = mappings.value(m_activeLogin.username).toArray();
|
|
||||||
|
|
||||||
if (!usernames.contains(m_activeLogin.player_name))
|
|
||||||
{
|
|
||||||
usernames.prepend(m_activeLogin.player_name);
|
|
||||||
mappings[m_activeLogin.username] = usernames;
|
|
||||||
root["mappings"] = mappings;
|
|
||||||
jsonDoc.setObject(root);
|
|
||||||
|
|
||||||
// QJson hack - shouldn't have to clear the file every time a save happens
|
|
||||||
listFile.resize(0);
|
|
||||||
listFile.write(jsonDoc.toJson());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void MainWindow::onGameUpdateComplete()
|
|
||||||
{
|
|
||||||
//launchInstance(m_activeInst, m_activeLogin);
|
|
||||||
}
|
|
||||||
|
|
||||||
void MainWindow::onGameUpdateError(QString error)
|
void MainWindow::onGameUpdateError(QString error)
|
||||||
{
|
{
|
||||||
CustomMessageBox::selectable(this, tr("Error updating instance"), error,
|
CustomMessageBox::selectable(this, tr("Error updating instance"), error,
|
||||||
|
@ -113,9 +113,11 @@ slots:
|
|||||||
*/
|
*/
|
||||||
void launchInstance(BaseInstance* instance, MojangAccountPtr account);
|
void launchInstance(BaseInstance* instance, MojangAccountPtr account);
|
||||||
|
|
||||||
void onLoginComplete();
|
/*!
|
||||||
|
* Prepares the given instance for launch with the given account.
|
||||||
|
*/
|
||||||
|
void prepareLaunch(BaseInstance* instance, MojangAccountPtr account);
|
||||||
|
|
||||||
void onGameUpdateComplete();
|
|
||||||
void onGameUpdateError(QString error);
|
void onGameUpdateError(QString error);
|
||||||
|
|
||||||
void taskStart();
|
void taskStart();
|
||||||
@ -160,12 +162,6 @@ private:
|
|||||||
|
|
||||||
BaseInstance *m_selectedInstance;
|
BaseInstance *m_selectedInstance;
|
||||||
|
|
||||||
// A pointer to the instance we are actively doing stuff with.
|
|
||||||
// This is set when the user launches an instance and is used to refer to that
|
|
||||||
// instance throughout the launching process.
|
|
||||||
BaseInstance *m_activeInst;
|
|
||||||
LoginResponse m_activeLogin;
|
|
||||||
|
|
||||||
Task *m_versionLoadTask;
|
Task *m_versionLoadTask;
|
||||||
|
|
||||||
QLabel *m_statusLeft;
|
QLabel *m_statusLeft;
|
||||||
|
@ -34,6 +34,7 @@ AccountListDialog::AccountListDialog(QWidget *parent) :
|
|||||||
ui->setupUi(this);
|
ui->setupUi(this);
|
||||||
|
|
||||||
m_accounts = MMC->accounts();
|
m_accounts = MMC->accounts();
|
||||||
|
// TODO: Make the "Active?" column show checkboxes or radio buttons.
|
||||||
ui->listView->setModel(m_accounts.get());
|
ui->listView->setModel(m_accounts.get());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -63,6 +64,17 @@ void AccountListDialog::on_editAccountBtn_clicked()
|
|||||||
// TODO
|
// TODO
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void AccountListDialog::on_setActiveBtn_clicked()
|
||||||
|
{
|
||||||
|
QModelIndexList selection = ui->listView->selectionModel()->selectedIndexes();
|
||||||
|
if (selection.size() > 0)
|
||||||
|
{
|
||||||
|
QModelIndex selected = selection.first();
|
||||||
|
MojangAccountPtr account = selected.data(MojangAccountList::PointerRole).value<MojangAccountPtr>();
|
||||||
|
m_accounts->setActiveAccount(account->username());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void AccountListDialog::on_closeBtnBox_rejected()
|
void AccountListDialog::on_closeBtnBox_rejected()
|
||||||
{
|
{
|
||||||
close();
|
close();
|
||||||
|
@ -42,6 +42,8 @@ slots:
|
|||||||
|
|
||||||
void on_editAccountBtn_clicked();
|
void on_editAccountBtn_clicked();
|
||||||
|
|
||||||
|
void on_setActiveBtn_clicked();
|
||||||
|
|
||||||
// This will be sent when the "close" button is clicked.
|
// This will be sent when the "close" button is clicked.
|
||||||
void on_closeBtnBox_rejected();
|
void on_closeBtnBox_rejected();
|
||||||
|
|
||||||
|
@ -27,7 +27,7 @@
|
|||||||
<item>
|
<item>
|
||||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||||
<item>
|
<item>
|
||||||
<widget class="QListView" name="listView"/>
|
<widget class="QTreeView" name="listView"/>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<layout class="QVBoxLayout" name="manageAcctsBtnBox">
|
<layout class="QVBoxLayout" name="manageAcctsBtnBox">
|
||||||
@ -65,6 +65,16 @@
|
|||||||
</property>
|
</property>
|
||||||
</spacer>
|
</spacer>
|
||||||
</item>
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QPushButton" name="setActiveBtn">
|
||||||
|
<property name="toolTip">
|
||||||
|
<string><html><head/><body><p>Set the currently selected account as the active account. The active account is the account that is used to log in (unless it is overridden in an instance-specific setting).</p></body></html></string>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>&Set Active</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
</item>
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
|
@ -33,7 +33,7 @@ MojangAccountList::MojangAccountList(QObject *parent) : QAbstractListModel(paren
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
MojangAccountPtr MojangAccountList::findAccount(const QString &username)
|
MojangAccountPtr MojangAccountList::findAccount(const QString &username) const
|
||||||
{
|
{
|
||||||
for (int i = 0; i < count(); i++)
|
for (int i = 0; i < count(); i++)
|
||||||
{
|
{
|
||||||
@ -41,7 +41,7 @@ MojangAccountPtr MojangAccountList::findAccount(const QString &username)
|
|||||||
if (account->username() == username)
|
if (account->username() == username)
|
||||||
return account;
|
return account;
|
||||||
}
|
}
|
||||||
return MojangAccountPtr();
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -82,6 +82,25 @@ void MojangAccountList::removeAccount(QModelIndex index)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
MojangAccountPtr MojangAccountList::activeAccount() const
|
||||||
|
{
|
||||||
|
if (m_activeAccount.isEmpty())
|
||||||
|
return nullptr;
|
||||||
|
else
|
||||||
|
return findAccount(m_activeAccount);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MojangAccountList::setActiveAccount(const QString& username)
|
||||||
|
{
|
||||||
|
beginResetModel();
|
||||||
|
for (MojangAccountPtr account : m_accounts)
|
||||||
|
if (account->username() == username)
|
||||||
|
m_activeAccount = username;
|
||||||
|
endResetModel();
|
||||||
|
onListChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void MojangAccountList::onListChanged()
|
void MojangAccountList::onListChanged()
|
||||||
{
|
{
|
||||||
if (m_autosave)
|
if (m_autosave)
|
||||||
@ -112,6 +131,9 @@ QVariant MojangAccountList::data(const QModelIndex &index, int role) const
|
|||||||
case Qt::DisplayRole:
|
case Qt::DisplayRole:
|
||||||
switch (index.column())
|
switch (index.column())
|
||||||
{
|
{
|
||||||
|
case ActiveColumn:
|
||||||
|
return account->username() == m_activeAccount;
|
||||||
|
|
||||||
case NameColumn:
|
case NameColumn:
|
||||||
return account->username();
|
return account->username();
|
||||||
|
|
||||||
@ -137,6 +159,9 @@ QVariant MojangAccountList::headerData(int section, Qt::Orientation orientation,
|
|||||||
case Qt::DisplayRole:
|
case Qt::DisplayRole:
|
||||||
switch (section)
|
switch (section)
|
||||||
{
|
{
|
||||||
|
case ActiveColumn:
|
||||||
|
return "Active?";
|
||||||
|
|
||||||
case NameColumn:
|
case NameColumn:
|
||||||
return "Name";
|
return "Name";
|
||||||
|
|
||||||
@ -167,7 +192,7 @@ int MojangAccountList::rowCount(const QModelIndex &parent) const
|
|||||||
|
|
||||||
int MojangAccountList::columnCount(const QModelIndex &parent) const
|
int MojangAccountList::columnCount(const QModelIndex &parent) const
|
||||||
{
|
{
|
||||||
return 1;
|
return 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
void MojangAccountList::updateListData(QList<MojangAccountPtr> versions)
|
void MojangAccountList::updateListData(QList<MojangAccountPtr> versions)
|
||||||
@ -252,6 +277,9 @@ bool MojangAccountList::loadList(const QString& filePath)
|
|||||||
}
|
}
|
||||||
endResetModel();
|
endResetModel();
|
||||||
|
|
||||||
|
// Load the active account.
|
||||||
|
m_activeAccount = root.value("activeAccount").toString("");
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -285,6 +313,9 @@ bool MojangAccountList::saveList(const QString& filePath)
|
|||||||
// Insert the account list into the root object.
|
// Insert the account list into the root object.
|
||||||
root.insert("accounts", accounts);
|
root.insert("accounts", accounts);
|
||||||
|
|
||||||
|
// Save the active account.
|
||||||
|
root.insert("activeAccount", m_activeAccount);
|
||||||
|
|
||||||
// Create a JSON document object to convert our JSON to bytes.
|
// Create a JSON document object to convert our JSON to bytes.
|
||||||
QJsonDocument doc(root);
|
QJsonDocument doc(root);
|
||||||
|
|
||||||
|
@ -44,8 +44,12 @@ public:
|
|||||||
enum VListColumns
|
enum VListColumns
|
||||||
{
|
{
|
||||||
// TODO: Add icon column.
|
// TODO: Add icon column.
|
||||||
// First column - Name
|
|
||||||
NameColumn = 0,
|
// First column - Active?
|
||||||
|
ActiveColumn = 0,
|
||||||
|
|
||||||
|
// Second column - Name
|
||||||
|
NameColumn,
|
||||||
};
|
};
|
||||||
|
|
||||||
explicit MojangAccountList(QObject *parent = 0);
|
explicit MojangAccountList(QObject *parent = 0);
|
||||||
@ -83,7 +87,7 @@ public:
|
|||||||
* \return A const pointer to the account with the given username. NULL if
|
* \return A const pointer to the account with the given username. NULL if
|
||||||
* one doesn't exist.
|
* one doesn't exist.
|
||||||
*/
|
*/
|
||||||
virtual MojangAccountPtr findAccount(const QString &username);
|
virtual MojangAccountPtr findAccount(const QString &username) const;
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* Sets the default path to save the list file to.
|
* Sets the default path to save the list file to.
|
||||||
@ -108,6 +112,19 @@ public:
|
|||||||
*/
|
*/
|
||||||
virtual bool saveList(const QString& file="");
|
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 MojangAccount. If there isn't an active account, returns a null pointer.
|
||||||
|
*/
|
||||||
|
virtual MojangAccountPtr activeAccount() const;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Sets the given account as the current active account.
|
||||||
|
*/
|
||||||
|
virtual void setActiveAccount(const QString& username);
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
/*!
|
/*!
|
||||||
* Signal emitted to indicate that the account list has changed.
|
* Signal emitted to indicate that the account list has changed.
|
||||||
@ -124,6 +141,12 @@ protected:
|
|||||||
|
|
||||||
QList<MojangAccountPtr> m_accounts;
|
QList<MojangAccountPtr> m_accounts;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* Username of the account that is currently active.
|
||||||
|
* Empty string if no account is active.
|
||||||
|
*/
|
||||||
|
QString m_activeAccount;
|
||||||
|
|
||||||
//! Path to the account list file. Empty string if there isn't one.
|
//! Path to the account list file. Empty string if there isn't one.
|
||||||
QString m_listFilePath;
|
QString m_listFilePath;
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user