mirror of
https://github.com/dolphin-emu/dolphin.git
synced 2024-11-15 22:09:19 -07:00
fef1b84f0a
QStringLiterals generate a buffer so that during runtime there's very little cost to constructing a QString. However, this also means that duplicated strings cannot be optimized out into a single entry that gets referenced everywhere, taking up space in the binary. Rather than use QStringLiteral(""), we can just use QString{} (the default constructor) to signify the empty string. This gets rid of an unnecessary string buffer from being created, saving a tiny bit of space. While we're at it, we can just use the character overloads of particular functions when they're available instead of using a QString overload. The characters in this case are Latin-1 to begin with, so we can just specify the characters as QLatin1Char instances to use those overloads. These will automatically convert to QChar if needed, so this is safe.
373 lines
14 KiB
C++
373 lines
14 KiB
C++
// Copyright 2017 Dolphin Emulator Project
|
|
// Licensed under GPLv2+
|
|
// Refer to the license.txt file included.
|
|
|
|
#include "DolphinQt/NetPlay/NetPlaySetupDialog.h"
|
|
|
|
#include <QCheckBox>
|
|
#include <QComboBox>
|
|
#include <QDialogButtonBox>
|
|
#include <QGridLayout>
|
|
#include <QLabel>
|
|
#include <QLineEdit>
|
|
#include <QListWidget>
|
|
#include <QPushButton>
|
|
#include <QSignalBlocker>
|
|
#include <QSpinBox>
|
|
#include <QTabWidget>
|
|
|
|
#include "Core/Config/NetplaySettings.h"
|
|
|
|
#include "DolphinQt/GameList/GameListModel.h"
|
|
#include "DolphinQt/QtUtils/ModalMessageBox.h"
|
|
#include "DolphinQt/Settings.h"
|
|
|
|
#include "UICommon/NetPlayIndex.h"
|
|
|
|
NetPlaySetupDialog::NetPlaySetupDialog(QWidget* parent)
|
|
: QDialog(parent), m_game_list_model(Settings::Instance().GetGameListModel())
|
|
{
|
|
setWindowTitle(tr("NetPlay Setup"));
|
|
setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);
|
|
|
|
CreateMainLayout();
|
|
|
|
bool use_index = Config::Get(Config::NETPLAY_USE_INDEX);
|
|
std::string index_region = Config::Get(Config::NETPLAY_INDEX_REGION);
|
|
std::string index_name = Config::Get(Config::NETPLAY_INDEX_NAME);
|
|
std::string index_password = Config::Get(Config::NETPLAY_INDEX_PASSWORD);
|
|
std::string nickname = Config::Get(Config::NETPLAY_NICKNAME);
|
|
std::string traversal_choice = Config::Get(Config::NETPLAY_TRAVERSAL_CHOICE);
|
|
int connect_port = Config::Get(Config::NETPLAY_CONNECT_PORT);
|
|
int host_port = Config::Get(Config::NETPLAY_HOST_PORT);
|
|
int host_listen_port = Config::Get(Config::NETPLAY_LISTEN_PORT);
|
|
bool enable_chunked_upload_limit = Config::Get(Config::NETPLAY_ENABLE_CHUNKED_UPLOAD_LIMIT);
|
|
u32 chunked_upload_limit = Config::Get(Config::NETPLAY_CHUNKED_UPLOAD_LIMIT);
|
|
#ifdef USE_UPNP
|
|
bool use_upnp = Config::Get(Config::NETPLAY_USE_UPNP);
|
|
|
|
m_host_upnp->setChecked(use_upnp);
|
|
#endif
|
|
|
|
m_nickname_edit->setText(QString::fromStdString(nickname));
|
|
m_connection_type->setCurrentIndex(traversal_choice == "direct" ? 0 : 1);
|
|
m_connect_port_box->setValue(connect_port);
|
|
m_host_port_box->setValue(host_port);
|
|
|
|
m_host_force_port_box->setValue(host_listen_port);
|
|
m_host_force_port_box->setEnabled(false);
|
|
|
|
m_host_server_browser->setChecked(use_index);
|
|
|
|
m_host_server_region->setEnabled(use_index);
|
|
m_host_server_region->setCurrentIndex(
|
|
m_host_server_region->findData(QString::fromStdString(index_region)));
|
|
|
|
m_host_server_name->setEnabled(use_index);
|
|
m_host_server_name->setText(QString::fromStdString(index_name));
|
|
|
|
m_host_server_password->setEnabled(use_index);
|
|
m_host_server_password->setText(QString::fromStdString(index_password));
|
|
|
|
m_host_chunked_upload_limit_check->setChecked(enable_chunked_upload_limit);
|
|
m_host_chunked_upload_limit_box->setValue(chunked_upload_limit);
|
|
m_host_chunked_upload_limit_box->setEnabled(enable_chunked_upload_limit);
|
|
|
|
OnConnectionTypeChanged(m_connection_type->currentIndex());
|
|
|
|
ConnectWidgets();
|
|
}
|
|
|
|
void NetPlaySetupDialog::CreateMainLayout()
|
|
{
|
|
m_main_layout = new QGridLayout;
|
|
m_button_box = new QDialogButtonBox(QDialogButtonBox::Cancel);
|
|
m_nickname_edit = new QLineEdit;
|
|
m_connection_type = new QComboBox;
|
|
m_reset_traversal_button = new QPushButton(tr("Reset Traversal Settings"));
|
|
m_tab_widget = new QTabWidget;
|
|
|
|
// Connection widget
|
|
auto* connection_widget = new QWidget;
|
|
auto* connection_layout = new QGridLayout;
|
|
|
|
m_ip_label = new QLabel;
|
|
m_ip_edit = new QLineEdit;
|
|
m_connect_port_label = new QLabel(tr("Port:"));
|
|
m_connect_port_box = new QSpinBox;
|
|
m_connect_button = new QPushButton(tr("Connect"));
|
|
|
|
m_connect_port_box->setMaximum(65535);
|
|
|
|
connection_layout->addWidget(m_ip_label, 0, 0);
|
|
connection_layout->addWidget(m_ip_edit, 0, 1);
|
|
connection_layout->addWidget(m_connect_port_label, 0, 2);
|
|
connection_layout->addWidget(m_connect_port_box, 0, 3);
|
|
connection_layout->addWidget(
|
|
new QLabel(
|
|
tr("ALERT:\n\n"
|
|
"All players must use the same Dolphin version.\n"
|
|
"If enabled, SD cards must be identical between players.\n"
|
|
"If DSP LLE is used, DSP ROMs must be identical between players.\n"
|
|
"If a game is hanging on boot, it may not support Dual Core Netplay."
|
|
" Disable Dual Core.\n"
|
|
"If connecting directly, the host must have the chosen UDP port open/forwarded!\n"
|
|
"\n"
|
|
"Wii Remote support in netplay is experimental and may not work correctly.\n"
|
|
"Use at your own risk.\n")),
|
|
1, 0, -1, -1);
|
|
connection_layout->addWidget(m_connect_button, 3, 3, Qt::AlignRight);
|
|
|
|
connection_widget->setLayout(connection_layout);
|
|
|
|
// Host widget
|
|
auto* host_widget = new QWidget;
|
|
auto* host_layout = new QGridLayout;
|
|
m_host_port_label = new QLabel(tr("Port:"));
|
|
m_host_port_box = new QSpinBox;
|
|
m_host_force_port_check = new QCheckBox(tr("Force Listen Port:"));
|
|
m_host_force_port_box = new QSpinBox;
|
|
m_host_chunked_upload_limit_check = new QCheckBox(tr("Limit Chunked Upload Speed:"));
|
|
m_host_chunked_upload_limit_box = new QSpinBox;
|
|
m_host_server_browser = new QCheckBox(tr("Show in server browser"));
|
|
m_host_server_name = new QLineEdit;
|
|
m_host_server_password = new QLineEdit;
|
|
m_host_server_region = new QComboBox;
|
|
|
|
#ifdef USE_UPNP
|
|
m_host_upnp = new QCheckBox(tr("Forward port (UPnP)"));
|
|
#endif
|
|
m_host_games = new QListWidget;
|
|
m_host_button = new QPushButton(tr("Host"));
|
|
|
|
m_host_port_box->setMaximum(65535);
|
|
m_host_force_port_box->setMaximum(65535);
|
|
m_host_chunked_upload_limit_box->setRange(1, 1000000);
|
|
m_host_chunked_upload_limit_box->setSingleStep(100);
|
|
m_host_chunked_upload_limit_box->setSuffix(QStringLiteral(" kbps"));
|
|
|
|
m_host_chunked_upload_limit_check->setToolTip(tr(
|
|
"This will limit the speed of chunked uploading per client, which is used for save sync."));
|
|
|
|
m_host_server_name->setToolTip(tr("Name of your session shown in the server browser"));
|
|
m_host_server_name->setPlaceholderText(tr("Name"));
|
|
m_host_server_password->setToolTip(tr("Password for joining your game (leave empty for none)"));
|
|
m_host_server_password->setPlaceholderText(tr("Password"));
|
|
|
|
for (const auto& region : NetPlayIndex::GetRegions())
|
|
{
|
|
m_host_server_region->addItem(
|
|
tr("%1 (%2)").arg(tr(region.second.c_str())).arg(QString::fromStdString(region.first)),
|
|
QString::fromStdString(region.first));
|
|
}
|
|
|
|
host_layout->addWidget(m_host_port_label, 0, 0);
|
|
host_layout->addWidget(m_host_port_box, 0, 1);
|
|
#ifdef USE_UPNP
|
|
host_layout->addWidget(m_host_upnp, 0, 2);
|
|
#endif
|
|
host_layout->addWidget(m_host_server_browser, 1, 0);
|
|
host_layout->addWidget(m_host_server_region, 1, 1);
|
|
host_layout->addWidget(m_host_server_name, 1, 2);
|
|
host_layout->addWidget(m_host_server_password, 1, 3);
|
|
host_layout->addWidget(m_host_games, 2, 0, 1, -1);
|
|
host_layout->addWidget(m_host_force_port_check, 3, 0);
|
|
host_layout->addWidget(m_host_force_port_box, 3, 1, Qt::AlignLeft);
|
|
host_layout->addWidget(m_host_chunked_upload_limit_check, 4, 0);
|
|
host_layout->addWidget(m_host_chunked_upload_limit_box, 4, 1, Qt::AlignLeft);
|
|
host_layout->addWidget(m_host_button, 4, 3, 2, 1, Qt::AlignRight);
|
|
|
|
host_widget->setLayout(host_layout);
|
|
|
|
m_connection_type->addItem(tr("Direct Connection"));
|
|
m_connection_type->addItem(tr("Traversal Server"));
|
|
|
|
m_main_layout->addWidget(new QLabel(tr("Connection Type:")), 0, 0);
|
|
m_main_layout->addWidget(m_connection_type, 0, 1);
|
|
m_main_layout->addWidget(m_reset_traversal_button, 0, 2);
|
|
m_main_layout->addWidget(new QLabel(tr("Nickname:")), 1, 0);
|
|
m_main_layout->addWidget(m_nickname_edit, 1, 1);
|
|
m_main_layout->addWidget(m_tab_widget, 2, 0, 1, -1);
|
|
m_main_layout->addWidget(m_button_box, 3, 0, 1, -1);
|
|
|
|
// Tabs
|
|
m_tab_widget->addTab(connection_widget, tr("Connect"));
|
|
m_tab_widget->addTab(host_widget, tr("Host"));
|
|
|
|
setLayout(m_main_layout);
|
|
}
|
|
|
|
void NetPlaySetupDialog::ConnectWidgets()
|
|
{
|
|
connect(m_connection_type, static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged),
|
|
this, &NetPlaySetupDialog::OnConnectionTypeChanged);
|
|
connect(m_nickname_edit, &QLineEdit::textChanged, this, &NetPlaySetupDialog::SaveSettings);
|
|
|
|
// Connect widget
|
|
connect(m_ip_edit, &QLineEdit::textChanged, this, &NetPlaySetupDialog::SaveSettings);
|
|
connect(m_connect_port_box, static_cast<void (QSpinBox::*)(int)>(&QSpinBox::valueChanged), this,
|
|
&NetPlaySetupDialog::SaveSettings);
|
|
// Host widget
|
|
connect(m_host_port_box, static_cast<void (QSpinBox::*)(int)>(&QSpinBox::valueChanged), this,
|
|
&NetPlaySetupDialog::SaveSettings);
|
|
connect(m_host_games, static_cast<void (QListWidget::*)(int)>(&QListWidget::currentRowChanged),
|
|
[this](int index) {
|
|
Settings::GetQSettings().setValue(QStringLiteral("netplay/hostgame"),
|
|
m_host_games->item(index)->text());
|
|
});
|
|
|
|
connect(m_host_games, &QListWidget::itemDoubleClicked, this, &NetPlaySetupDialog::accept);
|
|
|
|
connect(m_host_force_port_check, &QCheckBox::toggled,
|
|
[this](bool value) { m_host_force_port_box->setEnabled(value); });
|
|
connect(m_host_chunked_upload_limit_check, &QCheckBox::toggled, this, [this](bool value) {
|
|
m_host_chunked_upload_limit_box->setEnabled(value);
|
|
SaveSettings();
|
|
});
|
|
connect(m_host_chunked_upload_limit_box,
|
|
static_cast<void (QSpinBox::*)(int)>(&QSpinBox::valueChanged), this,
|
|
&NetPlaySetupDialog::SaveSettings);
|
|
#ifdef USE_UPNP
|
|
connect(m_host_upnp, &QCheckBox::stateChanged, this, &NetPlaySetupDialog::SaveSettings);
|
|
#endif
|
|
|
|
connect(m_connect_button, &QPushButton::clicked, this, &QDialog::accept);
|
|
connect(m_host_button, &QPushButton::clicked, this, &QDialog::accept);
|
|
connect(m_button_box, &QDialogButtonBox::rejected, this, &QDialog::reject);
|
|
connect(m_reset_traversal_button, &QPushButton::clicked, this,
|
|
&NetPlaySetupDialog::ResetTraversalHost);
|
|
connect(m_host_server_browser, &QCheckBox::toggled, this, [this](bool value) {
|
|
m_host_server_region->setEnabled(value);
|
|
m_host_server_name->setEnabled(value);
|
|
m_host_server_password->setEnabled(value);
|
|
});
|
|
}
|
|
|
|
void NetPlaySetupDialog::SaveSettings()
|
|
{
|
|
Config::ConfigChangeCallbackGuard config_guard;
|
|
|
|
Config::SetBaseOrCurrent(Config::NETPLAY_NICKNAME, m_nickname_edit->text().toStdString());
|
|
Config::SetBaseOrCurrent(m_connection_type->currentIndex() == 0 ? Config::NETPLAY_ADDRESS :
|
|
Config::NETPLAY_HOST_CODE,
|
|
m_ip_edit->text().toStdString());
|
|
Config::SetBaseOrCurrent(Config::NETPLAY_CONNECT_PORT,
|
|
static_cast<u16>(m_connect_port_box->value()));
|
|
Config::SetBaseOrCurrent(Config::NETPLAY_HOST_PORT, static_cast<u16>(m_host_port_box->value()));
|
|
#ifdef USE_UPNP
|
|
Config::SetBaseOrCurrent(Config::NETPLAY_USE_UPNP, m_host_upnp->isChecked());
|
|
#endif
|
|
|
|
if (m_host_force_port_check->isChecked())
|
|
Config::SetBaseOrCurrent(Config::NETPLAY_LISTEN_PORT,
|
|
static_cast<u16>(m_host_force_port_box->value()));
|
|
|
|
Config::SetBaseOrCurrent(Config::NETPLAY_ENABLE_CHUNKED_UPLOAD_LIMIT,
|
|
m_host_chunked_upload_limit_check->isChecked());
|
|
Config::SetBaseOrCurrent(Config::NETPLAY_CHUNKED_UPLOAD_LIMIT,
|
|
m_host_chunked_upload_limit_box->value());
|
|
|
|
Config::SetBaseOrCurrent(Config::NETPLAY_USE_INDEX, m_host_server_browser->isChecked());
|
|
Config::SetBaseOrCurrent(Config::NETPLAY_INDEX_REGION,
|
|
m_host_server_region->currentData().toString().toStdString());
|
|
Config::SetBaseOrCurrent(Config::NETPLAY_INDEX_NAME, m_host_server_name->text().toStdString());
|
|
Config::SetBaseOrCurrent(Config::NETPLAY_INDEX_PASSWORD,
|
|
m_host_server_password->text().toStdString());
|
|
}
|
|
|
|
void NetPlaySetupDialog::OnConnectionTypeChanged(int index)
|
|
{
|
|
m_connect_port_box->setHidden(index != 0);
|
|
m_connect_port_label->setHidden(index != 0);
|
|
|
|
m_host_port_label->setHidden(index != 0);
|
|
m_host_port_box->setHidden(index != 0);
|
|
#ifdef USE_UPNP
|
|
m_host_upnp->setHidden(index != 0);
|
|
#endif
|
|
m_host_force_port_check->setHidden(index == 0);
|
|
m_host_force_port_box->setHidden(index == 0);
|
|
|
|
m_reset_traversal_button->setHidden(index == 0);
|
|
|
|
std::string address =
|
|
index == 0 ? Config::Get(Config::NETPLAY_ADDRESS) : Config::Get(Config::NETPLAY_HOST_CODE);
|
|
|
|
m_ip_label->setText(index == 0 ? tr("IP Address:") : tr("Host Code:"));
|
|
m_ip_edit->setText(QString::fromStdString(address));
|
|
|
|
Config::SetBaseOrCurrent(Config::NETPLAY_TRAVERSAL_CHOICE,
|
|
std::string(index == 0 ? "direct" : "traversal"));
|
|
}
|
|
|
|
void NetPlaySetupDialog::show()
|
|
{
|
|
PopulateGameList();
|
|
QDialog::show();
|
|
}
|
|
|
|
void NetPlaySetupDialog::accept()
|
|
{
|
|
SaveSettings();
|
|
if (m_tab_widget->currentIndex() == 0)
|
|
{
|
|
emit Join();
|
|
}
|
|
else
|
|
{
|
|
auto items = m_host_games->selectedItems();
|
|
if (items.empty())
|
|
{
|
|
ModalMessageBox::critical(this, tr("Error"), tr("You must select a game to host!"));
|
|
return;
|
|
}
|
|
|
|
if (m_host_server_browser->isChecked() && m_host_server_name->text().isEmpty())
|
|
{
|
|
ModalMessageBox::critical(this, tr("Error"), tr("You must provide a name for your session!"));
|
|
return;
|
|
}
|
|
|
|
emit Host(items[0]->text());
|
|
}
|
|
}
|
|
|
|
void NetPlaySetupDialog::PopulateGameList()
|
|
{
|
|
QSignalBlocker blocker(m_host_games);
|
|
|
|
m_host_games->clear();
|
|
for (int i = 0; i < m_game_list_model->rowCount(QModelIndex()); i++)
|
|
{
|
|
auto title = m_game_list_model->GetUniqueIdentifier(i);
|
|
auto path = m_game_list_model->GetPath(i);
|
|
|
|
auto* item = new QListWidgetItem(title);
|
|
item->setData(Qt::UserRole, path);
|
|
m_host_games->addItem(item);
|
|
}
|
|
|
|
m_host_games->sortItems();
|
|
|
|
const QString selected_game =
|
|
Settings::GetQSettings().value(QStringLiteral("netplay/hostgame"), QString{}).toString();
|
|
const auto find_list = m_host_games->findItems(selected_game, Qt::MatchFlag::MatchExactly);
|
|
|
|
if (find_list.count() > 0)
|
|
m_host_games->setCurrentItem(find_list[0]);
|
|
}
|
|
|
|
void NetPlaySetupDialog::ResetTraversalHost()
|
|
{
|
|
Config::SetBaseOrCurrent(Config::NETPLAY_TRAVERSAL_SERVER,
|
|
Config::NETPLAY_TRAVERSAL_SERVER.default_value);
|
|
Config::SetBaseOrCurrent(Config::NETPLAY_TRAVERSAL_PORT,
|
|
Config::NETPLAY_TRAVERSAL_PORT.default_value);
|
|
|
|
ModalMessageBox::information(
|
|
this, tr("Reset Traversal Server"),
|
|
tr("Reset Traversal Server to %1:%2")
|
|
.arg(QString::fromStdString(Config::NETPLAY_TRAVERSAL_SERVER.default_value),
|
|
QString::number(Config::NETPLAY_TRAVERSAL_PORT.default_value)));
|
|
}
|