Split multiplayer code into its own class

master
James Rowe 2018-04-01 00:06:48 +07:00
parent ddbbab8fd6
commit f346a9d372
9 changed files with 253 additions and 195 deletions

@ -69,6 +69,8 @@ add_executable(citra-qt
multiplayer/lobby.cpp multiplayer/lobby.cpp
multiplayer/message.h multiplayer/message.h
multiplayer/message.cpp multiplayer/message.cpp
multiplayer/state.cpp
multiplayer/state.h
multiplayer/validation.h multiplayer/validation.h
ui_settings.cpp ui_settings.cpp
ui_settings.h ui_settings.h

@ -31,11 +31,7 @@
#include "citra_qt/game_list.h" #include "citra_qt/game_list.h"
#include "citra_qt/hotkeys.h" #include "citra_qt/hotkeys.h"
#include "citra_qt/main.h" #include "citra_qt/main.h"
#include "citra_qt/multiplayer/client_room.h" #include "citra_qt/multiplayer/state.h"
#include "citra_qt/multiplayer/direct_connect.h"
#include "citra_qt/multiplayer/host_room.h"
#include "citra_qt/multiplayer/lobby.h"
#include "citra_qt/multiplayer/message.h"
#include "citra_qt/ui_settings.h" #include "citra_qt/ui_settings.h"
#include "citra_qt/updater/updater.h" #include "citra_qt/updater/updater.h"
#include "citra_qt/util/clickable_label.h" #include "citra_qt/util/clickable_label.h"
@ -137,16 +133,6 @@ GMainWindow::GMainWindow() : config(new Config()), emu_thread(nullptr) {
Network::Init(); Network::Init();
if (auto member = Network::GetRoomMember().lock()) {
// register the network structs to use in slots and signals
qRegisterMetaType<Network::RoomMember::State>();
state_callback_handle = member->BindOnStateChanged(
[this](const Network::RoomMember::State& state) { emit NetworkStateChanged(state); });
connect(this, &GMainWindow::NetworkStateChanged, this, &GMainWindow::OnNetworkStateChanged);
}
qRegisterMetaType<Common::WebResult>();
setWindowTitle(QString("Citra %1| %2-%3") setWindowTitle(QString("Citra %1| %2-%3")
.arg(Common::g_build_name, Common::g_scm_branch, Common::g_scm_desc)); .arg(Common::g_build_name, Common::g_scm_branch, Common::g_scm_desc));
show(); show();
@ -173,12 +159,6 @@ GMainWindow::~GMainWindow() {
delete render_window; delete render_window;
Pica::g_debug_context.reset(); Pica::g_debug_context.reset();
if (state_callback_handle) {
if (auto member = Network::GetRoomMember().lock()) {
member->Unbind(state_callback_handle);
}
}
Network::Shutdown(); Network::Shutdown();
} }
@ -192,6 +172,8 @@ void GMainWindow::InitializeWidgets() {
game_list = new GameList(this); game_list = new GameList(this);
ui.horizontalLayout->addWidget(game_list); ui.horizontalLayout->addWidget(game_list);
multiplayer_state = new MultiplayerState(this, game_list->GetModel());
// Setup updater // Setup updater
updater = new Updater(this); updater = new Updater(this);
UISettings::values.updater_found = updater->HasUpdater(); UISettings::values.updater_found = updater->HasUpdater();
@ -220,24 +202,14 @@ void GMainWindow::InitializeWidgets() {
tr("Time taken to emulate a 3DS frame, not counting framelimiting or v-sync. For " tr("Time taken to emulate a 3DS frame, not counting framelimiting or v-sync. For "
"full-speed emulation this should be at most 16.67 ms.")); "full-speed emulation this should be at most 16.67 ms."));
announce_multiplayer_session = std::make_shared<Core::AnnounceMultiplayerSession>();
announce_multiplayer_session->BindErrorCallback(
[this](const Common::WebResult& result) { emit AnnounceFailed(result); });
connect(this, &GMainWindow::AnnounceFailed, this, &GMainWindow::OnAnnounceFailed);
network_status_text = new ClickableLabel(this);
network_status_icon = new ClickableLabel(this);
network_status_text->setToolTip(tr("Current connection status"));
for (auto& label : {emu_speed_label, game_fps_label, emu_frametime_label}) { for (auto& label : {emu_speed_label, game_fps_label, emu_frametime_label}) {
label->setVisible(false); label->setVisible(false);
label->setFrameStyle(QFrame::NoFrame); label->setFrameStyle(QFrame::NoFrame);
label->setContentsMargins(4, 0, 4, 0); label->setContentsMargins(4, 0, 4, 0);
statusBar()->addPermanentWidget(label, 0); statusBar()->addPermanentWidget(label, 0);
} }
statusBar()->addPermanentWidget(network_status_text, 0); statusBar()->addPermanentWidget(multiplayer_state->GetStatusText(), 0);
statusBar()->addPermanentWidget(network_status_icon, 0); statusBar()->addPermanentWidget(multiplayer_state->GetStatusIcon(), 0);
network_status_icon->setPixmap(QIcon::fromTheme("disconnected").pixmap(16));
network_status_text->setText(tr("Not Connected. Click here to find a room!"));
statusBar()->setVisible(true); statusBar()->setVisible(true);
// Removes an ugly inner border from the status bar widgets under Linux // Removes an ugly inner border from the status bar widgets under Linux
@ -431,9 +403,6 @@ void GMainWindow::ConnectWidgetEvents() {
connect(this, &GMainWindow::UpdateProgress, this, &GMainWindow::OnUpdateProgress); connect(this, &GMainWindow::UpdateProgress, this, &GMainWindow::OnUpdateProgress);
connect(this, &GMainWindow::CIAInstallReport, this, &GMainWindow::OnCIAInstallReport); connect(this, &GMainWindow::CIAInstallReport, this, &GMainWindow::OnCIAInstallReport);
connect(this, &GMainWindow::CIAInstallFinished, this, &GMainWindow::OnCIAInstallFinished); connect(this, &GMainWindow::CIAInstallFinished, this, &GMainWindow::OnCIAInstallFinished);
connect(network_status_text, &ClickableLabel::clicked, this, &GMainWindow::OnOpenNetworkRoom);
connect(network_status_icon, &ClickableLabel::clicked, this, &GMainWindow::OnOpenNetworkRoom);
} }
void GMainWindow::ConnectMenuEvents() { void GMainWindow::ConnectMenuEvents() {
@ -462,12 +431,16 @@ void GMainWindow::ConnectMenuEvents() {
connect(ui.action_Show_Status_Bar, &QAction::triggered, statusBar(), &QStatusBar::setVisible); connect(ui.action_Show_Status_Bar, &QAction::triggered, statusBar(), &QStatusBar::setVisible);
// Multiplayer // Multiplayer
connect(ui.action_View_Lobby, &QAction::triggered, this, &GMainWindow::OnViewLobby); connect(ui.action_View_Lobby, &QAction::triggered, multiplayer_state,
connect(ui.action_Start_Room, &QAction::triggered, this, &GMainWindow::OnCreateRoom); &MultiplayerState::OnViewLobby);
connect(ui.action_Stop_Room, &QAction::triggered, this, &GMainWindow::OnCloseRoom); connect(ui.action_Start_Room, &QAction::triggered, multiplayer_state,
connect(ui.action_Connect_To_Room, &QAction::triggered, this, &MultiplayerState::OnCreateRoom);
&GMainWindow::OnDirectConnectToRoom); connect(ui.action_Stop_Room, &QAction::triggered, multiplayer_state,
connect(ui.action_Chat, &QAction::triggered, this, &GMainWindow::OnOpenNetworkRoom); &MultiplayerState::OnCloseRoom);
connect(ui.action_Connect_To_Room, &QAction::triggered, multiplayer_state,
&MultiplayerState::OnDirectConnectToRoom);
connect(ui.action_Chat, &QAction::triggered, multiplayer_state,
&MultiplayerState::OnOpenNetworkRoom);
ui.action_Fullscreen->setShortcut(GetHotkey("Main Window", "Fullscreen", this)->key()); ui.action_Fullscreen->setShortcut(GetHotkey("Main Window", "Fullscreen", this)->key());
ui.action_Screen_Layout_Swap_Screens->setShortcut( ui.action_Screen_Layout_Swap_Screens->setShortcut(
@ -931,30 +904,6 @@ void GMainWindow::OnMenuRecentFile() {
} }
} }
void GMainWindow::OnNetworkStateChanged(const Network::RoomMember::State& state) {
LOG_INFO(Frontend, "network state change");
if (state == Network::RoomMember::State::Joined) {
network_status_icon->setPixmap(QIcon::fromTheme("connected").pixmap(16));
network_status_text->setText(tr("Connected"));
ui.action_Chat->setEnabled(true);
return;
}
network_status_icon->setPixmap(QIcon::fromTheme("disconnected").pixmap(16));
network_status_text->setText(tr("Not Connected"));
ui.action_Chat->setDisabled(true);
ChangeRoomState();
}
void GMainWindow::OnAnnounceFailed(const Common::WebResult& result) {
announce_multiplayer_session->Stop();
QMessageBox::warning(
this, tr("Error"),
tr("Announcing the room failed.\nThe room will not get listed publicly.\nError: ") +
QString::fromStdString(result.result_string),
QMessageBox::Ok);
}
void GMainWindow::OnStartGame() { void GMainWindow::OnStartGame() {
emu_thread->SetRunning(true); emu_thread->SetRunning(true);
qRegisterMetaType<Core::System::ResultStatus>("Core::System::ResultStatus"); qRegisterMetaType<Core::System::ResultStatus>("Core::System::ResultStatus");
@ -1129,80 +1078,6 @@ void GMainWindow::OnCreateGraphicsSurfaceViewer() {
graphicsSurfaceViewerWidget->show(); graphicsSurfaceViewerWidget->show();
} }
static void BringWidgetToFront(QWidget* widget) {
widget->show();
widget->activateWindow();
widget->raise();
}
void GMainWindow::OnViewLobby() {
if (lobby == nullptr) {
lobby = new Lobby(this, game_list->GetModel(), announce_multiplayer_session);
connect(lobby, &Lobby::Closed, [&] {
LOG_INFO(Frontend, "Destroying lobby");
// lobby->close();
lobby = nullptr;
});
}
BringWidgetToFront(lobby);
}
void GMainWindow::OnCreateRoom() {
if (host_room == nullptr) {
host_room = new HostRoomWindow(this, game_list->GetModel(), announce_multiplayer_session);
connect(host_room, &HostRoomWindow::Closed, [&] {
// host_room->close();
LOG_INFO(Frontend, "Destroying host room");
host_room = nullptr;
});
}
BringWidgetToFront(host_room);
}
void GMainWindow::OnCloseRoom() {
if (auto room = Network::GetRoom().lock()) {
if (room->GetState() == Network::Room::State::Open) {
if (NetworkMessage::WarnCloseRoom()) {
room->Destroy();
announce_multiplayer_session->Stop();
// host_room->close();
}
}
}
}
void GMainWindow::OnOpenNetworkRoom() {
if (auto member = Network::GetRoomMember().lock()) {
if (member->IsConnected()) {
if (client_room == nullptr) {
client_room = new ClientRoomWindow(this);
connect(client_room, &ClientRoomWindow::Closed, [&] {
LOG_INFO(Frontend, "Destroying client room");
// client_room->close();
client_room = nullptr;
});
}
BringWidgetToFront(client_room);
return;
}
}
// If the user is not a member of a room, show the lobby instead.
// This is currently only used on the clickable label in the status bar
OnViewLobby();
}
void GMainWindow::OnDirectConnectToRoom() {
if (direct_connect == nullptr) {
direct_connect = new DirectConnectWindow(this);
connect(direct_connect, &DirectConnectWindow::Closed, [&] {
LOG_INFO(Frontend, "Destroying direct connect");
// direct_connect->close();
direct_connect = nullptr;
});
}
BringWidgetToFront(direct_connect);
}
void GMainWindow::UpdateStatusBar() { void GMainWindow::UpdateStatusBar() {
if (emu_thread == nullptr) { if (emu_thread == nullptr) {
status_bar_update_timer.stop(); status_bar_update_timer.stop();
@ -1335,17 +1210,7 @@ void GMainWindow::closeEvent(QCloseEvent* event) {
ShutdownGame(); ShutdownGame();
render_window->close(); render_window->close();
multiplayer_state->Close();
// Close Multiplayer windows
if (host_room)
host_room->close();
if (direct_connect)
direct_connect->close();
if (client_room)
client_room->close();
if (lobby)
lobby->close();
QWidget::closeEvent(event); QWidget::closeEvent(event);
} }

@ -29,6 +29,7 @@ class GraphicsTracingWidget;
class GraphicsVertexShaderWidget; class GraphicsVertexShaderWidget;
class GRenderWindow; class GRenderWindow;
class MicroProfileDialog; class MicroProfileDialog;
class MultiplayerState;
class ProfilerWidget; class ProfilerWidget;
template <typename> template <typename>
class QFutureWatcher; class QFutureWatcher;
@ -37,16 +38,6 @@ class RegistersWidget;
class Updater; class Updater;
class WaitTreeWidget; class WaitTreeWidget;
// Multiplayer forward declarations
class Lobby;
class HostRoomWindow;
class ClientRoomWindow;
class DirectConnectWindow;
namespace Core {
class AnnounceMultiplayerSession;
}
class GMainWindow : public QMainWindow { class GMainWindow : public QMainWindow {
Q_OBJECT Q_OBJECT
@ -94,16 +85,6 @@ signals:
// Signal that tells widgets to update icons to use the current theme // Signal that tells widgets to update icons to use the current theme
void UpdateThemedIcons(); void UpdateThemedIcons();
void NetworkStateChanged(const Network::RoomMember::State&);
void AnnounceFailed(const Common::WebResult&);
public slots:
void OnViewLobby();
void OnCreateRoom();
void OnCloseRoom();
void OnOpenNetworkRoom();
void OnDirectConnectToRoom();
private: private:
void InitializeWidgets(); void InitializeWidgets();
void InitializeDebugWidgets(); void InitializeDebugWidgets();
@ -173,8 +154,6 @@ private slots:
/// Called whenever a user selects the "File->Select Game List Root" menu item /// Called whenever a user selects the "File->Select Game List Root" menu item
void OnMenuSelectGameListRoot(); void OnMenuSelectGameListRoot();
void OnMenuRecentFile(); void OnMenuRecentFile();
void OnNetworkStateChanged(const Network::RoomMember::State& state);
void OnAnnounceFailed(const Common::WebResult&);
void OnConfigure(); void OnConfigure();
void OnToggleFilterBar(); void OnToggleFilterBar();
void OnDisplayTitleBars(bool); void OnDisplayTitleBars(bool);
@ -211,12 +190,10 @@ private:
QLabel* emu_speed_label = nullptr; QLabel* emu_speed_label = nullptr;
QLabel* game_fps_label = nullptr; QLabel* game_fps_label = nullptr;
QLabel* emu_frametime_label = nullptr; QLabel* emu_frametime_label = nullptr;
ClickableLabel* network_status_icon = nullptr;
ClickableLabel* network_status_text = nullptr;
QTimer status_bar_update_timer; QTimer status_bar_update_timer;
MultiplayerState* multiplayer_state = nullptr;
std::unique_ptr<Config> config; std::unique_ptr<Config> config;
std::shared_ptr<Core::AnnounceMultiplayerSession> announce_multiplayer_session;
// Whether emulation is currently running in Citra. // Whether emulation is currently running in Citra.
bool emulation_running = false; bool emulation_running = false;
@ -237,14 +214,6 @@ private:
bool explicit_update_check = false; bool explicit_update_check = false;
bool defer_update_prompt = false; bool defer_update_prompt = false;
// Multiplayer windows
Lobby* lobby = nullptr;
HostRoomWindow* host_room = nullptr;
ClientRoomWindow* client_room = nullptr;
DirectConnectWindow* direct_connect = nullptr;
Network::RoomMember::CallbackHandle<Network::RoomMember::State> state_callback_handle;
QAction* actions_recent_files[max_recent_files_item]; QAction* actions_recent_files[max_recent_files_item];
QTranslator translator; QTranslator translator;
@ -260,4 +229,3 @@ protected:
Q_DECLARE_METATYPE(size_t); Q_DECLARE_METATYPE(size_t);
Q_DECLARE_METATYPE(Service::AM::InstallStatus); Q_DECLARE_METATYPE(Service::AM::InstallStatus);
Q_DECLARE_METATYPE(Common::WebResult);

@ -12,6 +12,7 @@
#include "citra_qt/multiplayer/client_room.h" #include "citra_qt/multiplayer/client_room.h"
#include "citra_qt/multiplayer/direct_connect.h" #include "citra_qt/multiplayer/direct_connect.h"
#include "citra_qt/multiplayer/message.h" #include "citra_qt/multiplayer/message.h"
#include "citra_qt/multiplayer/state.h"
#include "citra_qt/multiplayer/validation.h" #include "citra_qt/multiplayer/validation.h"
#include "citra_qt/ui_settings.h" #include "citra_qt/ui_settings.h"
#include "core/settings.h" #include "core/settings.h"
@ -124,7 +125,7 @@ void DirectConnectWindow::OnConnection() {
ShowError(NetworkMessage::USERNAME_IN_USE); ShowError(NetworkMessage::USERNAME_IN_USE);
break; break;
case Network::RoomMember::State::Joining: case Network::RoomMember::State::Joining:
auto parent = static_cast<GMainWindow*>(parentWidget()); auto parent = static_cast<MultiplayerState*>(parentWidget());
parent->OnOpenNetworkRoom(); parent->OnOpenNetworkRoom();
close(); close();
} }

@ -14,6 +14,7 @@
#include "citra_qt/main.h" #include "citra_qt/main.h"
#include "citra_qt/multiplayer/host_room.h" #include "citra_qt/multiplayer/host_room.h"
#include "citra_qt/multiplayer/message.h" #include "citra_qt/multiplayer/message.h"
#include "citra_qt/multiplayer/state.h"
#include "citra_qt/multiplayer/validation.h" #include "citra_qt/multiplayer/validation.h"
#include "citra_qt/ui_settings.h" #include "citra_qt/ui_settings.h"
#include "common/logging/log.h" #include "common/logging/log.h"
@ -136,8 +137,8 @@ void HostRoomWindow::OnConnection() {
LOG_ERROR(Network, "Starting announce session failed"); LOG_ERROR(Network, "Starting announce session failed");
} }
} }
auto parent = static_cast<GMainWindow*>(parentWidget()); auto parent = static_cast<MultiplayerState*>(parentWidget());
parent->ChangeRoomState(); // parent->ChangeRoomState();
parent->OnOpenNetworkRoom(); parent->OnOpenNetworkRoom();
close(); close();
emit Closed(); emit Closed();

@ -11,6 +11,7 @@
#include "citra_qt/multiplayer/lobby.h" #include "citra_qt/multiplayer/lobby.h"
#include "citra_qt/multiplayer/lobby_p.h" #include "citra_qt/multiplayer/lobby_p.h"
#include "citra_qt/multiplayer/message.h" #include "citra_qt/multiplayer/message.h"
#include "citra_qt/multiplayer/state.h"
#include "citra_qt/multiplayer/validation.h" #include "citra_qt/multiplayer/validation.h"
#include "citra_qt/ui_settings.h" #include "citra_qt/ui_settings.h"
#include "common/logging/log.h" #include "common/logging/log.h"
@ -51,9 +52,9 @@ Lobby::Lobby(QWidget* parent, QStandardItemModel* list,
ui->nickname->setText(UISettings::values.nickname); ui->nickname->setText(UISettings::values.nickname);
// UI Buttons // UI Buttons
GMainWindow* p = reinterpret_cast<GMainWindow*>(parent); MultiplayerState* p = reinterpret_cast<MultiplayerState*>(parent);
connect(ui->refresh_list, &QPushButton::pressed, this, &Lobby::RefreshLobby); connect(ui->refresh_list, &QPushButton::pressed, this, &Lobby::RefreshLobby);
connect(ui->chat, &QPushButton::pressed, p, &GMainWindow::OnOpenNetworkRoom); connect(ui->chat, &QPushButton::pressed, p, &MultiplayerState::OnOpenNetworkRoom);
connect(ui->games_owned, &QCheckBox::stateChanged, proxy, connect(ui->games_owned, &QCheckBox::stateChanged, proxy,
&LobbyFilterProxyModel::SetFilterOwned); &LobbyFilterProxyModel::SetFilterOwned);
connect(ui->hide_full, &QCheckBox::stateChanged, proxy, &LobbyFilterProxyModel::SetFilterFull); connect(ui->hide_full, &QCheckBox::stateChanged, proxy, &LobbyFilterProxyModel::SetFilterFull);
@ -64,7 +65,7 @@ Lobby::Lobby(QWidget* parent, QStandardItemModel* list,
// Actions // Actions
connect(this, &Lobby::LobbyRefreshed, this, &Lobby::OnRefreshLobby); connect(this, &Lobby::LobbyRefreshed, this, &Lobby::OnRefreshLobby);
// TODO(jroweboy): change this slot to OnConnected? // TODO(jroweboy): change this slot to OnConnected?
connect(this, &Lobby::Connected, p, &GMainWindow::OnOpenNetworkRoom); connect(this, &Lobby::Connected, p, &MultiplayerState::OnOpenNetworkRoom);
// setup the callbacks for network updates // setup the callbacks for network updates
if (auto member = Network::GetRoomMember().lock()) { if (auto member = Network::GetRoomMember().lock()) {
@ -90,8 +91,6 @@ Lobby::Lobby(QWidget* parent, QStandardItemModel* list,
ui->chat->setDisabled(true); ui->chat->setDisabled(true);
} }
Lobby::~Lobby() {}
const QString Lobby::PasswordPrompt() { const QString Lobby::PasswordPrompt() {
bool ok; bool ok;
const QString text = const QString text =
@ -305,7 +304,7 @@ void Lobby::OnConnection() {
ShowError(NetworkMessage::UNABLE_TO_CONNECT); ShowError(NetworkMessage::UNABLE_TO_CONNECT);
break; break;
case Network::RoomMember::State::Joining: case Network::RoomMember::State::Joining:
auto parent = static_cast<GMainWindow*>(parentWidget()); auto parent = static_cast<MultiplayerState*>(parentWidget());
parent->OnOpenNetworkRoom(); parent->OnOpenNetworkRoom();
close(); close();
break; break;

@ -31,7 +31,7 @@ class Lobby : public QDialog {
public: public:
explicit Lobby(QWidget* parent, QStandardItemModel* list, explicit Lobby(QWidget* parent, QStandardItemModel* list,
std::shared_ptr<Core::AnnounceMultiplayerSession> session); std::shared_ptr<Core::AnnounceMultiplayerSession> session);
~Lobby(); ~Lobby() = default;
public slots: public slots:
/** /**

@ -0,0 +1,157 @@
// Copyright 2018 Citra Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#include <QIcon>
#include <QMessageBox>
#include <QStandardItemModel>
#include "citra_qt/game_list.h"
#include "citra_qt/multiplayer/client_room.h"
#include "citra_qt/multiplayer/direct_connect.h"
#include "citra_qt/multiplayer/host_room.h"
#include "citra_qt/multiplayer/lobby.h"
#include "citra_qt/multiplayer/message.h"
#include "citra_qt/multiplayer/state.h"
#include "citra_qt/util/clickable_label.h"
#include "common/announce_multiplayer_room.h"
#include "common/logging/log.h"
MultiplayerState::MultiplayerState(QWidget* parent, QStandardItemModel* game_list_model)
: QWidget(parent), game_list_model(game_list_model) {
if (auto member = Network::GetRoomMember().lock()) {
// register the network structs to use in slots and signals
qRegisterMetaType<Network::RoomMember::State>();
state_callback_handle = member->BindOnStateChanged(
[this](const Network::RoomMember::State& state) { emit NetworkStateChanged(state); });
connect(this, &MultiplayerState::NetworkStateChanged, this,
&MultiplayerState::OnNetworkStateChanged);
}
qRegisterMetaType<Common::WebResult>();
announce_multiplayer_session = std::make_shared<Core::AnnounceMultiplayerSession>();
announce_multiplayer_session->BindErrorCallback(
[this](const Common::WebResult& result) { emit AnnounceFailed(result); });
connect(this, &MultiplayerState::AnnounceFailed, this, &MultiplayerState::OnAnnounceFailed);
status_text = new ClickableLabel(this);
status_icon = new ClickableLabel(this);
status_text->setToolTip(tr("Current connection status"));
status_text->setText(tr("Not Connected. Click here to find a room!"));
status_icon->setPixmap(QIcon::fromTheme("disconnected").pixmap(16));
connect(status_text, &ClickableLabel::clicked, this, &MultiplayerState::OnOpenNetworkRoom);
connect(status_icon, &ClickableLabel::clicked, this, &MultiplayerState::OnOpenNetworkRoom);
}
MultiplayerState::~MultiplayerState() {
if (state_callback_handle) {
if (auto member = Network::GetRoomMember().lock()) {
member->Unbind(state_callback_handle);
}
}
}
void MultiplayerState::Close() {
if (host_room)
host_room->close();
if (direct_connect)
direct_connect->close();
if (client_room)
client_room->close();
if (lobby)
lobby->close();
}
void MultiplayerState::OnNetworkStateChanged(const Network::RoomMember::State& state) {
NGLOG_DEBUG(Frontend, "Network state change");
if (state == Network::RoomMember::State::Joined) {
status_icon->setPixmap(QIcon::fromTheme("connected").pixmap(16));
status_text->setText(tr("Connected"));
return;
}
status_icon->setPixmap(QIcon::fromTheme("disconnected").pixmap(16));
status_text->setText(tr("Not Connected"));
}
void MultiplayerState::OnAnnounceFailed(const Common::WebResult& result) {
announce_multiplayer_session->Stop();
QMessageBox::warning(this, tr("Error"),
tr("Failed to announce the room to the public lobby.\nThe room will not "
"get listed publicly.\nError: ") +
QString::fromStdString(result.result_string),
QMessageBox::Ok);
}
static void BringWidgetToFront(QWidget* widget) {
widget->show();
widget->activateWindow();
widget->raise();
}
void MultiplayerState::OnViewLobby() {
if (lobby == nullptr) {
lobby = new Lobby(this, game_list_model, announce_multiplayer_session);
connect(lobby, &Lobby::Closed, [&] {
LOG_INFO(Frontend, "Destroying lobby");
// lobby->close();
lobby = nullptr;
});
}
BringWidgetToFront(lobby);
}
void MultiplayerState::OnCreateRoom() {
if (host_room == nullptr) {
host_room = new HostRoomWindow(this, game_list_model, announce_multiplayer_session);
connect(host_room, &HostRoomWindow::Closed, [&] {
// host_room->close();
LOG_INFO(Frontend, "Destroying host room");
host_room = nullptr;
});
}
BringWidgetToFront(host_room);
}
void MultiplayerState::OnCloseRoom() {
if (auto room = Network::GetRoom().lock()) {
if (room->GetState() == Network::Room::State::Open) {
if (NetworkMessage::WarnCloseRoom()) {
room->Destroy();
announce_multiplayer_session->Stop();
// host_room->close();
}
}
}
}
void MultiplayerState::OnOpenNetworkRoom() {
if (auto member = Network::GetRoomMember().lock()) {
if (member->IsConnected()) {
if (client_room == nullptr) {
client_room = new ClientRoomWindow(this);
connect(client_room, &ClientRoomWindow::Closed, [&] {
LOG_INFO(Frontend, "Destroying client room");
// client_room->close();
client_room = nullptr;
});
}
BringWidgetToFront(client_room);
return;
}
}
// If the user is not a member of a room, show the lobby instead.
// This is currently only used on the clickable label in the status bar
OnViewLobby();
}
void MultiplayerState::OnDirectConnectToRoom() {
if (direct_connect == nullptr) {
direct_connect = new DirectConnectWindow(this);
connect(direct_connect, &DirectConnectWindow::Closed, [&] {
LOG_INFO(Frontend, "Destroying direct connect");
// direct_connect->close();
direct_connect = nullptr;
});
}
BringWidgetToFront(direct_connect);
}

@ -0,0 +1,65 @@
// Copyright 2018 Citra Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#pragma once
#include <QWidget>
#include "network/network.h"
class QStandardItemModel;
class Lobby;
class HostRoomWindow;
class ClientRoomWindow;
class DirectConnectWindow;
class ClickableLabel;
namespace Core {
class AnnounceMultiplayerSession;
}
class MultiplayerState : public QWidget {
Q_OBJECT;
public:
explicit MultiplayerState(QWidget* parent, QStandardItemModel* game_list);
~MultiplayerState();
/**
* Close all open multiplayer related dialogs
*/
void Close();
ClickableLabel* GetStatusText() const {
return status_text;
}
ClickableLabel* GetStatusIcon() const {
return status_icon;
}
public slots:
void OnNetworkStateChanged(const Network::RoomMember::State& state);
void OnViewLobby();
void OnCreateRoom();
void OnCloseRoom();
void OnOpenNetworkRoom();
void OnDirectConnectToRoom();
void OnAnnounceFailed(const Common::WebResult&);
signals:
void NetworkStateChanged(const Network::RoomMember::State&);
void AnnounceFailed(const Common::WebResult&);
private:
Lobby* lobby = nullptr;
HostRoomWindow* host_room = nullptr;
ClientRoomWindow* client_room = nullptr;
DirectConnectWindow* direct_connect = nullptr;
ClickableLabel* status_icon = nullptr;
ClickableLabel* status_text = nullptr;
QStandardItemModel* game_list_model = nullptr;
std::shared_ptr<Core::AnnounceMultiplayerSession> announce_multiplayer_session;
Network::RoomMember::CallbackHandle<Network::RoomMember::State> state_callback_handle;
};
Q_DECLARE_METATYPE(Common::WebResult);