Skip to content
Permalink
Browse files

Qt/NetPlay: Integrate NetPlayIndex

  • Loading branch information...
spycrab committed Mar 30, 2019
1 parent 0279d12 commit 094bf0d2ffb476d177d68ea496898615055963c1
@@ -36,7 +36,7 @@ class HttpRequest::Impl final

static int CurlProgressCallback(Impl* impl, double dlnow, double dltotal, double ulnow,
double ultotal);
const std::string EscapeComponent(const std::string& string);
std::string EscapeComponent(const std::string& string);

private:
static std::mutex s_curl_was_inited_mutex;
@@ -75,7 +75,7 @@ void HttpRequest::FollowRedirects(long max)
m_impl->FollowRedirects(max);
}

const std::string HttpRequest::EscapeComponent(const std::string& string)
std::string HttpRequest::EscapeComponent(const std::string& string)
{
return m_impl->EscapeComponent(string);
}
@@ -165,7 +165,7 @@ void HttpRequest::Impl::FollowRedirects(long max)
curl_easy_setopt(m_curl.get(), CURLOPT_MAXREDIRS, max);
}

const std::string HttpRequest::Impl::EscapeComponent(const std::string& string)
std::string HttpRequest::Impl::EscapeComponent(const std::string& string)
{
return curl_easy_escape(m_curl.get(), string.c_str(), static_cast<int>(string.size()));
}
@@ -34,7 +34,7 @@ class HttpRequest final
void SetCookies(const std::string& cookies);
void UseIPv4();
void FollowRedirects(long max = 1);
const std::string EscapeComponent(const std::string& string);
std::string EscapeComponent(const std::string& string);
Response Get(const std::string& url, const Headers& headers = {});
Response Post(const std::string& url, const std::vector<u8>& payload,
const Headers& headers = {});
@@ -20,7 +20,7 @@ const ConfigInfo<u16> NETPLAY_TRAVERSAL_PORT{{System::Main, "NetPlay", "Traversa
const ConfigInfo<std::string> NETPLAY_TRAVERSAL_CHOICE{{System::Main, "NetPlay", "TraversalChoice"},
"direct"};
const ConfigInfo<std::string> NETPLAY_INDEX_URL{{System::Main, "NetPlay", "IndexServer"},
"https://dolphin-emu.org/lobby"};
"https://lobby.dolphin-emu.org"};

const ConfigInfo<bool> NETPLAY_USE_INDEX{{System::Main, "NetPlay", "UseIndex"}, false};
const ConfigInfo<std::string> NETPLAY_INDEX_NAME{{System::Main, "NetPlay", "IndexName"}, ""};
@@ -98,6 +98,7 @@ add_executable(dolphin-emu
NetPlay/ChunkedProgressDialog.cpp
NetPlay/GameListDialog.cpp
NetPlay/MD5Dialog.cpp
NetPlay/NetPlayBrowser.cpp
NetPlay/NetPlayDialog.cpp
NetPlay/NetPlaySetupDialog.cpp
NetPlay/PadMappingDialog.cpp
@@ -146,6 +146,7 @@
<QtMoc Include="NetPlay\ChunkedProgressDialog.h" />
<QtMoc Include="NetPlay\GameListDialog.h" />
<QtMoc Include="NetPlay\MD5Dialog.h" />
<QtMoc Include="NetPlay\NetPlayBrowser.h" />
<QtMoc Include="NetPlay\NetPlayDialog.h" />
<QtMoc Include="NetPlay\NetPlaySetupDialog.h" />
<QtMoc Include="NetPlay\PadMappingDialog.h" />
@@ -247,6 +248,7 @@
<ClCompile Include="$(QtMocOutPrefix)MemoryWidget.cpp" />
<ClCompile Include="$(QtMocOutPrefix)MenuBar.cpp" />
<ClCompile Include="$(QtMocOutPrefix)ModalMessageBox.cpp" />
<ClCompile Include="$(QtMocOutPrefix)NetPlayBrowser.cpp" />
<ClCompile Include="$(QtMocOutPrefix)NetPlayDialog.cpp" />
<ClCompile Include="$(QtMocOutPrefix)NetPlaySetupDialog.cpp" />
<ClCompile Include="$(QtMocOutPrefix)NewBreakpointDialog.cpp" />
@@ -364,6 +366,7 @@
<ClCompile Include="NetPlay\ChunkedProgressDialog.cpp" />
<ClCompile Include="NetPlay\GameListDialog.cpp" />
<ClCompile Include="NetPlay\MD5Dialog.cpp" />
<ClCompile Include="NetPlay\NetPlayBrowser.cpp" />
<ClCompile Include="NetPlay\NetPlayDialog.cpp" />
<ClCompile Include="NetPlay\NetPlaySetupDialog.cpp" />
<ClCompile Include="NetPlay\PadMappingDialog.cpp" />
@@ -80,6 +80,7 @@
#include "DolphinQt/HotkeyScheduler.h"
#include "DolphinQt/MainWindow.h"
#include "DolphinQt/MenuBar.h"
#include "DolphinQt/NetPlay/NetPlayBrowser.h"
#include "DolphinQt/NetPlay/NetPlayDialog.h"
#include "DolphinQt/NetPlay/NetPlaySetupDialog.h"
#include "DolphinQt/QtUtils/ModalMessageBox.h"
@@ -449,6 +450,7 @@ void MainWindow::ConnectMenuBar()
connect(m_menu_bar, &MenuBar::PerformOnlineUpdate, this, &MainWindow::PerformOnlineUpdate);
connect(m_menu_bar, &MenuBar::BootWiiSystemMenu, this, &MainWindow::BootWiiSystemMenu);
connect(m_menu_bar, &MenuBar::StartNetPlay, this, &MainWindow::ShowNetPlaySetupDialog);
connect(m_menu_bar, &MenuBar::BrowseNetPlay, this, &MainWindow::ShowNetPlayBrowser);
connect(m_menu_bar, &MenuBar::ShowFIFOPlayer, this, &MainWindow::ShowFIFOPlayer);
connect(m_menu_bar, &MenuBar::ConnectWiiRemote, this, &MainWindow::OnConnectWiiRemote);

@@ -1125,6 +1127,13 @@ void MainWindow::ShowNetPlaySetupDialog()
m_netplay_setup_dialog->activateWindow();
}

void MainWindow::ShowNetPlayBrowser()
{
auto* browser = new NetPlayBrowser(this);
connect(browser, &NetPlayBrowser::Join, this, &MainWindow::NetPlayJoin);
browser->exec();
}

void MainWindow::ShowFIFOPlayer()
{
if (!m_fifo_window)
@@ -148,6 +148,7 @@ class MainWindow final : public QMainWindow
void ShowAboutDialog();
void ShowHotkeyDialog();
void ShowNetPlaySetupDialog();
void ShowNetPlayBrowser();
void ShowFIFOPlayer();
void ShowMemcardManager();
void ShowResourcePackManager();
@@ -241,6 +241,7 @@ void MenuBar::AddToolsMenu()
gc_ipl->addAction(tr("PAL"), this, [this] { emit BootGameCubeIPL(DiscIO::Region::PAL); });

tools_menu->addAction(tr("Start &NetPlay..."), this, &MenuBar::StartNetPlay);
tools_menu->addAction(tr("Browse &NetPlay Sessions...."), this, &MenuBar::BrowseNetPlay);
tools_menu->addAction(tr("FIFO Player"), this, &MenuBar::ShowFIFOPlayer);

tools_menu->addSeparator();
@@ -61,6 +61,7 @@ class MenuBar final : public QMenuBar
void FrameAdvance();
void Screenshot();
void StartNetPlay();
void BrowseNetPlay();
void StateLoad();
void StateSave();
void StateLoadSlot();
@@ -0,0 +1,243 @@
// Copyright 2019 Dolphin Emulator Project
// Licensed under GPLv2+
// Refer to the license.txt file included.

#include "DolphinQt/NetPlay/NetPlayBrowser.h"

#include <QComboBox>
#include <QDialogButtonBox>
#include <QGridLayout>
#include <QGroupBox>
#include <QHeaderView>
#include <QInputDialog>
#include <QLabel>
#include <QLineEdit>
#include <QPushButton>
#include <QRadioButton>
#include <QSpacerItem>
#include <QTableWidget>
#include <QTableWidgetItem>
#include <QVBoxLayout>

#include "Common/Version.h"

#include "Core/Config/NetplaySettings.h"
#include "Core/ConfigManager.h"

#include "DolphinQt/QtUtils/ModalMessageBox.h"

NetPlayBrowser::NetPlayBrowser(QWidget* parent) : QDialog(parent)
{
setWindowTitle(tr("NetPlay Session Browser"));
setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);

CreateWidgets();
ConnectWidgets();

resize(750, 500);

m_table_widget->verticalHeader()->setHidden(true);
m_table_widget->setAlternatingRowColors(true);

Refresh();
}

void NetPlayBrowser::CreateWidgets()
{
auto* layout = new QVBoxLayout;

m_table_widget = new QTableWidget;

m_table_widget->setSelectionBehavior(QAbstractItemView::SelectRows);
m_table_widget->setSelectionMode(QAbstractItemView::SingleSelection);

m_region_combo = new QComboBox;

m_region_combo->addItem(tr("Any Region"));

for (const auto& region : NetPlayIndex::GetRegions())
{
m_region_combo->addItem(
tr("%1 (%2)").arg(tr(region.second.c_str())).arg(QString::fromStdString(region.first)),
QString::fromStdString(region.first));
}

m_status_label = new QLabel;
m_button_box = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel);
m_button_refresh = new QPushButton(tr("Refresh"));
m_edit_name = new QLineEdit;
m_edit_game_id = new QLineEdit;

m_radio_all = new QRadioButton(tr("Private and Public"));
m_radio_private = new QRadioButton(tr("Private"));
m_radio_public = new QRadioButton(tr("Public"));

m_radio_all->setChecked(true);

auto* filter_box = new QGroupBox(tr("Filters"));
auto* filter_layout = new QGridLayout;
filter_box->setLayout(filter_layout);

filter_layout->addWidget(new QLabel(tr("Region:")), 0, 0);
filter_layout->addWidget(m_region_combo, 0, 1);
filter_layout->addWidget(new QLabel(tr("Name:")), 1, 0);
filter_layout->addWidget(m_edit_name, 1, 1, 1, -1);
filter_layout->addWidget(new QLabel(tr("Game ID:")), 2, 0);
filter_layout->addWidget(m_edit_game_id, 2, 1, 1, -1);
filter_layout->addWidget(m_radio_all, 3, 1);
filter_layout->addWidget(m_radio_public, 3, 2);
filter_layout->addWidget(m_radio_private, 3, 3);
filter_layout->addItem(new QSpacerItem(4, 1, QSizePolicy::Expanding), 2, 4);

layout->addWidget(m_table_widget);
layout->addWidget(filter_box);
layout->addWidget(m_status_label);
layout->addWidget(m_button_box);

m_button_box->addButton(m_button_refresh, QDialogButtonBox::ResetRole);
m_button_box->button(QDialogButtonBox::Ok)->setEnabled(false);

setLayout(layout);
}

