// Copyright 2017 Citra Emulator Project // Licensed under GPLv2 or any later version // Refer to the license.txt file included. #include #include #include #include #include #include #include "citra_qt/main.h" #include "citra_qt/multiplayer/client_room.h" #include "citra_qt/multiplayer/direct_connect.h" #include "citra_qt/multiplayer/message.h" #include "citra_qt/multiplayer/state.h" #include "citra_qt/multiplayer/validation.h" #include "citra_qt/ui_settings.h" #include "core/settings.h" #include "network/network.h" #include "ui_direct_connect.h" enum class ConnectionType : u8 { TraversalServer, IP }; DirectConnectWindow::DirectConnectWindow(QWidget* parent) : QDialog(parent, Qt::WindowTitleHint | Qt::WindowCloseButtonHint | Qt::WindowSystemMenuHint), ui(new Ui::DirectConnect) { ui->setupUi(this); // setup the watcher for background connections watcher = new QFutureWatcher; connect(watcher, &QFutureWatcher::finished, this, &DirectConnectWindow::OnConnection); ui->nickname->setValidator(Validation::nickname); ui->nickname->setText(UISettings::values.nickname); ui->ip->setValidator(Validation::ip); ui->ip->setText(UISettings::values.ip); ui->port->setValidator(Validation::port); ui->port->setText(UISettings::values.port); // TODO(jroweboy): Show or hide the connection options based on the current value of the combo // box. Add this back in when the traversal server support is added. connect(ui->connect, &QPushButton::pressed, this, &DirectConnectWindow::Connect); } void DirectConnectWindow::Connect() { if (!ui->nickname->hasAcceptableInput()) { NetworkMessage::ShowError(NetworkMessage::USERNAME_NOT_VALID); return; } if (const auto member = Network::GetRoomMember().lock()) { if (member->IsConnected() && !NetworkMessage::WarnDisconnect()) { return; } } switch (static_cast(ui->connection_type->currentIndex())) { case ConnectionType::TraversalServer: break; case ConnectionType::IP: if (!ui->ip->hasAcceptableInput()) { NetworkMessage::ShowError(NetworkMessage::IP_ADDRESS_NOT_VALID); return; } if (!ui->port->hasAcceptableInput()) { NetworkMessage::ShowError(NetworkMessage::PORT_NOT_VALID); return; } break; } // Store settings UISettings::values.nickname = ui->nickname->text(); UISettings::values.ip = ui->ip->text(); UISettings::values.port = (ui->port->isModified() && !ui->port->text().isEmpty()) ? ui->port->text() : UISettings::values.port; Settings::Apply(); // attempt to connect in a different thread QFuture f = QtConcurrent::run([&] { if (auto room_member = Network::GetRoomMember().lock()) { auto port = UISettings::values.port.toUInt(); room_member->Join(ui->nickname->text().toStdString(), ui->ip->text().toStdString().c_str(), port, 0, Network::NoPreferredMac, ui->password->text().toStdString().c_str()); } }); watcher->setFuture(f); // and disable widgets and display a connecting while we wait BeginConnecting(); } void DirectConnectWindow::BeginConnecting() { ui->connect->setEnabled(false); ui->connect->setText(tr("Connecting")); } void DirectConnectWindow::EndConnecting() { ui->connect->setEnabled(true); ui->connect->setText(tr("Connect")); } void DirectConnectWindow::OnConnection() { EndConnecting(); bool isConnected = true; if (auto room_member = Network::GetRoomMember().lock()) { switch (room_member->GetState()) { case Network::RoomMember::State::CouldNotConnect: isConnected = false; ShowError(NetworkMessage::UNABLE_TO_CONNECT); break; case Network::RoomMember::State::NameCollision: isConnected = false; ShowError(NetworkMessage::USERNAME_IN_USE); break; case Network::RoomMember::State::Joining: auto parent = static_cast(parentWidget()); parent->OnOpenNetworkRoom(); close(); } } }