2
1
Fork 0
mirror of https://github.com/yuzu-emu/yuzu.git synced 2024-07-04 23:31:19 +01:00

Merge pull request #6863 from spholz/fix-lan-play

Fix LAN Play
This commit is contained in:
Fernando S 2021-08-16 17:10:00 +02:00 committed by GitHub
commit 521e6ac174
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
16 changed files with 409 additions and 103 deletions

View file

@ -701,7 +701,7 @@ if (APPLE)
elseif (WIN32)
# WSAPoll and SHGetKnownFolderPath (AppData/Roaming) didn't exist before WinNT 6.x (Vista)
add_definitions(-D_WIN32_WINNT=0x0600 -DWINVER=0x0600)
set(PLATFORM_LIBRARIES winmm ws2_32)
set(PLATFORM_LIBRARIES winmm ws2_32 iphlpapi)
if (MINGW)
# PSAPI is the Process Status API
set(PLATFORM_LIBRARIES ${PLATFORM_LIBRARIES} psapi imm32 version)

View file

@ -558,9 +558,10 @@ struct Values {
BasicSetting<std::string> log_filter{"*:Info", "log_filter"};
BasicSetting<bool> use_dev_keys{false, "use_dev_keys"};
// Services
// Network
BasicSetting<std::string> bcat_backend{"none", "bcat_backend"};
BasicSetting<bool> bcat_boxcat_local{false, "bcat_boxcat_local"};
BasicSetting<std::string> network_interface{std::string(), "network_interface"};
// WebService
BasicSetting<bool> enable_telemetry{true, "enable_telemetry"};

View file

@ -636,6 +636,8 @@ add_library(core STATIC
memory.h
network/network.cpp
network/network.h
network/network_interface.cpp
network/network_interface.h
network/sockets.h
perf_stats.cpp
perf_stats.h

View file

@ -11,6 +11,7 @@
#include "core/hle/service/nifm/nifm.h"
#include "core/hle/service/service.h"
#include "core/network/network.h"
#include "core/network/network_interface.h"
namespace Service::NIFM {
@ -179,10 +180,10 @@ private:
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(ResultSuccess);
if (Settings::values.bcat_backend.GetValue() == "none") {
rb.PushEnum(RequestState::NotSubmitted);
} else {
if (Network::GetHostIPv4Address().has_value()) {
rb.PushEnum(RequestState::Connected);
} else {
rb.PushEnum(RequestState::NotSubmitted);
}
}
@ -322,12 +323,15 @@ private:
void GetCurrentIpAddress(Kernel::HLERequestContext& ctx) {
LOG_WARNING(Service_NIFM, "(STUBBED) called");
const auto [ipv4, error] = Network::GetHostIPv4Address();
UNIMPLEMENTED_IF(error != Network::Errno::SUCCESS);
auto ipv4 = Network::GetHostIPv4Address();
if (!ipv4) {
LOG_ERROR(Service_NIFM, "Couldn't get host IPv4 address, defaulting to 0.0.0.0");
ipv4.emplace(Network::IPv4Address{0, 0, 0, 0});
}
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(ResultSuccess);
rb.PushRaw(ipv4);
rb.PushRaw(*ipv4);
}
void CreateTemporaryNetworkProfile(Kernel::HLERequestContext& ctx) {
LOG_DEBUG(Service_NIFM, "called");
@ -354,10 +358,10 @@ private:
static_assert(sizeof(IpConfigInfo) == sizeof(IpAddressSetting) + sizeof(DnsSetting),
"IpConfigInfo has incorrect size.");
const IpConfigInfo ip_config_info{
IpConfigInfo ip_config_info{
.ip_address_setting{
.is_automatic{true},
.current_address{192, 168, 1, 100},
.current_address{0, 0, 0, 0},
.subnet_mask{255, 255, 255, 0},
.gateway{192, 168, 1, 1},
},
@ -368,6 +372,19 @@ private:
},
};
const auto iface = Network::GetSelectedNetworkInterface();
if (iface) {
ip_config_info.ip_address_setting =
IpAddressSetting{.is_automatic{true},
.current_address{Network::TranslateIPv4(iface->ip_address)},
.subnet_mask{Network::TranslateIPv4(iface->subnet_mask)},
.gateway{Network::TranslateIPv4(iface->gateway)}};
} else {
LOG_ERROR(Service_NIFM,
"Couldn't get host network configuration info, using default values");
}
IPC::ResponseBuilder rb{ctx, 2 + (sizeof(IpConfigInfo) + 3) / sizeof(u32)};
rb.Push(ResultSuccess);
rb.PushRaw<IpConfigInfo>(ip_config_info);
@ -384,10 +401,10 @@ private:
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(ResultSuccess);
if (Settings::values.bcat_backend.GetValue() == "none") {
rb.Push<u8>(0);
} else {
if (Network::GetHostIPv4Address().has_value()) {
rb.Push<u8>(1);
} else {
rb.Push<u8>(0);
}
}
void IsAnyInternetRequestAccepted(Kernel::HLERequestContext& ctx) {
@ -395,10 +412,10 @@ private:
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(ResultSuccess);
if (Settings::values.bcat_backend.GetValue() == "none") {
rb.Push<u8>(0);
} else {
if (Network::GetHostIPv4Address().has_value()) {
rb.Push<u8>(1);
} else {
rb.Push<u8>(0);
}
}
};

View file

@ -10,9 +10,10 @@
#include "common/common_funcs.h"
#ifdef _WIN32
#define _WINSOCK_DEPRECATED_NO_WARNINGS // gethostname
#include <winsock2.h>
#include <ws2tcpip.h>
#elif YUZU_UNIX
#include <arpa/inet.h>
#include <errno.h>
#include <fcntl.h>
#include <netdb.h>
@ -27,7 +28,9 @@
#include "common/assert.h"
#include "common/common_types.h"
#include "common/logging/log.h"
#include "common/settings.h"
#include "core/network/network.h"
#include "core/network/network_interface.h"
#include "core/network/sockets.h"
namespace Network {
@ -47,11 +50,6 @@ void Finalize() {
WSACleanup();
}
constexpr IPv4Address TranslateIPv4(in_addr addr) {
auto& bytes = addr.S_un.S_un_b;
return IPv4Address{bytes.s_b1, bytes.s_b2, bytes.s_b3, bytes.s_b4};
}
sockaddr TranslateFromSockAddrIn(SockAddrIn input) {
sockaddr_in result;
@ -138,12 +136,6 @@ void Initialize() {}
void Finalize() {}
constexpr IPv4Address TranslateIPv4(in_addr addr) {
const u32 bytes = addr.s_addr;
return IPv4Address{static_cast<u8>(bytes), static_cast<u8>(bytes >> 8),
static_cast<u8>(bytes >> 16), static_cast<u8>(bytes >> 24)};
}
sockaddr TranslateFromSockAddrIn(SockAddrIn input) {
sockaddr_in result;
@ -182,7 +174,7 @@ linger MakeLinger(bool enable, u32 linger_value) {
}
bool EnableNonBlock(int fd, bool enable) {
int flags = fcntl(fd, F_GETFD);
int flags = fcntl(fd, F_GETFL);
if (flags == -1) {
return false;
}
@ -191,7 +183,7 @@ bool EnableNonBlock(int fd, bool enable) {
} else {
flags &= ~O_NONBLOCK;
}
return fcntl(fd, F_SETFD, flags) == 0;
return fcntl(fd, F_SETFL, flags) == 0;
}
Errno TranslateNativeError(int e) {
@ -227,8 +219,12 @@ Errno GetAndLogLastError() {
#else
int e = errno;
#endif
const Errno err = TranslateNativeError(e);
if (err == Errno::AGAIN) {
return err;
}
LOG_ERROR(Network, "Socket operation error: {}", NativeErrorToString(e));
return TranslateNativeError(e);
return err;
}
int TranslateDomain(Domain domain) {
@ -353,27 +349,29 @@ NetworkInstance::~NetworkInstance() {
Finalize();
}
std::pair<IPv4Address, Errno> GetHostIPv4Address() {
std::array<char, 256> name{};
if (gethostname(name.data(), static_cast<int>(name.size()) - 1) == SOCKET_ERROR) {
return {IPv4Address{}, GetAndLogLastError()};
std::optional<IPv4Address> GetHostIPv4Address() {
const std::string& selected_network_interface = Settings::values.network_interface.GetValue();
const auto network_interfaces = Network::GetAvailableNetworkInterfaces();
if (network_interfaces.size() == 0) {
LOG_ERROR(Network, "GetAvailableNetworkInterfaces returned no interfaces");
return {};
}
hostent* const ent = gethostbyname(name.data());
if (!ent) {
return {IPv4Address{}, GetAndLogLastError()};
}
if (ent->h_addr_list == nullptr) {
UNIMPLEMENTED_MSG("No addr provided in hostent->h_addr_list");
return {IPv4Address{}, Errno::SUCCESS};
}
if (ent->h_length != sizeof(in_addr)) {
UNIMPLEMENTED_MSG("Unexpected size={} in hostent->h_length", ent->h_length);
}
const auto res =
std::ranges::find_if(network_interfaces, [&selected_network_interface](const auto& iface) {
return iface.name == selected_network_interface;
});
in_addr addr;
std::memcpy(&addr, ent->h_addr_list[0], sizeof(addr));
return {TranslateIPv4(addr), Errno::SUCCESS};
if (res != network_interfaces.end()) {
char ip_addr[16] = {};
ASSERT(inet_ntop(AF_INET, &res->ip_address, ip_addr, sizeof(ip_addr)) != nullptr);
LOG_INFO(Network, "IP address: {}", ip_addr);
return TranslateIPv4(res->ip_address);
} else {
LOG_ERROR(Network, "Couldn't find selected interface \"{}\"", selected_network_interface);
return {};
}
}
std::pair<s32, Errno> Poll(std::vector<PollFD>& pollfds, s32 timeout) {

View file

@ -5,11 +5,18 @@
#pragma once
#include <array>
#include <optional>
#include <utility>
#include "common/common_funcs.h"
#include "common/common_types.h"
#ifdef _WIN32
#include <winsock2.h>
#elif YUZU_UNIX
#include <netinet/in.h>
#endif
namespace Network {
class Socket;
@ -92,8 +99,21 @@ public:
~NetworkInstance();
};
#ifdef _WIN32
constexpr IPv4Address TranslateIPv4(in_addr addr) {
auto& bytes = addr.S_un.S_un_b;
return IPv4Address{bytes.s_b1, bytes.s_b2, bytes.s_b3, bytes.s_b4};
}
#elif YUZU_UNIX
constexpr IPv4Address TranslateIPv4(in_addr addr) {
const u32 bytes = addr.s_addr;
return IPv4Address{static_cast<u8>(bytes), static_cast<u8>(bytes >> 8),
static_cast<u8>(bytes >> 16), static_cast<u8>(bytes >> 24)};
}
#endif
/// @brief Returns host's IPv4 address
/// @return Pair of an array of human ordered IPv4 address (e.g. 192.168.0.1) and an error code
std::pair<IPv4Address, Errno> GetHostIPv4Address();
/// @return human ordered IPv4 address (e.g. 192.168.0.1) as an array
std::optional<IPv4Address> GetHostIPv4Address();
} // namespace Network

View file

@ -0,0 +1,203 @@
// Copyright 2021 yuzu emulator team
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#include <algorithm>
#include <fstream>
#include <sstream>
#include <vector>
#include "common/bit_cast.h"
#include "common/common_types.h"
#include "common/logging/log.h"
#include "common/settings.h"
#include "common/string_util.h"
#include "core/network/network_interface.h"
#ifdef _WIN32
#include <iphlpapi.h>
#else
#include <cerrno>
#include <ifaddrs.h>
#include <net/if.h>
#endif
namespace Network {
#ifdef _WIN32
std::vector<NetworkInterface> GetAvailableNetworkInterfaces() {
std::vector<IP_ADAPTER_ADDRESSES> adapter_addresses;
DWORD ret = ERROR_BUFFER_OVERFLOW;
DWORD buf_size = 0;
// retry up to 5 times
for (int i = 0; i < 5 && ret == ERROR_BUFFER_OVERFLOW; i++) {
ret = GetAdaptersAddresses(
AF_INET, GAA_FLAG_SKIP_MULTICAST | GAA_FLAG_SKIP_DNS_SERVER | GAA_FLAG_INCLUDE_GATEWAYS,
nullptr, adapter_addresses.data(), &buf_size);
if (ret == ERROR_BUFFER_OVERFLOW) {
adapter_addresses.resize((buf_size / sizeof(IP_ADAPTER_ADDRESSES)) + 1);
} else {
break;
}
}
if (ret == NO_ERROR) {
std::vector<NetworkInterface> result;
for (auto current_address = adapter_addresses.data(); current_address != nullptr;
current_address = current_address->Next) {
if (current_address->FirstUnicastAddress == nullptr ||
current_address->FirstUnicastAddress->Address.lpSockaddr == nullptr) {
continue;
}
if (current_address->OperStatus != IfOperStatusUp) {
continue;
}
const auto ip_addr = Common::BitCast<struct sockaddr_in>(
*current_address->FirstUnicastAddress->Address.lpSockaddr)
.sin_addr;
ULONG mask = 0;
if (ConvertLengthToIpv4Mask(current_address->FirstUnicastAddress->OnLinkPrefixLength,
&mask) != NO_ERROR) {
LOG_ERROR(Network, "Failed to convert IPv4 prefix length to subnet mask");
continue;
}
struct in_addr gateway = {.S_un{.S_addr{0}}};
if (current_address->FirstGatewayAddress != nullptr &&
current_address->FirstGatewayAddress->Address.lpSockaddr != nullptr) {
gateway = Common::BitCast<struct sockaddr_in>(
*current_address->FirstGatewayAddress->Address.lpSockaddr)
.sin_addr;
}
result.push_back(NetworkInterface{
.name{Common::UTF16ToUTF8(std::wstring{current_address->FriendlyName})},
.ip_address{ip_addr},
.subnet_mask = in_addr{.S_un{.S_addr{mask}}},
.gateway = gateway});
}
return result;
} else {
LOG_ERROR(Network, "Failed to get network interfaces with GetAdaptersAddresses");
return {};
}
}
#else
std::vector<NetworkInterface> GetAvailableNetworkInterfaces() {
std::vector<NetworkInterface> result;
struct ifaddrs* ifaddr = nullptr;
if (getifaddrs(&ifaddr) != 0) {
LOG_ERROR(Network, "Failed to get network interfaces with getifaddrs: {}",
std::strerror(errno));
return result;
}
for (auto ifa = ifaddr; ifa != nullptr; ifa = ifa->ifa_next) {
if (ifa->ifa_addr == nullptr || ifa->ifa_netmask == nullptr) {
continue;
}
if (ifa->ifa_addr->sa_family != AF_INET) {
continue;
}
if ((ifa->ifa_flags & IFF_UP) == 0 || (ifa->ifa_flags & IFF_LOOPBACK) != 0) {
continue;
}
std::uint32_t gateway{0};
std::ifstream file{"/proc/net/route"};
if (file.is_open()) {
// ignore header
file.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
bool gateway_found = false;
for (std::string line; std::getline(file, line);) {
std::istringstream iss{line};
std::string iface_name{};
iss >> iface_name;
if (iface_name != ifa->ifa_name) {
continue;
}
iss >> std::hex;
std::uint32_t dest{0};
iss >> dest;
if (dest != 0) {
// not the default route
continue;
}
iss >> gateway;
std::uint16_t flags{0};
iss >> flags;
// flag RTF_GATEWAY (defined in <linux/route.h>)
if ((flags & 0x2) == 0) {
continue;
}
gateway_found = true;
break;
}
if (!gateway_found) {
gateway = 0;
}
} else {
LOG_ERROR(Network, "Failed to open \"/proc/net/route\"");
}
result.push_back(NetworkInterface{
.name{ifa->ifa_name},
.ip_address{Common::BitCast<struct sockaddr_in>(*ifa->ifa_addr).sin_addr},
.subnet_mask{Common::BitCast<struct sockaddr_in>(*ifa->ifa_netmask).sin_addr},
.gateway{in_addr{.s_addr = gateway}}});
}
freeifaddrs(ifaddr);
return result;
}
#endif
std::optional<NetworkInterface> GetSelectedNetworkInterface() {
const std::string& selected_network_interface = Settings::values.network_interface.GetValue();
const auto network_interfaces = Network::GetAvailableNetworkInterfaces();
if (network_interfaces.size() == 0) {
LOG_ERROR(Network, "GetAvailableNetworkInterfaces returned no interfaces");
return {};
}
const auto res =
std::ranges::find_if(network_interfaces, [&selected_network_interface](const auto& iface) {
return iface.name == selected_network_interface;
});
if (res != network_interfaces.end()) {
return *res;
} else {
LOG_ERROR(Network, "Couldn't find selected interface \"{}\"", selected_network_interface);
return {};
}
}
} // namespace Network

View file

@ -0,0 +1,29 @@
// Copyright 2021 yuzu emulator team
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#pragma once
#include <optional>
#include <string>
#include <vector>
#ifdef _WIN32
#include <winsock2.h>
#else
#include <netinet/in.h>
#endif
namespace Network {
struct NetworkInterface {
std::string name;
struct in_addr ip_address;
struct in_addr subnet_mask;
struct in_addr gateway;
};
std::vector<NetworkInterface> GetAvailableNetworkInterfaces();
std::optional<NetworkInterface> GetSelectedNetworkInterface();
} // namespace Network

View file

@ -102,9 +102,9 @@ add_executable(yuzu
configuration/configure_profile_manager.cpp
configuration/configure_profile_manager.h
configuration/configure_profile_manager.ui
configuration/configure_service.cpp
configuration/configure_service.h
configuration/configure_service.ui
configuration/configure_network.cpp
configuration/configure_network.h
configuration/configure_network.ui
configuration/configure_system.cpp
configuration/configure_system.h
configuration/configure_system.ui

View file

@ -692,6 +692,7 @@ void Config::ReadServiceValues() {
qt_config->beginGroup(QStringLiteral("Services"));
ReadBasicSetting(Settings::values.bcat_backend);
ReadBasicSetting(Settings::values.bcat_boxcat_local);
ReadBasicSetting(Settings::values.network_interface);
qt_config->endGroup();
}
@ -1144,7 +1145,7 @@ void Config::SaveValues() {
SaveDataStorageValues();
SaveDebuggingValues();
SaveDisabledAddOnValues();
SaveServiceValues();
SaveNetworkValues();
SaveUIValues();
SaveWebServiceValues();
SaveMiscellaneousValues();
@ -1238,11 +1239,12 @@ void Config::SaveDebuggingValues() {
qt_config->endGroup();
}
void Config::SaveServiceValues() {
void Config::SaveNetworkValues() {
qt_config->beginGroup(QStringLiteral("Services"));
WriteBasicSetting(Settings::values.bcat_backend);
WriteBasicSetting(Settings::values.bcat_boxcat_local);
WriteBasicSetting(Settings::values.network_interface);
qt_config->endGroup();
}

View file

@ -88,7 +88,7 @@ private:
void SaveCoreValues();
void SaveDataStorageValues();
void SaveDebuggingValues();
void SaveServiceValues();
void SaveNetworkValues();
void SaveDisabledAddOnValues();
void SaveMiscellaneousValues();
void SavePathValues();

View file

@ -147,12 +147,12 @@
<string>Web</string>
</attribute>
</widget>
<widget class="ConfigureService" name="serviceTab">
<widget class="ConfigureNetwork" name="networkTab">
<property name="accessibleName">
<string>Services</string>
<string>Network</string>
</property>
<attribute name="title">
<string>Services</string>
<string>Network</string>
</attribute>
</widget>
</widget>
@ -242,9 +242,9 @@
<container>1</container>
</customwidget>
<customwidget>
<class>ConfigureService</class>
<class>ConfigureNetwork</class>
<extends>QWidget</extends>
<header>configuration/configure_service.h</header>
<header>configuration/configure_network.h</header>
<container>1</container>
</customwidget>
<customwidget>

View file

@ -67,7 +67,7 @@ void ConfigureDialog::ApplyConfiguration() {
ui->audioTab->ApplyConfiguration();
ui->debugTab->ApplyConfiguration();
ui->webTab->ApplyConfiguration();
ui->serviceTab->ApplyConfiguration();
ui->networkTab->ApplyConfiguration();
Core::System::GetInstance().ApplySettings();
Settings::LogSettings();
}
@ -103,7 +103,7 @@ Q_DECLARE_METATYPE(QList<QWidget*>);
void ConfigureDialog::PopulateSelectionList() {
const std::array<std::pair<QString, QList<QWidget*>>, 6> items{
{{tr("General"), {ui->generalTab, ui->hotkeysTab, ui->uiTab, ui->webTab, ui->debugTab}},
{tr("System"), {ui->systemTab, ui->profileManagerTab, ui->serviceTab, ui->filesystemTab}},
{tr("System"), {ui->systemTab, ui->profileManagerTab, ui->networkTab, ui->filesystemTab}},
{tr("CPU"), {ui->cpuTab}},
{tr("Graphics"), {ui->graphicsTab, ui->graphicsAdvancedTab}},
{tr("Audio"), {ui->audioTab}},

View file

@ -5,9 +5,11 @@
#include <QGraphicsItem>
#include <QtConcurrent/QtConcurrent>
#include "common/settings.h"
#include "core/core.h"
#include "core/hle/service/bcat/backend/boxcat.h"
#include "ui_configure_service.h"
#include "yuzu/configuration/configure_service.h"
#include "core/network/network_interface.h"
#include "ui_configure_network.h"
#include "yuzu/configuration/configure_network.h"
#ifdef YUZU_ENABLE_BOXCAT
namespace {
@ -35,8 +37,8 @@ QString FormatEventStatusString(const Service::BCAT::EventStatus& status) {
} // Anonymous namespace
#endif
ConfigureService::ConfigureService(QWidget* parent)
: QWidget(parent), ui(std::make_unique<Ui::ConfigureService>()) {
ConfigureNetwork::ConfigureNetwork(QWidget* parent)
: QWidget(parent), ui(std::make_unique<Ui::ConfigureNetwork>()) {
ui->setupUi(this);
ui->bcat_source->addItem(QStringLiteral("None"));
@ -47,29 +49,42 @@ ConfigureService::ConfigureService(QWidget* parent)
ui->bcat_source->addItem(QStringLiteral("Boxcat"), QStringLiteral("boxcat"));
#endif
ui->network_interface->addItem(tr("None"));
for (const auto& iface : Network::GetAvailableNetworkInterfaces()) {
ui->network_interface->addItem(QString::fromStdString(iface.name));
}
connect(ui->bcat_source, QOverload<int>::of(&QComboBox::currentIndexChanged), this,
&ConfigureService::OnBCATImplChanged);
&ConfigureNetwork::OnBCATImplChanged);
this->SetConfiguration();
}
ConfigureService::~ConfigureService() = default;
ConfigureNetwork::~ConfigureNetwork() = default;
void ConfigureService::ApplyConfiguration() {
void ConfigureNetwork::ApplyConfiguration() {
Settings::values.bcat_backend = ui->bcat_source->currentText().toLower().toStdString();
Settings::values.network_interface = ui->network_interface->currentText().toStdString();
}
void ConfigureService::RetranslateUi() {
void ConfigureNetwork::RetranslateUi() {
ui->retranslateUi(this);
}
void ConfigureService::SetConfiguration() {
void ConfigureNetwork::SetConfiguration() {
const bool runtime_lock = !Core::System::GetInstance().IsPoweredOn();
const int index =
ui->bcat_source->findData(QString::fromStdString(Settings::values.bcat_backend.GetValue()));
ui->bcat_source->setCurrentIndex(index == -1 ? 0 : index);
const std::string& network_interface = Settings::values.network_interface.GetValue();
ui->network_interface->setCurrentText(QString::fromStdString(network_interface));
ui->network_interface->setEnabled(runtime_lock);
}
std::pair<QString, QString> ConfigureService::BCATDownloadEvents() {
std::pair<QString, QString> ConfigureNetwork::BCATDownloadEvents() {
#ifdef YUZU_ENABLE_BOXCAT
std::optional<std::string> global;
std::map<std::string, Service::BCAT::EventStatus> map;
@ -114,7 +129,7 @@ std::pair<QString, QString> ConfigureService::BCATDownloadEvents() {
#endif
}
void ConfigureService::OnBCATImplChanged() {
void ConfigureNetwork::OnBCATImplChanged() {
#ifdef YUZU_ENABLE_BOXCAT
const auto boxcat = ui->bcat_source->currentText() == QStringLiteral("Boxcat");
ui->bcat_empty_header->setHidden(!boxcat);
@ -133,7 +148,7 @@ void ConfigureService::OnBCATImplChanged() {
#endif
}
void ConfigureService::OnUpdateBCATEmptyLabel(std::pair<QString, QString> string) {
void ConfigureNetwork::OnUpdateBCATEmptyLabel(std::pair<QString, QString> string) {
#ifdef YUZU_ENABLE_BOXCAT
const auto boxcat = ui->bcat_source->currentText() == QStringLiteral("Boxcat");
if (boxcat) {

View file

@ -9,15 +9,15 @@
#include <QWidget>
namespace Ui {
class ConfigureService;
class ConfigureNetwork;
}
class ConfigureService : public QWidget {
class ConfigureNetwork : public QWidget {
Q_OBJECT
public:
explicit ConfigureService(QWidget* parent = nullptr);
~ConfigureService() override;
explicit ConfigureNetwork(QWidget* parent = nullptr);
~ConfigureNetwork() override;
void ApplyConfiguration();
void RetranslateUi();
@ -29,6 +29,6 @@ private:
void OnBCATImplChanged();
void OnUpdateBCATEmptyLabel(std::pair<QString, QString> string);
std::unique_ptr<Ui::ConfigureService> ui;
std::unique_ptr<Ui::ConfigureNetwork> ui;
QFutureWatcher<std::pair<QString, QString>> watcher{this};
};

View file

@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>ConfigureService</class>
<widget class="QWidget" name="ConfigureService">
<class>ConfigureNetwork</class>
<widget class="QWidget" name="ConfigureNetwork">
<property name="geometry">
<rect>
<x>0</x>
@ -16,22 +16,38 @@
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<layout class="QVBoxLayout" name="verticalLayout_3">
<item>
<widget class="QGroupBox" name="groupBox_2">
<property name="title">
<string>General</string>
</property>
<layout class="QGridLayout" name="gridLayout_2">
<item row="1" column="1">
<widget class="QComboBox" name="network_interface"/>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_4">
<property name="text">
<string>Network Interface</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="groupBox">
<property name="title">
<string>BCAT</string>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="1" column="1" colspan="2">
<widget class="QLabel" name="label_2">
<property name="maximumSize">
<size>
<width>260</width>
<height>16777215</height>
</size>
</property>
<item row="3" column="0">
<widget class="QLabel" name="bcat_empty_header">
<property name="text">
<string>BCAT is Nintendo's way of sending data to games to engage its community and unlock additional content.</string>
<string/>
</property>
<property name="alignment">
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set>
</property>
<property name="wordWrap">
<bool>true</bool>
@ -51,11 +67,8 @@
</property>
</widget>
</item>
<item row="3" column="1" colspan="2">
<widget class="QLabel" name="bcat_empty_label">
<property name="enabled">
<bool>true</bool>
</property>
<item row="1" column="1" colspan="2">
<widget class="QLabel" name="label_2">
<property name="maximumSize">
<size>
<width>260</width>
@ -63,10 +76,7 @@
</size>
</property>
<property name="text">
<string/>
</property>
<property name="alignment">
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set>
<string>BCAT is Nintendo's way of sending data to games to engage its community and unlock additional content.</string>
</property>
<property name="wordWrap">
<bool>true</bool>
@ -86,8 +96,17 @@
<item row="0" column="1" colspan="2">
<widget class="QComboBox" name="bcat_source"/>
</item>
<item row="3" column="0">
<widget class="QLabel" name="bcat_empty_header">
<item row="3" column="1" colspan="2">
<widget class="QLabel" name="bcat_empty_label">
<property name="enabled">
<bool>true</bool>
</property>
<property name="maximumSize">
<size>
<width>260</width>
<height>16777215</height>
</size>
</property>
<property name="text">
<string/>
</property>