void NetPlayBrowser::ConnectWidgets()
{
connect(m_button_box, &QDialogButtonBox::accepted, this, &NetPlayBrowser::accept);
connect(m_button_box, &QDialogButtonBox::rejected, this, &NetPlayBrowser::reject);
connect(m_button_refresh, &QPushButton::pressed, this, &NetPlayBrowser::Refresh);

connect(m_radio_all, &QRadioButton::toggled, this, &NetPlayBrowser::Refresh);
connect(m_radio_private, &QRadioButton::toggled, this, &NetPlayBrowser::Refresh);

connect(m_edit_name, &QLineEdit::textChanged, this, &NetPlayBrowser::Refresh);
connect(m_edit_game_id, &QLineEdit::textChanged, this, &NetPlayBrowser::Refresh);
connect(m_table_widget, &QTableWidget::itemSelectionChanged, this,
&NetPlayBrowser::OnSelectionChanged);
}

void NetPlayBrowser::Refresh()
{
m_status_label->setText(tr("Refreshing..."));

m_table_widget->clear();
m_table_widget->setColumnCount(6);
m_table_widget->setHorizontalHeaderLabels(
{tr("Region"), tr("Name"), tr("Password?"), tr("In-Game?"), tr("Game"), tr("Players")});
m_table_widget->horizontalHeader()->setSectionResizeMode(0, QHeaderView::ResizeToContents);
m_table_widget->horizontalHeader()->setSectionResizeMode(1, QHeaderView::Stretch);
m_table_widget->horizontalHeader()->setSectionResizeMode(2, QHeaderView::ResizeToContents);
m_table_widget->horizontalHeader()->setSectionResizeMode(3, QHeaderView::ResizeToContents);
m_table_widget->horizontalHeader()->setSectionResizeMode(4, QHeaderView::Stretch);

NetPlayIndex client;

std::map<std::string, std::string> filters;

filters["version"] = Common::scm_desc_str;

if (!m_edit_name->text().isEmpty())
filters["name"] = m_edit_name->text().toStdString();

if (!m_edit_game_id->text().isEmpty())
filters["game"] = m_edit_game_id->text().toStdString();

if (!m_radio_all->isChecked())
filters["password"] = std::to_string(m_radio_private->isChecked());

if (m_region_combo->currentIndex() != 0)
filters["region"] = m_region_combo->currentData().toString().toStdString();

auto entries = client.List(filters);

if (!entries)
{
m_status_label->setText(
tr("Error obtaining session list: %1").arg(QString::fromStdString(client.GetLastError())));
return;
}

const int session_count = static_cast<int>(entries.value().size());

m_table_widget->setRowCount(session_count);

for (int i = 0; i < session_count; i++)
{
const auto& entry = entries.value()[i];

auto* region = new QTableWidgetItem(QString::fromStdString(entry.region));
auto* name = new QTableWidgetItem(QString::fromStdString(entry.name));
auto* password = new QTableWidgetItem(entry.has_password ? tr("Yes") : tr("No"));
auto* in_game = new QTableWidgetItem(entry.in_game ? tr("Yes") : tr("No"));
auto* game_id = new QTableWidgetItem(QString::fromStdString(entry.game_id));
auto* player_count = new QTableWidgetItem(QStringLiteral("%1").arg(entry.player_count));

for (const auto& item : {region, name, password, game_id, player_count})
item->setFlags(Qt::ItemIsEnabled | Qt::ItemIsSelectable);

m_table_widget->setItem(i, 0, region);
m_table_widget->setItem(i, 1, name);
m_table_widget->setItem(i, 2, password);
m_table_widget->setItem(i, 3, in_game);
m_table_widget->setItem(i, 4, game_id);
m_table_widget->setItem(i, 5, player_count);
}

m_status_label->setText(
(session_count == 1 ? tr("%1 session found") : tr("%1 sessions found")).arg(session_count));

m_sessions = entries.value();
}

