mirror of
				https://git.suyu.dev/suyu/suyu
				synced 2025-11-04 00:49:02 -06:00 
			
		
		
		
	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:
		@@ -433,9 +433,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"};
 | 
			
		||||
 
 | 
			
		||||
@@ -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
 | 
			
		||||
 
 | 
			
		||||
@@ -179,10 +179,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 +322,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_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};
 | 
			
		||||
        rb.Push(ResultSuccess);
 | 
			
		||||
        rb.PushRaw(ipv4);
 | 
			
		||||
        rb.PushRaw(ipv4.value());
 | 
			
		||||
    }
 | 
			
		||||
    void CreateTemporaryNetworkProfile(Kernel::HLERequestContext& ctx) {
 | 
			
		||||
        LOG_DEBUG(Service_NIFM, "called");
 | 
			
		||||
@@ -354,13 +357,16 @@ private:
 | 
			
		||||
        static_assert(sizeof(IpConfigInfo) == sizeof(IpAddressSetting) + sizeof(DnsSetting),
 | 
			
		||||
                      "IpConfigInfo has incorrect size.");
 | 
			
		||||
 | 
			
		||||
        const auto [ipv4, error] = Network::GetHostIPv4Address();
 | 
			
		||||
        ASSERT_MSG(error == Network::Errno::SUCCESS, "Couldn't get host IPv4 address");
 | 
			
		||||
        auto ipv4 = Network::GetHostIPv4Address();
 | 
			
		||||
        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{
 | 
			
		||||
            .ip_address_setting{
 | 
			
		||||
                .is_automatic{true},
 | 
			
		||||
                .current_address{ipv4},
 | 
			
		||||
                .current_address{ipv4.value()},
 | 
			
		||||
                .subnet_mask{255, 255, 255, 0},
 | 
			
		||||
                .gateway{192, 168, 1, 1},
 | 
			
		||||
            },
 | 
			
		||||
@@ -387,10 +393,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) {
 | 
			
		||||
@@ -398,10 +404,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);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
 
 | 
			
		||||
@@ -10,8 +10,8 @@
 | 
			
		||||
#include "common/common_funcs.h"
 | 
			
		||||
 | 
			
		||||
#ifdef _WIN32
 | 
			
		||||
#define _WINSOCK_DEPRECATED_NO_WARNINGS // gethostname
 | 
			
		||||
#include <winsock2.h>
 | 
			
		||||
#include <ws2tcpip.h>
 | 
			
		||||
#elif YUZU_UNIX
 | 
			
		||||
#include <errno.h>
 | 
			
		||||
#include <fcntl.h>
 | 
			
		||||
@@ -19,6 +19,7 @@
 | 
			
		||||
#include <netinet/in.h>
 | 
			
		||||
#include <poll.h>
 | 
			
		||||
#include <sys/socket.h>
 | 
			
		||||
#include <arpa/inet.h>
 | 
			
		||||
#include <unistd.h>
 | 
			
		||||
#else
 | 
			
		||||
#error "Unimplemented platform"
 | 
			
		||||
@@ -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 {
 | 
			
		||||
@@ -357,27 +360,27 @@ 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();
 | 
			
		||||
    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;
 | 
			
		||||
    std::memcpy(&addr, ent->h_addr_list[0], sizeof(addr));
 | 
			
		||||
    return {TranslateIPv4(addr), Errno::SUCCESS};
 | 
			
		||||
    const auto res = std::ranges::find_if(network_interfaces,
 | 
			
		||||
                                          [&selected_network_interface](const auto& interface) {
 | 
			
		||||
                                              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) {
 | 
			
		||||
 
 | 
			
		||||
@@ -5,6 +5,7 @@
 | 
			
		||||
#pragma once
 | 
			
		||||
 | 
			
		||||
#include <array>
 | 
			
		||||
#include <optional>
 | 
			
		||||
#include <utility>
 | 
			
		||||
 | 
			
		||||
#include "common/common_funcs.h"
 | 
			
		||||
@@ -93,7 +94,7 @@ public:
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/// @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
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										113
									
								
								src/core/network/network_interface.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										113
									
								
								src/core/network/network_interface.cpp
									
									
									
									
									
										Normal file
									
								
							@@ -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
 | 
			
		||||
							
								
								
									
										25
									
								
								src/core/network/network_interface.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								src/core/network/network_interface.h
									
									
									
									
									
										Normal file
									
								
							@@ -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.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
 | 
			
		||||
 
 | 
			
		||||
@@ -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();
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -88,7 +88,7 @@ private:
 | 
			
		||||
    void SaveCoreValues();
 | 
			
		||||
    void SaveDataStorageValues();
 | 
			
		||||
    void SaveDebuggingValues();
 | 
			
		||||
    void SaveServiceValues();
 | 
			
		||||
    void SaveNetworkValues();
 | 
			
		||||
    void SaveDisabledAddOnValues();
 | 
			
		||||
    void SaveMiscellaneousValues();
 | 
			
		||||
    void SavePathValues();
 | 
			
		||||
 
 | 
			
		||||
@@ -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>
 | 
			
		||||
 
 | 
			
		||||
@@ -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}},
 | 
			
		||||
 
 | 
			
		||||
@@ -5,9 +5,10 @@
 | 
			
		||||
#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 "ui_configure_network.h"
 | 
			
		||||
#include "yuzu/configuration/configure_network.h"
 | 
			
		||||
 | 
			
		||||
#ifdef YUZU_ENABLE_BOXCAT
 | 
			
		||||
namespace {
 | 
			
		||||
@@ -35,8 +36,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 +48,42 @@ ConfigureService::ConfigureService(QWidget* parent)
 | 
			
		||||
    ui->bcat_source->addItem(QStringLiteral("Boxcat"), QStringLiteral("boxcat"));
 | 
			
		||||
#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,
 | 
			
		||||
            &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 +128,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 +147,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) {
 | 
			
		||||
@@ -8,16 +8,18 @@
 | 
			
		||||
#include <QFutureWatcher>
 | 
			
		||||
#include <QWidget>
 | 
			
		||||
 | 
			
		||||
#include "core/network/network_interface.h"
 | 
			
		||||
 | 
			
		||||
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 +31,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};
 | 
			
		||||
};
 | 
			
		||||
@@ -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>
 | 
			
		||||
		Reference in New Issue
	
	Block a user