configuration: add option to select network interface
This commit renames the "Services" tab to "Network" and adds a combobox that allows the user to select the network interface that yuzu should use. This new setting is now used to get the local IP address in Network::GetHostIPv4Address. This prevents yuzu from selecting the wrong network interface and thus using the wrong IP address. The return type of Network::GetHostIPv4Adress has also been changed.
This commit is contained in:
parent
33ebe471e8
commit
1e98e73828
|
@ -701,7 +701,7 @@ if (APPLE)
|
||||||
elseif (WIN32)
|
elseif (WIN32)
|
||||||
# WSAPoll and SHGetKnownFolderPath (AppData/Roaming) didn't exist before WinNT 6.x (Vista)
|
# WSAPoll and SHGetKnownFolderPath (AppData/Roaming) didn't exist before WinNT 6.x (Vista)
|
||||||
add_definitions(-D_WIN32_WINNT=0x0600 -DWINVER=0x0600)
|
add_definitions(-D_WIN32_WINNT=0x0600 -DWINVER=0x0600)
|
||||||
set(PLATFORM_LIBRARIES winmm ws2_32)
|
set(PLATFORM_LIBRARIES winmm ws2_32 iphlpapi)
|
||||||
if (MINGW)
|
if (MINGW)
|
||||||
# PSAPI is the Process Status API
|
# PSAPI is the Process Status API
|
||||||
set(PLATFORM_LIBRARIES ${PLATFORM_LIBRARIES} psapi imm32 version)
|
set(PLATFORM_LIBRARIES ${PLATFORM_LIBRARIES} psapi imm32 version)
|
||||||
|
|
|
@ -433,9 +433,10 @@ struct Values {
|
||||||
BasicSetting<std::string> log_filter{"*:Info", "log_filter"};
|
BasicSetting<std::string> log_filter{"*:Info", "log_filter"};
|
||||||
BasicSetting<bool> use_dev_keys{false, "use_dev_keys"};
|
BasicSetting<bool> use_dev_keys{false, "use_dev_keys"};
|
||||||
|
|
||||||
// Services
|
// Network
|
||||||
BasicSetting<std::string> bcat_backend{"none", "bcat_backend"};
|
BasicSetting<std::string> bcat_backend{"none", "bcat_backend"};
|
||||||
BasicSetting<bool> bcat_boxcat_local{false, "bcat_boxcat_local"};
|
BasicSetting<bool> bcat_boxcat_local{false, "bcat_boxcat_local"};
|
||||||
|
BasicSetting<std::string> network_interface{std::string(), "network_interface"};
|
||||||
|
|
||||||
// WebService
|
// WebService
|
||||||
BasicSetting<bool> enable_telemetry{true, "enable_telemetry"};
|
BasicSetting<bool> enable_telemetry{true, "enable_telemetry"};
|
||||||
|
|
|
@ -636,6 +636,8 @@ add_library(core STATIC
|
||||||
memory.h
|
memory.h
|
||||||
network/network.cpp
|
network/network.cpp
|
||||||
network/network.h
|
network/network.h
|
||||||
|
network/network_interface.cpp
|
||||||
|
network/network_interface.h
|
||||||
network/sockets.h
|
network/sockets.h
|
||||||
perf_stats.cpp
|
perf_stats.cpp
|
||||||
perf_stats.h
|
perf_stats.h
|
||||||
|
|
|
@ -179,10 +179,10 @@ private:
|
||||||
IPC::ResponseBuilder rb{ctx, 3};
|
IPC::ResponseBuilder rb{ctx, 3};
|
||||||
rb.Push(ResultSuccess);
|
rb.Push(ResultSuccess);
|
||||||
|
|
||||||
if (Settings::values.bcat_backend.GetValue() == "none") {
|
if (Network::GetHostIPv4Address().has_value()) {
|
||||||
rb.PushEnum(RequestState::NotSubmitted);
|
|
||||||
} else {
|
|
||||||
rb.PushEnum(RequestState::Connected);
|
rb.PushEnum(RequestState::Connected);
|
||||||
|
} else {
|
||||||
|
rb.PushEnum(RequestState::NotSubmitted);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -322,12 +322,15 @@ private:
|
||||||
void GetCurrentIpAddress(Kernel::HLERequestContext& ctx) {
|
void GetCurrentIpAddress(Kernel::HLERequestContext& ctx) {
|
||||||
LOG_WARNING(Service_NIFM, "(STUBBED) called");
|
LOG_WARNING(Service_NIFM, "(STUBBED) called");
|
||||||
|
|
||||||
const auto [ipv4, error] = Network::GetHostIPv4Address();
|
auto ipv4 = Network::GetHostIPv4Address();
|
||||||
UNIMPLEMENTED_IF(error != Network::Errno::SUCCESS);
|
if (!ipv4) {
|
||||||
|
LOG_CRITICAL(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};
|
IPC::ResponseBuilder rb{ctx, 3};
|
||||||
rb.Push(ResultSuccess);
|
rb.Push(ResultSuccess);
|
||||||
rb.PushRaw(ipv4);
|
rb.PushRaw(ipv4.value());
|
||||||
}
|
}
|
||||||
void CreateTemporaryNetworkProfile(Kernel::HLERequestContext& ctx) {
|
void CreateTemporaryNetworkProfile(Kernel::HLERequestContext& ctx) {
|
||||||
LOG_DEBUG(Service_NIFM, "called");
|
LOG_DEBUG(Service_NIFM, "called");
|
||||||
|
@ -354,13 +357,16 @@ private:
|
||||||
static_assert(sizeof(IpConfigInfo) == sizeof(IpAddressSetting) + sizeof(DnsSetting),
|
static_assert(sizeof(IpConfigInfo) == sizeof(IpAddressSetting) + sizeof(DnsSetting),
|
||||||
"IpConfigInfo has incorrect size.");
|
"IpConfigInfo has incorrect size.");
|
||||||
|
|
||||||
const auto [ipv4, error] = Network::GetHostIPv4Address();
|
auto ipv4 = Network::GetHostIPv4Address();
|
||||||
ASSERT_MSG(error == Network::Errno::SUCCESS, "Couldn't get host IPv4 address");
|
if (!ipv4) {
|
||||||
|
LOG_CRITICAL(Service_NIFM, "Couldn't get host IPv4 address, defaulting to 0.0.0.0");
|
||||||
|
ipv4.emplace(Network::IPv4Address{0, 0, 0, 0});
|
||||||
|
}
|
||||||
|
|
||||||
const IpConfigInfo ip_config_info{
|
const IpConfigInfo ip_config_info{
|
||||||
.ip_address_setting{
|
.ip_address_setting{
|
||||||
.is_automatic{true},
|
.is_automatic{true},
|
||||||
.current_address{ipv4},
|
.current_address{ipv4.value()},
|
||||||
.subnet_mask{255, 255, 255, 0},
|
.subnet_mask{255, 255, 255, 0},
|
||||||
.gateway{192, 168, 1, 1},
|
.gateway{192, 168, 1, 1},
|
||||||
},
|
},
|
||||||
|
@ -387,10 +393,10 @@ private:
|
||||||
|
|
||||||
IPC::ResponseBuilder rb{ctx, 3};
|
IPC::ResponseBuilder rb{ctx, 3};
|
||||||
rb.Push(ResultSuccess);
|
rb.Push(ResultSuccess);
|
||||||
if (Settings::values.bcat_backend.GetValue() == "none") {
|
if (Network::GetHostIPv4Address().has_value()) {
|
||||||
rb.Push<u8>(0);
|
|
||||||
} else {
|
|
||||||
rb.Push<u8>(1);
|
rb.Push<u8>(1);
|
||||||
|
} else {
|
||||||
|
rb.Push<u8>(0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
void IsAnyInternetRequestAccepted(Kernel::HLERequestContext& ctx) {
|
void IsAnyInternetRequestAccepted(Kernel::HLERequestContext& ctx) {
|
||||||
|
@ -398,10 +404,10 @@ private:
|
||||||
|
|
||||||
IPC::ResponseBuilder rb{ctx, 3};
|
IPC::ResponseBuilder rb{ctx, 3};
|
||||||
rb.Push(ResultSuccess);
|
rb.Push(ResultSuccess);
|
||||||
if (Settings::values.bcat_backend.GetValue() == "none") {
|
if (Network::GetHostIPv4Address().has_value()) {
|
||||||
rb.Push<u8>(0);
|
|
||||||
} else {
|
|
||||||
rb.Push<u8>(1);
|
rb.Push<u8>(1);
|
||||||
|
} else {
|
||||||
|
rb.Push<u8>(0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -10,8 +10,8 @@
|
||||||
#include "common/common_funcs.h"
|
#include "common/common_funcs.h"
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
#define _WINSOCK_DEPRECATED_NO_WARNINGS // gethostname
|
|
||||||
#include <winsock2.h>
|
#include <winsock2.h>
|
||||||
|
#include <ws2tcpip.h>
|
||||||
#elif YUZU_UNIX
|
#elif YUZU_UNIX
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
|
@ -19,6 +19,7 @@
|
||||||
#include <netinet/in.h>
|
#include <netinet/in.h>
|
||||||
#include <poll.h>
|
#include <poll.h>
|
||||||
#include <sys/socket.h>
|
#include <sys/socket.h>
|
||||||
|
#include <arpa/inet.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#else
|
#else
|
||||||
#error "Unimplemented platform"
|
#error "Unimplemented platform"
|
||||||
|
@ -27,7 +28,9 @@
|
||||||
#include "common/assert.h"
|
#include "common/assert.h"
|
||||||
#include "common/common_types.h"
|
#include "common/common_types.h"
|
||||||
#include "common/logging/log.h"
|
#include "common/logging/log.h"
|
||||||
|
#include "common/settings.h"
|
||||||
#include "core/network/network.h"
|
#include "core/network/network.h"
|
||||||
|
#include "core/network/network_interface.h"
|
||||||
#include "core/network/sockets.h"
|
#include "core/network/sockets.h"
|
||||||
|
|
||||||
namespace Network {
|
namespace Network {
|
||||||
|
@ -357,27 +360,27 @@ NetworkInstance::~NetworkInstance() {
|
||||||
Finalize();
|
Finalize();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::pair<IPv4Address, Errno> GetHostIPv4Address() {
|
std::optional<IPv4Address> GetHostIPv4Address() {
|
||||||
std::array<char, 256> name{};
|
const std::string& selected_network_interface = Settings::values.network_interface.GetValue();
|
||||||
if (gethostname(name.data(), static_cast<int>(name.size()) - 1) == SOCKET_ERROR) {
|
const auto network_interfaces = Network::GetAvailableNetworkInterfaces();
|
||||||
return {IPv4Address{}, GetAndLogLastError()};
|
ASSERT_MSG(network_interfaces.size() > 0, "GetAvailableNetworkInterfaces returned no interfaces");
|
||||||
}
|
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
in_addr addr;
|
const auto res = std::ranges::find_if(network_interfaces,
|
||||||
std::memcpy(&addr, ent->h_addr_list[0], sizeof(addr));
|
[&selected_network_interface](const auto& interface) {
|
||||||
return {TranslateIPv4(addr), Errno::SUCCESS};
|
return interface.name == selected_network_interface;
|
||||||
|
});
|
||||||
|
|
||||||
|
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) {
|
std::pair<s32, Errno> Poll(std::vector<PollFD>& pollfds, s32 timeout) {
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <array>
|
#include <array>
|
||||||
|
#include <optional>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
|
||||||
#include "common/common_funcs.h"
|
#include "common/common_funcs.h"
|
||||||
|
@ -93,7 +94,7 @@ public:
|
||||||
};
|
};
|
||||||
|
|
||||||
/// @brief Returns host's IPv4 address
|
/// @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
|
/// @return human ordered IPv4 address (e.g. 192.168.0.1) as an array
|
||||||
std::pair<IPv4Address, Errno> GetHostIPv4Address();
|
std::optional<IPv4Address> GetHostIPv4Address();
|
||||||
|
|
||||||
} // namespace Network
|
} // namespace Network
|
||||||
|
|
|
@ -0,0 +1,113 @@
|
||||||
|
// Copyright 2021 yuzu emulator team
|
||||||
|
// Licensed under GPLv2 or any later version
|
||||||
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include "common/common_types.h"
|
||||||
|
#include "common/logging/log.h"
|
||||||
|
#include "common/string_util.h"
|
||||||
|
#include "core/network/network_interface.h"
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
#include <iphlpapi.h>
|
||||||
|
#else
|
||||||
|
#include <ifaddrs.h>
|
||||||
|
#include <net/if.h>
|
||||||
|
#include <cerrno>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace Network {
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
|
||||||
|
std::vector<NetworkInterface> GetAvailableNetworkInterfaces() {
|
||||||
|
std::vector<NetworkInterface> result;
|
||||||
|
|
||||||
|
std::vector<u8> adapter_addresses_raw;
|
||||||
|
auto adapter_addresses = reinterpret_cast<PIP_ADAPTER_ADDRESSES>(adapter_addresses_raw.data());
|
||||||
|
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,
|
||||||
|
nullptr, adapter_addresses, &buf_size);
|
||||||
|
|
||||||
|
if (ret == ERROR_BUFFER_OVERFLOW) {
|
||||||
|
adapter_addresses_raw.resize(buf_size);
|
||||||
|
adapter_addresses =
|
||||||
|
reinterpret_cast<PIP_ADAPTER_ADDRESSES>(adapter_addresses_raw.data());
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ret == NO_ERROR) {
|
||||||
|
for (auto current_address = adapter_addresses; 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 = std::bit_cast<struct sockaddr_in>(
|
||||||
|
*current_address->FirstUnicastAddress->Address.lpSockaddr)
|
||||||
|
.sin_addr;
|
||||||
|
|
||||||
|
result.push_back(NetworkInterface{
|
||||||
|
.name{Common::UTF16ToUTF8(std::wstring{current_address->FriendlyName})},
|
||||||
|
.ip_address{ip_addr}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
LOG_ERROR(Network, "Failed to get network interfaces with GetAdaptersAddresses");
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
#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) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ifa->ifa_addr->sa_family != AF_INET) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(ifa->ifa_flags & IFF_UP) || ifa->ifa_flags & IFF_LOOPBACK) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
result.push_back(NetworkInterface{
|
||||||
|
.name{ifa->ifa_name},
|
||||||
|
.ip_address{std::bit_cast<struct sockaddr_in>(*ifa->ifa_addr).sin_addr}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
freeifaddrs(ifaddr);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
} // namespace Network
|
|
@ -0,0 +1,25 @@
|
||||||
|
// Copyright 2021 yuzu emulator team
|
||||||
|
// Licensed under GPLv2 or any later version
|
||||||
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#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;
|
||||||
|
};
|
||||||
|
|
||||||
|
std::vector<NetworkInterface> GetAvailableNetworkInterfaces();
|
||||||
|
|
||||||
|
} // namespace Network
|
|
@ -102,9 +102,9 @@ add_executable(yuzu
|
||||||
configuration/configure_profile_manager.cpp
|
configuration/configure_profile_manager.cpp
|
||||||
configuration/configure_profile_manager.h
|
configuration/configure_profile_manager.h
|
||||||
configuration/configure_profile_manager.ui
|
configuration/configure_profile_manager.ui
|
||||||
configuration/configure_service.cpp
|
configuration/configure_network.cpp
|
||||||
configuration/configure_service.h
|
configuration/configure_network.h
|
||||||
configuration/configure_service.ui
|
configuration/configure_network.ui
|
||||||
configuration/configure_system.cpp
|
configuration/configure_system.cpp
|
||||||
configuration/configure_system.h
|
configuration/configure_system.h
|
||||||
configuration/configure_system.ui
|
configuration/configure_system.ui
|
||||||
|
|
|
@ -692,6 +692,7 @@ void Config::ReadServiceValues() {
|
||||||
qt_config->beginGroup(QStringLiteral("Services"));
|
qt_config->beginGroup(QStringLiteral("Services"));
|
||||||
ReadBasicSetting(Settings::values.bcat_backend);
|
ReadBasicSetting(Settings::values.bcat_backend);
|
||||||
ReadBasicSetting(Settings::values.bcat_boxcat_local);
|
ReadBasicSetting(Settings::values.bcat_boxcat_local);
|
||||||
|
ReadBasicSetting(Settings::values.network_interface);
|
||||||
qt_config->endGroup();
|
qt_config->endGroup();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1144,7 +1145,7 @@ void Config::SaveValues() {
|
||||||
SaveDataStorageValues();
|
SaveDataStorageValues();
|
||||||
SaveDebuggingValues();
|
SaveDebuggingValues();
|
||||||
SaveDisabledAddOnValues();
|
SaveDisabledAddOnValues();
|
||||||
SaveServiceValues();
|
SaveNetworkValues();
|
||||||
SaveUIValues();
|
SaveUIValues();
|
||||||
SaveWebServiceValues();
|
SaveWebServiceValues();
|
||||||
SaveMiscellaneousValues();
|
SaveMiscellaneousValues();
|
||||||
|
@ -1238,11 +1239,12 @@ void Config::SaveDebuggingValues() {
|
||||||
qt_config->endGroup();
|
qt_config->endGroup();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Config::SaveServiceValues() {
|
void Config::SaveNetworkValues() {
|
||||||
qt_config->beginGroup(QStringLiteral("Services"));
|
qt_config->beginGroup(QStringLiteral("Services"));
|
||||||
|
|
||||||
WriteBasicSetting(Settings::values.bcat_backend);
|
WriteBasicSetting(Settings::values.bcat_backend);
|
||||||
WriteBasicSetting(Settings::values.bcat_boxcat_local);
|
WriteBasicSetting(Settings::values.bcat_boxcat_local);
|
||||||
|
WriteBasicSetting(Settings::values.network_interface);
|
||||||
|
|
||||||
qt_config->endGroup();
|
qt_config->endGroup();
|
||||||
}
|
}
|
||||||
|
|
|
@ -88,7 +88,7 @@ private:
|
||||||
void SaveCoreValues();
|
void SaveCoreValues();
|
||||||
void SaveDataStorageValues();
|
void SaveDataStorageValues();
|
||||||
void SaveDebuggingValues();
|
void SaveDebuggingValues();
|
||||||
void SaveServiceValues();
|
void SaveNetworkValues();
|
||||||
void SaveDisabledAddOnValues();
|
void SaveDisabledAddOnValues();
|
||||||
void SaveMiscellaneousValues();
|
void SaveMiscellaneousValues();
|
||||||
void SavePathValues();
|
void SavePathValues();
|
||||||
|
|
|
@ -147,12 +147,12 @@
|
||||||
<string>Web</string>
|
<string>Web</string>
|
||||||
</attribute>
|
</attribute>
|
||||||
</widget>
|
</widget>
|
||||||
<widget class="ConfigureService" name="serviceTab">
|
<widget class="ConfigureNetwork" name="networkTab">
|
||||||
<property name="accessibleName">
|
<property name="accessibleName">
|
||||||
<string>Services</string>
|
<string>Network</string>
|
||||||
</property>
|
</property>
|
||||||
<attribute name="title">
|
<attribute name="title">
|
||||||
<string>Services</string>
|
<string>Network</string>
|
||||||
</attribute>
|
</attribute>
|
||||||
</widget>
|
</widget>
|
||||||
</widget>
|
</widget>
|
||||||
|
@ -242,9 +242,9 @@
|
||||||
<container>1</container>
|
<container>1</container>
|
||||||
</customwidget>
|
</customwidget>
|
||||||
<customwidget>
|
<customwidget>
|
||||||
<class>ConfigureService</class>
|
<class>ConfigureNetwork</class>
|
||||||
<extends>QWidget</extends>
|
<extends>QWidget</extends>
|
||||||
<header>configuration/configure_service.h</header>
|
<header>configuration/configure_network.h</header>
|
||||||
<container>1</container>
|
<container>1</container>
|
||||||
</customwidget>
|
</customwidget>
|
||||||
<customwidget>
|
<customwidget>
|
||||||
|
|
|
@ -67,7 +67,7 @@ void ConfigureDialog::ApplyConfiguration() {
|
||||||
ui->audioTab->ApplyConfiguration();
|
ui->audioTab->ApplyConfiguration();
|
||||||
ui->debugTab->ApplyConfiguration();
|
ui->debugTab->ApplyConfiguration();
|
||||||
ui->webTab->ApplyConfiguration();
|
ui->webTab->ApplyConfiguration();
|
||||||
ui->serviceTab->ApplyConfiguration();
|
ui->networkTab->ApplyConfiguration();
|
||||||
Core::System::GetInstance().ApplySettings();
|
Core::System::GetInstance().ApplySettings();
|
||||||
Settings::LogSettings();
|
Settings::LogSettings();
|
||||||
}
|
}
|
||||||
|
@ -103,7 +103,7 @@ Q_DECLARE_METATYPE(QList<QWidget*>);
|
||||||
void ConfigureDialog::PopulateSelectionList() {
|
void ConfigureDialog::PopulateSelectionList() {
|
||||||
const std::array<std::pair<QString, QList<QWidget*>>, 6> items{
|
const std::array<std::pair<QString, QList<QWidget*>>, 6> items{
|
||||||
{{tr("General"), {ui->generalTab, ui->hotkeysTab, ui->uiTab, ui->webTab, ui->debugTab}},
|
{{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("CPU"), {ui->cpuTab}},
|
||||||
{tr("Graphics"), {ui->graphicsTab, ui->graphicsAdvancedTab}},
|
{tr("Graphics"), {ui->graphicsTab, ui->graphicsAdvancedTab}},
|
||||||
{tr("Audio"), {ui->audioTab}},
|
{tr("Audio"), {ui->audioTab}},
|
||||||
|
|
|
@ -5,9 +5,10 @@
|
||||||
#include <QGraphicsItem>
|
#include <QGraphicsItem>
|
||||||
#include <QtConcurrent/QtConcurrent>
|
#include <QtConcurrent/QtConcurrent>
|
||||||
#include "common/settings.h"
|
#include "common/settings.h"
|
||||||
|
#include "core/core.h"
|
||||||
#include "core/hle/service/bcat/backend/boxcat.h"
|
#include "core/hle/service/bcat/backend/boxcat.h"
|
||||||
#include "ui_configure_service.h"
|
#include "ui_configure_network.h"
|
||||||
#include "yuzu/configuration/configure_service.h"
|
#include "yuzu/configuration/configure_network.h"
|
||||||
|
|
||||||
#ifdef YUZU_ENABLE_BOXCAT
|
#ifdef YUZU_ENABLE_BOXCAT
|
||||||
namespace {
|
namespace {
|
||||||
|
@ -35,8 +36,8 @@ QString FormatEventStatusString(const Service::BCAT::EventStatus& status) {
|
||||||
} // Anonymous namespace
|
} // Anonymous namespace
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
ConfigureService::ConfigureService(QWidget* parent)
|
ConfigureNetwork::ConfigureNetwork(QWidget* parent)
|
||||||
: QWidget(parent), ui(std::make_unique<Ui::ConfigureService>()) {
|
: QWidget(parent), ui(std::make_unique<Ui::ConfigureNetwork>()) {
|
||||||
ui->setupUi(this);
|
ui->setupUi(this);
|
||||||
|
|
||||||
ui->bcat_source->addItem(QStringLiteral("None"));
|
ui->bcat_source->addItem(QStringLiteral("None"));
|
||||||
|
@ -47,29 +48,42 @@ ConfigureService::ConfigureService(QWidget* parent)
|
||||||
ui->bcat_source->addItem(QStringLiteral("Boxcat"), QStringLiteral("boxcat"));
|
ui->bcat_source->addItem(QStringLiteral("Boxcat"), QStringLiteral("boxcat"));
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
ui->network_interface->addItem(QStringLiteral("None"));
|
||||||
|
for (const auto& interface : Network::GetAvailableNetworkInterfaces()) {
|
||||||
|
ui->network_interface->addItem(QString::fromStdString(interface.name));
|
||||||
|
}
|
||||||
|
|
||||||
connect(ui->bcat_source, QOverload<int>::of(&QComboBox::currentIndexChanged), this,
|
connect(ui->bcat_source, QOverload<int>::of(&QComboBox::currentIndexChanged), this,
|
||||||
&ConfigureService::OnBCATImplChanged);
|
&ConfigureNetwork::OnBCATImplChanged);
|
||||||
|
|
||||||
this->SetConfiguration();
|
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.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);
|
ui->retranslateUi(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ConfigureService::SetConfiguration() {
|
void ConfigureNetwork::SetConfiguration() {
|
||||||
|
const bool runtime_lock = !Core::System::GetInstance().IsPoweredOn();
|
||||||
|
|
||||||
const int index =
|
const int index =
|
||||||
ui->bcat_source->findData(QString::fromStdString(Settings::values.bcat_backend.GetValue()));
|
ui->bcat_source->findData(QString::fromStdString(Settings::values.bcat_backend.GetValue()));
|
||||||
ui->bcat_source->setCurrentIndex(index == -1 ? 0 : index);
|
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
|
#ifdef YUZU_ENABLE_BOXCAT
|
||||||
std::optional<std::string> global;
|
std::optional<std::string> global;
|
||||||
std::map<std::string, Service::BCAT::EventStatus> map;
|
std::map<std::string, Service::BCAT::EventStatus> map;
|
||||||
|
@ -114,7 +128,7 @@ std::pair<QString, QString> ConfigureService::BCATDownloadEvents() {
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void ConfigureService::OnBCATImplChanged() {
|
void ConfigureNetwork::OnBCATImplChanged() {
|
||||||
#ifdef YUZU_ENABLE_BOXCAT
|
#ifdef YUZU_ENABLE_BOXCAT
|
||||||
const auto boxcat = ui->bcat_source->currentText() == QStringLiteral("Boxcat");
|
const auto boxcat = ui->bcat_source->currentText() == QStringLiteral("Boxcat");
|
||||||
ui->bcat_empty_header->setHidden(!boxcat);
|
ui->bcat_empty_header->setHidden(!boxcat);
|
||||||
|
@ -133,7 +147,7 @@ void ConfigureService::OnBCATImplChanged() {
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void ConfigureService::OnUpdateBCATEmptyLabel(std::pair<QString, QString> string) {
|
void ConfigureNetwork::OnUpdateBCATEmptyLabel(std::pair<QString, QString> string) {
|
||||||
#ifdef YUZU_ENABLE_BOXCAT
|
#ifdef YUZU_ENABLE_BOXCAT
|
||||||
const auto boxcat = ui->bcat_source->currentText() == QStringLiteral("Boxcat");
|
const auto boxcat = ui->bcat_source->currentText() == QStringLiteral("Boxcat");
|
||||||
if (boxcat) {
|
if (boxcat) {
|
|
@ -8,16 +8,18 @@
|
||||||
#include <QFutureWatcher>
|
#include <QFutureWatcher>
|
||||||
#include <QWidget>
|
#include <QWidget>
|
||||||
|
|
||||||
|
#include "core/network/network_interface.h"
|
||||||
|
|
||||||
namespace Ui {
|
namespace Ui {
|
||||||
class ConfigureService;
|
class ConfigureNetwork;
|
||||||
}
|
}
|
||||||
|
|
||||||
class ConfigureService : public QWidget {
|
class ConfigureNetwork : public QWidget {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit ConfigureService(QWidget* parent = nullptr);
|
explicit ConfigureNetwork(QWidget* parent = nullptr);
|
||||||
~ConfigureService() override;
|
~ConfigureNetwork() override;
|
||||||
|
|
||||||
void ApplyConfiguration();
|
void ApplyConfiguration();
|
||||||
void RetranslateUi();
|
void RetranslateUi();
|
||||||
|
@ -29,6 +31,6 @@ private:
|
||||||
void OnBCATImplChanged();
|
void OnBCATImplChanged();
|
||||||
void OnUpdateBCATEmptyLabel(std::pair<QString, QString> string);
|
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};
|
QFutureWatcher<std::pair<QString, QString>> watcher{this};
|
||||||
};
|
};
|
|
@ -1,7 +1,7 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<ui version="4.0">
|
<ui version="4.0">
|
||||||
<class>ConfigureService</class>
|
<class>ConfigureNetwork</class>
|
||||||
<widget class="QWidget" name="ConfigureService">
|
<widget class="QWidget" name="ConfigureNetwork">
|
||||||
<property name="geometry">
|
<property name="geometry">
|
||||||
<rect>
|
<rect>
|
||||||
<x>0</x>
|
<x>0</x>
|
||||||
|
@ -16,22 +16,38 @@
|
||||||
<layout class="QVBoxLayout" name="verticalLayout">
|
<layout class="QVBoxLayout" name="verticalLayout">
|
||||||
<item>
|
<item>
|
||||||
<layout class="QVBoxLayout" name="verticalLayout_3">
|
<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>
|
<item>
|
||||||
<widget class="QGroupBox" name="groupBox">
|
<widget class="QGroupBox" name="groupBox">
|
||||||
<property name="title">
|
<property name="title">
|
||||||
<string>BCAT</string>
|
<string>BCAT</string>
|
||||||
</property>
|
</property>
|
||||||
<layout class="QGridLayout" name="gridLayout">
|
<layout class="QGridLayout" name="gridLayout">
|
||||||
<item row="1" column="1" colspan="2">
|
<item row="3" column="0">
|
||||||
<widget class="QLabel" name="label_2">
|
<widget class="QLabel" name="bcat_empty_header">
|
||||||
<property name="maximumSize">
|
|
||||||
<size>
|
|
||||||
<width>260</width>
|
|
||||||
<height>16777215</height>
|
|
||||||
</size>
|
|
||||||
</property>
|
|
||||||
<property name="text">
|
<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>
|
||||||
<property name="wordWrap">
|
<property name="wordWrap">
|
||||||
<bool>true</bool>
|
<bool>true</bool>
|
||||||
|
@ -51,11 +67,8 @@
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="3" column="1" colspan="2">
|
<item row="1" column="1" colspan="2">
|
||||||
<widget class="QLabel" name="bcat_empty_label">
|
<widget class="QLabel" name="label_2">
|
||||||
<property name="enabled">
|
|
||||||
<bool>true</bool>
|
|
||||||
</property>
|
|
||||||
<property name="maximumSize">
|
<property name="maximumSize">
|
||||||
<size>
|
<size>
|
||||||
<width>260</width>
|
<width>260</width>
|
||||||
|
@ -63,10 +76,7 @@
|
||||||
</size>
|
</size>
|
||||||
</property>
|
</property>
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string/>
|
<string>BCAT is Nintendo's way of sending data to games to engage its community and unlock additional content.</string>
|
||||||
</property>
|
|
||||||
<property name="alignment">
|
|
||||||
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set>
|
|
||||||
</property>
|
</property>
|
||||||
<property name="wordWrap">
|
<property name="wordWrap">
|
||||||
<bool>true</bool>
|
<bool>true</bool>
|
||||||
|
@ -86,8 +96,17 @@
|
||||||
<item row="0" column="1" colspan="2">
|
<item row="0" column="1" colspan="2">
|
||||||
<widget class="QComboBox" name="bcat_source"/>
|
<widget class="QComboBox" name="bcat_source"/>
|
||||||
</item>
|
</item>
|
||||||
<item row="3" column="0">
|
<item row="3" column="1" colspan="2">
|
||||||
<widget class="QLabel" name="bcat_empty_header">
|
<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">
|
<property name="text">
|
||||||
<string/>
|
<string/>
|
||||||
</property>
|
</property>
|
Reference in New Issue