void NetPlayBrowser::OnSelectionChanged()
{
m_button_box->button(QDialogButtonBox::Ok)
->setEnabled(!m_table_widget->selectedItems().isEmpty());
}

void NetPlayBrowser::accept()
{
const int index = m_table_widget->selectedItems()[0]->row();

NetPlaySession& session = m_sessions[index];

std::string server_id = session.server_id;

if (m_sessions[index].has_password)
{
auto* dialog = new QInputDialog(this);

dialog->setWindowFlags(dialog->windowFlags() & ~Qt::WindowContextHelpButtonHint);
dialog->setWindowTitle(tr("Enter password"));
dialog->setLabelText(tr("This session requires a password:"));
dialog->setWindowModality(Qt::WindowModal);
dialog->setTextEchoMode(QLineEdit::Password);

if (dialog->exec() != QDialog::Accepted)
return;

const std::string password = dialog->textValue().toStdString();

auto decrypted_id = session.DecryptID(password);

if (!decrypted_id)
{
ModalMessageBox::warning(this, tr("Error"), tr("Invalid password provided."));
return;
}

server_id = decrypted_id.value();
}

QDialog::accept();

Config::SetBaseOrCurrent(Config::NETPLAY_TRAVERSAL_CHOICE, session.method);

Config::SetBaseOrCurrent(Config::NETPLAY_CONNECT_PORT, session.port);

if (session.method == "traversal")
Config::SetBaseOrCurrent(Config::NETPLAY_HOST_CODE, server_id);
else
Config::SetBaseOrCurrent(Config::NETPLAY_ADDRESS, server_id);

emit Join();
}

0 comments on commit 094bf0d

Please sign in to comment.
You can’t perform that action at this time.