Merge branch 'feature_yggdrasil' into develop

Conflicts:
	gui/MainWindow.cpp
	logic/OneSixInstance.h

Fix missing session id functionality for legacy and old onesix.
This commit is contained in:
Petr Mrázek
2013-11-24 18:41:35 +01:00
24 changed files with 1849 additions and 132 deletions

View File

@ -57,6 +57,7 @@
#include "gui/dialogs/IconPickerDialog.h"
#include "gui/dialogs/EditNotesDialog.h"
#include "gui/dialogs/CopyInstanceDialog.h"
#include "gui/dialogs/AccountListDialog.h"
#include "gui/ConsoleWindow.h"
@ -84,11 +85,6 @@ MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWi
ui->setupUi(this);
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.
setUnifiedTitleAndToolBarOnMac(true);
@ -428,6 +424,12 @@ void MainWindow::on_actionSettings_triggered()
proxymodel->sort(0);
}
void MainWindow::on_actionManageAccounts_triggered()
{
AccountListDialog dialog(this);
dialog.exec();
}
void MainWindow::on_actionReportBug_triggered()
{
openWebPage(QUrl("http://multimc.myjetbrains.com/youtrack/dashboard#newissue=yes"));
@ -538,11 +540,7 @@ void MainWindow::instanceActivated(QModelIndex index)
NagUtils::checkJVMArgs(inst->settings().get("JvmArgs").toString(), this);
bool autoLogin = inst->settings().get("AutoLogin").toBool();
if (autoLogin)
doAutoLogin();
else
doLogin();
doLogin();
}
void MainWindow::on_actionLaunchInstance_triggered()
@ -554,106 +552,74 @@ void MainWindow::on_actionLaunchInstance_triggered()
}
}
void MainWindow::doAutoLogin()
{
if (!m_selectedInstance)
return;
Keyring *k = Keyring::instance();
QStringList accounts = k->getStoredAccounts("minecraft");
if (!accounts.isEmpty())
{
QString username = accounts[0];
QString password = k->getPassword("minecraft", username);
if (!password.isEmpty())
{
QLOG_INFO() << "Automatically logging in with stored account: " << username;
m_activeInst = m_selectedInstance;
doLogin(username, password);
}
else
{
QLOG_ERROR() << "Auto login set for account, but no password was found: "
<< username;
doLogin(tr("Auto login attempted, but no password is stored."));
}
}
else
{
QLOG_ERROR() << "Auto login set but no accounts were stored.";
doLogin(tr("Auto login attempted, but no accounts are stored."));
}
}
void MainWindow::doLogin(QString username, QString password)
{
PasswordLogin uInfo{username, password};
ProgressDialog *tDialog = new ProgressDialog(this);
LoginTask *loginTask = new LoginTask(uInfo, tDialog);
connect(loginTask, SIGNAL(succeeded()), SLOT(onLoginComplete()), Qt::QueuedConnection);
connect(loginTask, SIGNAL(failed(QString)), SLOT(doLogin(QString)), Qt::QueuedConnection);
tDialog->exec(loginTask);
}
void MainWindow::doLogin(const QString &errorMsg)
{
if (!m_selectedInstance)
return;
LoginDialog *loginDlg = new LoginDialog(this, errorMsg);
if (!m_selectedInstance->lastLaunch())
loginDlg->forceOnline();
loginDlg->exec();
if (loginDlg->result() == QDialog::Accepted)
// Find an account to use.
std::shared_ptr<MojangAccountList> accounts = MMC->accounts();
MojangAccountPtr account = accounts->activeAccount();
if (accounts->count() <= 0)
{
if (loginDlg->isOnline())
// Tell the user they need to log in at least one account in order to play.
auto reply = CustomMessageBox::selectable(this, tr("No Accounts"),
tr("In order to play Minecraft, you must have at least one Mojang or Minecraft account logged in to MultiMC."
"Would you like to open the account manager to add an account now?"),
QMessageBox::Information, QMessageBox::Yes | QMessageBox::No)->exec();
if (reply == QMessageBox::Yes)
{
m_activeInst = m_selectedInstance;
doLogin(loginDlg->getUsername(), loginDlg->getPassword());
// Open the account manager.
on_actionManageAccounts_triggered();
}
else
}
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)
{
QString user = loginDlg->getUsername();
if (user.length() == 0)
user = QString("Player");
m_activeLogin = {user, QString("Offline"), user, QString()};
m_activeInst = m_selectedInstance;
launchInstance(m_activeInst, m_activeLogin);
// Open the account manager.
on_actionManageAccounts_triggered();
}
}
else
{
// We'll need to validate the access token to make sure the account is still logged in.
// TODO: Do that ^
prepareLaunch(m_selectedInstance, account);
}
}
void MainWindow::onLoginComplete()
void MainWindow::prepareLaunch(BaseInstance* instance, MojangAccountPtr account)
{
if (!m_activeInst)
return;
LoginTask *task = (LoginTask *)QObject::sender();
m_activeLogin = task->getResult();
Task *updateTask = m_activeInst->doUpdate();
Task *updateTask = instance->doUpdate();
if (!updateTask)
{
launchInstance(m_activeInst, m_activeLogin);
launchInstance(instance, account);
}
else
{
ProgressDialog tDialog(this);
connect(updateTask, SIGNAL(succeeded()), SLOT(onGameUpdateComplete()));
connect(updateTask, &Task::succeeded, [this, instance, account] { launchInstance(instance, account); });
connect(updateTask, SIGNAL(failed(QString)), SLOT(onGameUpdateError(QString)));
tDialog.exec(updateTask);
delete updateTask;
}
auto job = new NetJob("Player skin: " + m_activeLogin.player_name);
QString playerName = account->currentProfile()->name();
auto meta = MMC->metacache()->resolveEntry("skins", m_activeLogin.player_name + ".png");
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/" + m_activeLogin.player_name + ".png"),
QUrl("http://skins.minecraft.net/MinecraftSkins/" + playerName + ".png"),
meta);
job->addNetAction(action);
meta->stale = true;
@ -678,12 +644,12 @@ void MainWindow::onLoginComplete()
QJsonDocument jsonDoc = QJsonDocument::fromJson(data, &jsonError);
QJsonObject root = jsonDoc.object();
QJsonObject mappings = root.value("mappings").toObject();
QJsonArray usernames = mappings.value(m_activeLogin.username).toArray();
QJsonArray usernames = mappings.value(account->username()).toArray();
if (!usernames.contains(m_activeLogin.player_name))
if (!usernames.contains(playerName))
{
usernames.prepend(m_activeLogin.player_name);
mappings[m_activeLogin.username] = usernames;
usernames.prepend(playerName);
mappings[account->username()] = usernames;
root["mappings"] = mappings;
jsonDoc.setObject(root);
@ -693,22 +659,12 @@ void MainWindow::onLoginComplete()
}
}
void MainWindow::onGameUpdateComplete()
{
launchInstance(m_activeInst, m_activeLogin);
}
void MainWindow::onGameUpdateError(QString error)
{
CustomMessageBox::selectable(this, tr("Error updating instance"), error,
QMessageBox::Warning)->show();
}
void MainWindow::launchInstance(BaseInstance *instance, LoginResponse response)
void MainWindow::launchInstance(BaseInstance *instance, MojangAccountPtr account)
{
Q_ASSERT_X(instance != NULL, "launchInstance", "instance is NULL");
Q_ASSERT_X(account.get() != nullptr, "launchInstance", "account is NULL");
proc = instance->prepareForLaunch(response);
proc = instance->prepareForLaunch(account);
if (!proc)
return;
@ -717,10 +673,19 @@ void MainWindow::launchInstance(BaseInstance *instance, LoginResponse response)
console = new ConsoleWindow(proc);
connect(console, SIGNAL(isClosing()), this, SLOT(instanceEnded()));
proc->setLogin(response.username, response.session_id);
// I think this will work...
QString username = account->username();
QString session_id = account->accessToken();
proc->setLogin(username, session_id);
proc->launch();
}
void MainWindow::onGameUpdateError(QString error)
{
CustomMessageBox::selectable(this, tr("Error updating instance"), error,
QMessageBox::Warning)->show();
}
void MainWindow::taskStart()
{
// Nothing to do here yet.

View File

@ -22,6 +22,8 @@
#include "logic/net/LoginTask.h"
#include "logic/BaseInstance.h"
#include "logic/auth/MojangAccount.h"
class QToolButton;
class LabeledToolButton;
class QLabel;
@ -80,6 +82,8 @@ slots:
void on_actionSettings_triggered();
void on_actionManageAccounts_triggered();
void on_actionReportBug_triggered();
void on_actionNews_triggered();
@ -103,12 +107,18 @@ slots:
void on_actionEditInstNotes_triggered();
void doLogin(const QString &errorMsg = "");
void doLogin(QString username, QString password);
void doAutoLogin();
void onLoginComplete();
/*!
* Launches the given instance with the given account.
* This function assumes that the given account has a valid, usable access token.
*/
void launchInstance(BaseInstance* instance, MojangAccountPtr account);
/*!
* Prepares the given instance for launch with the given account.
*/
void prepareLaunch(BaseInstance* instance, MojangAccountPtr account);
void onGameUpdateComplete();
void onGameUpdateError(QString error);
void taskStart();
@ -136,8 +146,6 @@ slots:
void startTask(Task *task);
void launchInstance(BaseInstance *inst, LoginResponse response);
protected:
bool eventFilter(QObject *obj, QEvent *ev);
void setCatBackground(bool enabled);
@ -155,12 +163,6 @@ private:
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;
QLabel *m_statusLeft;

View File

@ -70,6 +70,7 @@
<addaction name="separator"/>
<addaction name="actionCheckUpdate"/>
<addaction name="actionSettings"/>
<addaction name="actionManageAccounts"/>
<addaction name="separator"/>
<addaction name="actionReportBug"/>
<addaction name="actionNews"/>
@ -465,6 +466,14 @@
<string>Add a new instance.</string>
</property>
</action>
<action name="actionManageAccounts">
<property name="text">
<string>Manage Accounts</string>
</property>
<property name="toolTip">
<string>Manage your Mojang or Minecraft accounts.</string>
</property>
</action>
</widget>
<layoutdefault spacing="6" margin="11"/>
<resources>

View File

@ -0,0 +1,112 @@
/* Copyright 2013 MultiMC Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "AccountListDialog.h"
#include "ui_AccountListDialog.h"
#include <QItemSelectionModel>
#include <logger/QsLog.h>
#include <logic/auth/AuthenticateTask.h>
#include <gui/dialogs/LoginDialog.h>
#include <gui/dialogs/ProgressDialog.h>
#include <MultiMC.h>
AccountListDialog::AccountListDialog(QWidget *parent) :
QDialog(parent),
ui(new Ui::AccountListDialog)
{
ui->setupUi(this);
m_accounts = MMC->accounts();
// TODO: Make the "Active?" column show checkboxes or radio buttons.
ui->listView->setModel(m_accounts.get());
}
AccountListDialog::~AccountListDialog()
{
delete ui;
}
void AccountListDialog::on_addAccountBtn_clicked()
{
doLogin("Please log in to add your account.");
}
void AccountListDialog::on_rmAccountBtn_clicked()
{
QModelIndexList selection = ui->listView->selectionModel()->selectedIndexes();
if (selection.size() > 0)
{
QModelIndex selected = selection.first();
m_accounts->removeAccount(selected);
}
}
void AccountListDialog::on_editAccountBtn_clicked()
{
// 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()
{
close();
}
void AccountListDialog::doLogin(const QString& errMsg)
{
// TODO: We can use the login dialog for this for now, but we'll have to make something better for it eventually.
LoginDialog loginDialog(this);
loginDialog.exec();
if (loginDialog.result() == QDialog::Accepted)
{
QString username(loginDialog.getUsername());
QString password(loginDialog.getPassword());
MojangAccountPtr account = MojangAccountPtr(new MojangAccount(username));
ProgressDialog* progDialog = new ProgressDialog(this);
m_authTask = new AuthenticateTask(account, password, progDialog);
connect(m_authTask, SIGNAL(succeeded()), SLOT(onLoginComplete()), Qt::QueuedConnection);
connect(m_authTask, SIGNAL(failed(QString)), SLOT(doLogin(QString)), Qt::QueuedConnection);
progDialog->exec(m_authTask);
//delete m_authTask;
}
}
void AccountListDialog::onLoginComplete()
{
// Add the authenticated account to the accounts list.
MojangAccountPtr account = m_authTask->getMojangAccount();
m_accounts->addAccount(account);
//ui->listView->update();
}

View File

@ -0,0 +1,63 @@
/* Copyright 2013 MultiMC Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#pragma once
#include <QDialog>
#include <memory>
#include "logic/lists/MojangAccountList.h"
namespace Ui {
class AccountListDialog;
}
class AuthenticateTask;
class AccountListDialog : public QDialog
{
Q_OBJECT
public:
explicit AccountListDialog(QWidget *parent = 0);
~AccountListDialog();
public
slots:
void on_addAccountBtn_clicked();
void on_rmAccountBtn_clicked();
void on_editAccountBtn_clicked();
void on_setActiveBtn_clicked();
// This will be sent when the "close" button is clicked.
void on_closeBtnBox_rejected();
protected:
std::shared_ptr<MojangAccountList> m_accounts;
AuthenticateTask* m_authTask;
protected
slots:
void doLogin(const QString& errMsg="");
void onLoginComplete();
private:
Ui::AccountListDialog *ui;
};

View File

@ -0,0 +1,93 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>AccountListDialog</class>
<widget class="QDialog" name="AccountListDialog">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>400</width>
<height>300</height>
</rect>
</property>
<property name="windowTitle">
<string>Dialog</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_2">
<item>
<widget class="QLabel" name="welcomeLabel">
<property name="text">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Welcome! If you're new here, you can click the &amp;quot;Add&amp;quot; button to add your Mojang or Minecraft account.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QTreeView" name="listView"/>
</item>
<item>
<layout class="QVBoxLayout" name="manageAcctsBtnBox">
<item>
<widget class="QPushButton" name="addAccountBtn">
<property name="text">
<string>&amp;Add</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="editAccountBtn">
<property name="text">
<string>&amp;Edit</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="rmAccountBtn">
<property name="text">
<string>&amp;Remove</string>
</property>
</widget>
</item>
<item>
<spacer name="buttonSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QPushButton" name="setActiveBtn">
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;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).&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>&amp;Set Active</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</item>
<item>
<widget class="QDialogButtonBox" name="closeBtnBox">
<property name="standardButtons">
<set>QDialogButtonBox::Close</set>
</property>
</widget>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>