early-access version 1992
This commit is contained in:
parent
792cb23ddd
commit
df8f235e87
18 changed files with 552 additions and 56 deletions
|
@ -768,7 +768,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)
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
yuzu emulator early access
|
yuzu emulator early access
|
||||||
=============
|
=============
|
||||||
|
|
||||||
This is the source code for early-access 1991.
|
This is the source code for early-access 1992.
|
||||||
|
|
||||||
## Legal Notice
|
## Legal Notice
|
||||||
|
|
||||||
|
|
|
@ -569,9 +569,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_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};
|
IPC::ResponseBuilder rb{ctx, 3};
|
||||||
rb.Push(ResultSuccess);
|
rb.Push(ResultSuccess);
|
||||||
rb.PushRaw(ipv4);
|
rb.PushRaw(*ipv4);
|
||||||
}
|
}
|
||||||
void CreateTemporaryNetworkProfile(Kernel::HLERequestContext& ctx) {
|
void CreateTemporaryNetworkProfile(Kernel::HLERequestContext& ctx) {
|
||||||
LOG_DEBUG(Service_NIFM, "called");
|
LOG_DEBUG(Service_NIFM, "called");
|
||||||
|
@ -354,10 +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.");
|
||||||
|
|
||||||
|
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});
|
||||||
|
}
|
||||||
|
|
||||||
const IpConfigInfo ip_config_info{
|
const IpConfigInfo ip_config_info{
|
||||||
.ip_address_setting{
|
.ip_address_setting{
|
||||||
.is_automatic{true},
|
.is_automatic{true},
|
||||||
.current_address{192, 168, 1, 100},
|
.current_address{*ipv4},
|
||||||
.subnet_mask{255, 255, 255, 0},
|
.subnet_mask{255, 255, 255, 0},
|
||||||
.gateway{192, 168, 1, 1},
|
.gateway{192, 168, 1, 1},
|
||||||
},
|
},
|
||||||
|
@ -384,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) {
|
||||||
|
@ -395,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,9 +10,10 @@
|
||||||
#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 <arpa/inet.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <netdb.h>
|
#include <netdb.h>
|
||||||
|
@ -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 {
|
||||||
|
@ -182,7 +185,7 @@ linger MakeLinger(bool enable, u32 linger_value) {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool EnableNonBlock(int fd, bool enable) {
|
bool EnableNonBlock(int fd, bool enable) {
|
||||||
int flags = fcntl(fd, F_GETFD);
|
int flags = fcntl(fd, F_GETFL);
|
||||||
if (flags == -1) {
|
if (flags == -1) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -191,7 +194,7 @@ bool EnableNonBlock(int fd, bool enable) {
|
||||||
} else {
|
} else {
|
||||||
flags &= ~O_NONBLOCK;
|
flags &= ~O_NONBLOCK;
|
||||||
}
|
}
|
||||||
return fcntl(fd, F_SETFD, flags) == 0;
|
return fcntl(fd, F_SETFL, flags) == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
Errno TranslateNativeError(int e) {
|
Errno TranslateNativeError(int e) {
|
||||||
|
@ -227,8 +230,12 @@ Errno GetAndLogLastError() {
|
||||||
#else
|
#else
|
||||||
int e = errno;
|
int e = errno;
|
||||||
#endif
|
#endif
|
||||||
|
const Errno err = TranslateNativeError(e);
|
||||||
|
if (err == Errno::AGAIN) {
|
||||||
|
return err;
|
||||||
|
}
|
||||||
LOG_ERROR(Network, "Socket operation error: {}", NativeErrorToString(e));
|
LOG_ERROR(Network, "Socket operation error: {}", NativeErrorToString(e));
|
||||||
return TranslateNativeError(e);
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
int TranslateDomain(Domain domain) {
|
int TranslateDomain(Domain domain) {
|
||||||
|
@ -353,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());
|
const auto res = std::ranges::find_if(network_interfaces,
|
||||||
if (!ent) {
|
[&selected_network_interface](const auto& interface) {
|
||||||
return {IPv4Address{}, GetAndLogLastError()};
|
return interface.name == selected_network_interface;
|
||||||
}
|
});
|
||||||
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;
|
if (res != network_interfaces.end()) {
|
||||||
std::memcpy(&addr, ent->h_addr_list[0], sizeof(addr));
|
char ip_addr[16] = {};
|
||||||
return {TranslateIPv4(addr), Errno::SUCCESS};
|
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
|
||||||
|
|
113
src/core/network/network_interface.cpp
Executable file
113
src/core/network/network_interface.cpp
Executable 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/bit_cast.h"
|
||||||
|
#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 <cerrno>
|
||||||
|
#include <ifaddrs.h>
|
||||||
|
#include <net/if.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace Network {
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
|
||||||
|
std::vector<NetworkInterface> GetAvailableNetworkInterfaces() {
|
||||||
|
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) {
|
||||||
|
std::vector<NetworkInterface> result;
|
||||||
|
|
||||||
|
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 = Common::BitCast<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}});
|
||||||
|
}
|
||||||
|
|
||||||
|
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) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ifa->ifa_addr->sa_family != AF_INET) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((ifa->ifa_flags & IFF_UP) == 0 || (ifa->ifa_flags & IFF_LOOPBACK) != 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
result.push_back(NetworkInterface{
|
||||||
|
.name{ifa->ifa_name},
|
||||||
|
.ip_address{Common::BitCast<struct sockaddr_in>(*ifa->ifa_addr).sin_addr}});
|
||||||
|
}
|
||||||
|
|
||||||
|
freeifaddrs(ifaddr);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
} // namespace Network
|
25
src/core/network/network_interface.h
Executable file
25
src/core/network/network_interface.h
Executable 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
|
|
@ -95,8 +95,8 @@ const std::vector<u8>& H264::ComposeFrameHeader(const NvdecCommon::NvdecRegister
|
||||||
const s32 pic_height = context.h264_parameter_set.frame_height_in_map_units /
|
const s32 pic_height = context.h264_parameter_set.frame_height_in_map_units /
|
||||||
(context.h264_parameter_set.frame_mbs_only_flag ? 1 : 2);
|
(context.h264_parameter_set.frame_mbs_only_flag ? 1 : 2);
|
||||||
|
|
||||||
// TODO (ameerj): Find a way to compute this number, it seems to differ depending on the stream
|
// TODO (ameerj): Where do we get this number, it seems to be particular for each stream
|
||||||
writer.WriteUe(14); // Max number of reference frames
|
writer.WriteUe(6); // Max number of reference frames
|
||||||
writer.WriteBit(false);
|
writer.WriteBit(false);
|
||||||
writer.WriteUe(context.h264_parameter_set.pic_width_in_mbs - 1);
|
writer.WriteUe(context.h264_parameter_set.pic_width_in_mbs - 1);
|
||||||
writer.WriteUe(pic_height - 1);
|
writer.WriteUe(pic_height - 1);
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -707,6 +707,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();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1159,7 +1160,7 @@ void Config::SaveValues() {
|
||||||
SaveDataStorageValues();
|
SaveDataStorageValues();
|
||||||
SaveDebuggingValues();
|
SaveDebuggingValues();
|
||||||
SaveDisabledAddOnValues();
|
SaveDisabledAddOnValues();
|
||||||
SaveServiceValues();
|
SaveNetworkValues();
|
||||||
SaveUIValues();
|
SaveUIValues();
|
||||||
SaveWebServiceValues();
|
SaveWebServiceValues();
|
||||||
SaveMiscellaneousValues();
|
SaveMiscellaneousValues();
|
||||||
|
@ -1262,11 +1263,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}},
|
||||||
|
|
159
src/yuzu/configuration/configure_network.cpp
Executable file
159
src/yuzu/configuration/configure_network.cpp
Executable file
|
@ -0,0 +1,159 @@
|
||||||
|
// Copyright 2019 yuzu Emulator Project
|
||||||
|
// Licensed under GPLv2 or any later version
|
||||||
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
|
#include <QGraphicsItem>
|
||||||
|
#include <QtConcurrent/QtConcurrent>
|
||||||
|
#include "common/settings.h"
|
||||||
|
#include "core/core.h"
|
||||||
|
#include "core/hle/service/bcat/backend/boxcat.h"
|
||||||
|
#include "core/network/network_interface.h"
|
||||||
|
#include "ui_configure_network.h"
|
||||||
|
#include "yuzu/configuration/configure_network.h"
|
||||||
|
|
||||||
|
#ifdef YUZU_ENABLE_BOXCAT
|
||||||
|
namespace {
|
||||||
|
QString FormatEventStatusString(const Service::BCAT::EventStatus& status) {
|
||||||
|
QString out;
|
||||||
|
|
||||||
|
if (status.header.has_value()) {
|
||||||
|
out += QStringLiteral("<i>%1</i><br>").arg(QString::fromStdString(*status.header));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (status.events.size() == 1) {
|
||||||
|
out += QStringLiteral("%1<br>").arg(QString::fromStdString(status.events.front()));
|
||||||
|
} else {
|
||||||
|
for (const auto& event : status.events) {
|
||||||
|
out += QStringLiteral("- %1<br>").arg(QString::fromStdString(event));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (status.footer.has_value()) {
|
||||||
|
out += QStringLiteral("<i>%1</i><br>").arg(QString::fromStdString(*status.footer));
|
||||||
|
}
|
||||||
|
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
} // Anonymous namespace
|
||||||
|
#endif
|
||||||
|
|
||||||
|
ConfigureNetwork::ConfigureNetwork(QWidget* parent)
|
||||||
|
: QWidget(parent), ui(std::make_unique<Ui::ConfigureNetwork>()) {
|
||||||
|
ui->setupUi(this);
|
||||||
|
|
||||||
|
ui->bcat_source->addItem(QStringLiteral("None"));
|
||||||
|
ui->bcat_empty_label->setHidden(true);
|
||||||
|
ui->bcat_empty_header->setHidden(true);
|
||||||
|
|
||||||
|
#ifdef YUZU_ENABLE_BOXCAT
|
||||||
|
ui->bcat_source->addItem(QStringLiteral("Boxcat"), QStringLiteral("boxcat"));
|
||||||
|
#endif
|
||||||
|
|
||||||
|
ui->network_interface->addItem(tr("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,
|
||||||
|
&ConfigureNetwork::OnBCATImplChanged);
|
||||||
|
|
||||||
|
this->SetConfiguration();
|
||||||
|
}
|
||||||
|
|
||||||
|
ConfigureNetwork::~ConfigureNetwork() = default;
|
||||||
|
|
||||||
|
void ConfigureNetwork::ApplyConfiguration() {
|
||||||
|
Settings::values.bcat_backend = ui->bcat_source->currentText().toLower().toStdString();
|
||||||
|
Settings::values.network_interface = ui->network_interface->currentText().toStdString();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ConfigureNetwork::RetranslateUi() {
|
||||||
|
ui->retranslateUi(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
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> ConfigureNetwork::BCATDownloadEvents() {
|
||||||
|
#ifdef YUZU_ENABLE_BOXCAT
|
||||||
|
std::optional<std::string> global;
|
||||||
|
std::map<std::string, Service::BCAT::EventStatus> map;
|
||||||
|
const auto res = Service::BCAT::Boxcat::GetStatus(global, map);
|
||||||
|
|
||||||
|
switch (res) {
|
||||||
|
case Service::BCAT::Boxcat::StatusResult::Success:
|
||||||
|
break;
|
||||||
|
case Service::BCAT::Boxcat::StatusResult::Offline:
|
||||||
|
return {QString{},
|
||||||
|
tr("The boxcat service is offline or you are not connected to the internet.")};
|
||||||
|
case Service::BCAT::Boxcat::StatusResult::ParseError:
|
||||||
|
return {QString{},
|
||||||
|
tr("There was an error while processing the boxcat event data. Contact the yuzu "
|
||||||
|
"developers.")};
|
||||||
|
case Service::BCAT::Boxcat::StatusResult::BadClientVersion:
|
||||||
|
return {QString{},
|
||||||
|
tr("The version of yuzu you are using is either too new or too old for the server. "
|
||||||
|
"Try updating to the latest official release of yuzu.")};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (map.empty()) {
|
||||||
|
return {QStringLiteral("Current Boxcat Events"),
|
||||||
|
tr("There are currently no events on boxcat.")};
|
||||||
|
}
|
||||||
|
|
||||||
|
QString out;
|
||||||
|
|
||||||
|
if (global.has_value()) {
|
||||||
|
out += QStringLiteral("%1<br>").arg(QString::fromStdString(*global));
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const auto& [key, value] : map) {
|
||||||
|
out += QStringLiteral("%1<b>%2</b><br>%3")
|
||||||
|
.arg(out.isEmpty() ? QString{} : QStringLiteral("<br>"))
|
||||||
|
.arg(QString::fromStdString(key))
|
||||||
|
.arg(FormatEventStatusString(value));
|
||||||
|
}
|
||||||
|
return {tr("Current Boxcat Events"), std::move(out)};
|
||||||
|
#else
|
||||||
|
return {tr("Current Boxcat Events"), tr("There are currently no events on boxcat.")};
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void ConfigureNetwork::OnBCATImplChanged() {
|
||||||
|
#ifdef YUZU_ENABLE_BOXCAT
|
||||||
|
const auto boxcat = ui->bcat_source->currentText() == QStringLiteral("Boxcat");
|
||||||
|
ui->bcat_empty_header->setHidden(!boxcat);
|
||||||
|
ui->bcat_empty_label->setHidden(!boxcat);
|
||||||
|
ui->bcat_empty_header->setText(QString{});
|
||||||
|
ui->bcat_empty_label->setText(tr("Yuzu is retrieving the latest boxcat status..."));
|
||||||
|
|
||||||
|
if (!boxcat)
|
||||||
|
return;
|
||||||
|
|
||||||
|
const auto future = QtConcurrent::run([this] { return BCATDownloadEvents(); });
|
||||||
|
|
||||||
|
watcher.setFuture(future);
|
||||||
|
connect(&watcher, &QFutureWatcher<std::pair<QString, QString>>::finished, this,
|
||||||
|
[this] { OnUpdateBCATEmptyLabel(watcher.result()); });
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void ConfigureNetwork::OnUpdateBCATEmptyLabel(std::pair<QString, QString> string) {
|
||||||
|
#ifdef YUZU_ENABLE_BOXCAT
|
||||||
|
const auto boxcat = ui->bcat_source->currentText() == QStringLiteral("Boxcat");
|
||||||
|
if (boxcat) {
|
||||||
|
ui->bcat_empty_header->setText(string.first);
|
||||||
|
ui->bcat_empty_label->setText(string.second);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
34
src/yuzu/configuration/configure_network.h
Executable file
34
src/yuzu/configuration/configure_network.h
Executable file
|
@ -0,0 +1,34 @@
|
||||||
|
// Copyright 2019 yuzu Emulator Project
|
||||||
|
// Licensed under GPLv2 or any later version
|
||||||
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
#include <QFutureWatcher>
|
||||||
|
#include <QWidget>
|
||||||
|
|
||||||
|
namespace Ui {
|
||||||
|
class ConfigureNetwork;
|
||||||
|
}
|
||||||
|
|
||||||
|
class ConfigureNetwork : public QWidget {
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit ConfigureNetwork(QWidget* parent = nullptr);
|
||||||
|
~ConfigureNetwork() override;
|
||||||
|
|
||||||
|
void ApplyConfiguration();
|
||||||
|
void RetranslateUi();
|
||||||
|
|
||||||
|
private:
|
||||||
|
void SetConfiguration();
|
||||||
|
|
||||||
|
std::pair<QString, QString> BCATDownloadEvents();
|
||||||
|
void OnBCATImplChanged();
|
||||||
|
void OnUpdateBCATEmptyLabel(std::pair<QString, QString> string);
|
||||||
|
|
||||||
|
std::unique_ptr<Ui::ConfigureNetwork> ui;
|
||||||
|
QFutureWatcher<std::pair<QString, QString>> watcher{this};
|
||||||
|
};
|
143
src/yuzu/configuration/configure_network.ui
Executable file
143
src/yuzu/configuration/configure_network.ui
Executable file
|
@ -0,0 +1,143 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<ui version="4.0">
|
||||||
|
<class>ConfigureNetwork</class>
|
||||||
|
<widget class="QWidget" name="ConfigureNetwork">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>0</x>
|
||||||
|
<y>0</y>
|
||||||
|
<width>433</width>
|
||||||
|
<height>561</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="windowTitle">
|
||||||
|
<string>Form</string>
|
||||||
|
</property>
|
||||||
|
<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="3" column="0">
|
||||||
|
<widget class="QLabel" name="bcat_empty_header">
|
||||||
|
<property name="text">
|
||||||
|
<string/>
|
||||||
|
</property>
|
||||||
|
<property name="alignment">
|
||||||
|
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set>
|
||||||
|
</property>
|
||||||
|
<property name="wordWrap">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="0" column="0">
|
||||||
|
<widget class="QLabel" name="label">
|
||||||
|
<property name="maximumSize">
|
||||||
|
<size>
|
||||||
|
<width>16777215</width>
|
||||||
|
<height>16777215</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>BCAT Backend</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<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>
|
||||||
|
<property name="text">
|
||||||
|
<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>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="2" column="1" colspan="2">
|
||||||
|
<widget class="QLabel" name="label_3">
|
||||||
|
<property name="text">
|
||||||
|
<string><html><head/><body><p><a href="https://yuzu-emu.org/help/feature/boxcat"><span style=" text-decoration: underline; color:#0000ff;">Learn more about BCAT, Boxcat, and Current Events</span></a></p></body></html></string>
|
||||||
|
</property>
|
||||||
|
<property name="openExternalLinks">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="0" column="1" colspan="2">
|
||||||
|
<widget class="QComboBox" name="bcat_source"/>
|
||||||
|
</item>
|
||||||
|
<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>
|
||||||
|
<property name="alignment">
|
||||||
|
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set>
|
||||||
|
</property>
|
||||||
|
<property name="wordWrap">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<spacer name="verticalSpacer">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Vertical</enum>
|
||||||
|
</property>
|
||||||
|
<property name="sizeHint" stdset="0">
|
||||||
|
<size>
|
||||||
|
<width>20</width>
|
||||||
|
<height>40</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
</spacer>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
<resources/>
|
||||||
|
<connections/>
|
||||||
|
</ui>
|
Loading…
Reference in a new issue