diff --git a/patches/0002-fix-non-amd64-linkage.patch b/patches/0002-fix-non-amd64-linkage.patch deleted file mode 100644 index 46b7445..0000000 --- a/patches/0002-fix-non-amd64-linkage.patch +++ /dev/null @@ -1,33 +0,0 @@ -From 7ccb6aa7c216401aea1cf09adeb7d07ce077580b Mon Sep 17 00:00:00 2001 -From: liushuyu -Date: Mon, 12 Sep 2022 23:01:44 -0600 -Subject: [PATCH] common: do not link to xbyak on non-amd64 architectures - ---- - src/common/CMakeLists.txt | 3 ++- - 1 file changed, 2 insertions(+), 1 deletion(-) - -diff --git a/src/common/CMakeLists.txt b/src/common/CMakeLists.txt -index 635fb85c8..b1e0ba6cc 100644 ---- a/src/common/CMakeLists.txt -+++ b/src/common/CMakeLists.txt -@@ -166,6 +166,7 @@ if(ARCHITECTURE_x86_64) - x64/xbyak_abi.h - x64/xbyak_util.h - ) -+ target_link_libraries(common PRIVATE xbyak) - endif() - - if (MSVC) -@@ -189,7 +190,7 @@ endif() - create_target_directory_groups(common) - - target_link_libraries(common PUBLIC ${Boost_LIBRARIES} fmt::fmt microprofile Threads::Threads) --target_link_libraries(common PRIVATE lz4::lz4 xbyak) -+target_link_libraries(common PRIVATE lz4::lz4) - if (TARGET zstd::zstd) - target_link_libraries(common PRIVATE zstd::zstd) - else() --- -2.37.3 - diff --git a/patches/1001-ldn-full-impl.patch b/patches/1001-ldn-full-impl.patch deleted file mode 100644 index 42f905b..0000000 --- a/patches/1001-ldn-full-impl.patch +++ /dev/null @@ -1,2835 +0,0 @@ -From f5e635addaef59159bf6bc529b17954eda3684a1 Mon Sep 17 00:00:00 2001 -From: FearlessTobi -Date: Sun, 31 Jul 2022 04:46:26 +0200 -Subject: [PATCH 1/5] ldn: Initial implementation - ---- - src/core/CMakeLists.txt | 2 + - src/core/hle/service/ldn/lan_discovery.cpp | 644 +++++++++++++++++++++ - src/core/hle/service/ldn/lan_discovery.h | 133 +++++ - src/core/hle/service/ldn/ldn.cpp | 229 ++++---- - src/core/hle/service/ldn/ldn_types.h | 50 +- - src/core/internal_network/socket_proxy.cpp | 8 +- - src/dedicated_room/yuzu_room.cpp | 3 +- - src/network/room.cpp | 63 ++ - src/network/room.h | 1 + - src/network/room_member.cpp | 57 ++ - src/network/room_member.h | 35 +- - src/yuzu/main.cpp | 4 +- - src/yuzu/main.ui | 14 + - src/yuzu/multiplayer/chat_room.cpp | 12 +- - src/yuzu/multiplayer/state.cpp | 1 + - 15 files changed, 1132 insertions(+), 124 deletions(-) - create mode 100644 src/core/hle/service/ldn/lan_discovery.cpp - create mode 100644 src/core/hle/service/ldn/lan_discovery.h - -diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt -index 806e7ff6c0c1..52017878c9da 100644 ---- a/src/core/CMakeLists.txt -+++ b/src/core/CMakeLists.txt -@@ -500,6 +500,8 @@ add_library(core STATIC - hle/service/jit/jit.h - hle/service/lbl/lbl.cpp - hle/service/lbl/lbl.h -+ hle/service/ldn/lan_discovery.cpp -+ hle/service/ldn/lan_discovery.h - hle/service/ldn/ldn_results.h - hle/service/ldn/ldn.cpp - hle/service/ldn/ldn.h -diff --git a/src/core/hle/service/ldn/lan_discovery.cpp b/src/core/hle/service/ldn/lan_discovery.cpp -new file mode 100644 -index 000000000000..b04c990771ad ---- /dev/null -+++ b/src/core/hle/service/ldn/lan_discovery.cpp -@@ -0,0 +1,644 @@ -+// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project -+// SPDX-License-Identifier: GPL-2.0-or-later -+ -+#include "core/hle/service/ldn/lan_discovery.h" -+#include "core/internal_network/network.h" -+#include "core/internal_network/network_interface.h" -+ -+namespace Service::LDN { -+ -+LanStation::LanStation(s8 node_id_, LANDiscovery* discovery_) -+ : node_info(nullptr), status(NodeStatus::Disconnected), node_id(node_id_), -+ discovery(discovery_) {} -+ -+LanStation::~LanStation() = default; -+ -+NodeStatus LanStation::GetStatus() const { -+ return status; -+} -+ -+void LanStation::OnClose() { -+ LOG_INFO(Service_LDN, "OnClose {}", node_id); -+ Reset(); -+ discovery->UpdateNodes(); -+} -+ -+void LanStation::Reset() { -+ status = NodeStatus::Disconnected; -+}; -+ -+void LanStation::OverrideInfo() { -+ bool connected = GetStatus() == NodeStatus::Connected; -+ node_info->node_id = node_id; -+ node_info->is_connected = connected ? 1 : 0; -+} -+ -+LANDiscovery::LANDiscovery(Network::RoomNetwork& room_network_) -+ : stations({{{1, this}, {2, this}, {3, this}, {4, this}, {5, this}, {6, this}, {7, this}}}), -+ room_network{room_network_} { -+ LOG_INFO(Service_LDN, "LANDiscovery"); -+} -+ -+LANDiscovery::~LANDiscovery() { -+ LOG_INFO(Service_LDN, "~LANDiscovery"); -+ if (inited) { -+ Result rc = Finalize(); -+ LOG_INFO(Service_LDN, "Finalize: {}", rc.raw); -+ } -+} -+ -+void LANDiscovery::InitNetworkInfo() { -+ network_info.common.bssid = GetFakeMac(); -+ network_info.common.channel = WifiChannel::Wifi24_6; -+ network_info.common.link_level = LinkLevel::Good; -+ network_info.common.network_type = PackedNetworkType::Ldn; -+ network_info.common.ssid = fake_ssid; -+ -+ auto& nodes = network_info.ldn.nodes; -+ for (std::size_t i = 0; i < NodeCountMax; i++) { -+ nodes[i].node_id = static_cast(i); -+ nodes[i].is_connected = 0; -+ } -+} -+ -+void LANDiscovery::InitNodeStateChange() { -+ for (auto& node_update : nodeChanges) { -+ node_update.state_change = NodeStateChange::None; -+ } -+ for (auto& node_state : node_last_states) { -+ node_state = 0; -+ } -+} -+ -+State LANDiscovery::GetState() const { -+ return state; -+} -+ -+void LANDiscovery::SetState(State new_state) { -+ state = new_state; -+} -+ -+Result LANDiscovery::GetNetworkInfo(NetworkInfo& out_network) const { -+ if (state == State::AccessPointCreated || state == State::StationConnected) { -+ std::memcpy(&out_network, &network_info, sizeof(network_info)); -+ return ResultSuccess; -+ } -+ -+ return ResultBadState; -+} -+ -+Result LANDiscovery::GetNetworkInfo(NetworkInfo& out_network, -+ std::vector& out_updates, -+ std::size_t buffer_count) { -+ if (buffer_count > NodeCountMax) { -+ return ResultInvalidBufferCount; -+ } -+ -+ if (state == State::AccessPointCreated || state == State::StationConnected) { -+ std::memcpy(&out_network, &network_info, sizeof(network_info)); -+ for (std::size_t i = 0; i < buffer_count; i++) { -+ out_updates[i].state_change = nodeChanges[i].state_change; -+ nodeChanges[i].state_change = NodeStateChange::None; -+ } -+ return ResultSuccess; -+ } -+ -+ return ResultBadState; -+} -+ -+DisconnectReason LANDiscovery::GetDisconnectReason() const { -+ return disconnect_reason; -+} -+ -+Result LANDiscovery::Scan(std::vector& networks, u16& count, -+ const ScanFilter& filter) { -+ if (!IsFlagSet(filter.flag, ScanFilterFlag::NetworkType) || -+ filter.network_type <= NetworkType::All) { -+ if (!IsFlagSet(filter.flag, ScanFilterFlag::Ssid) && filter.ssid.length >= SsidLengthMax) { -+ return ResultBadInput; -+ } -+ } -+ -+ { -+ std::scoped_lock lock{packet_mutex}; -+ scan_results.clear(); -+ -+ SendBroadcast(Network::LDNPacketType::Scan); -+ } -+ -+ LOG_INFO(Service_LDN, "Waiting for scan replies"); -+ std::this_thread::sleep_for(std::chrono::seconds(1)); -+ -+ std::scoped_lock lock{packet_mutex}; -+ for (const auto& [key, info] : scan_results) { -+ if (count >= networks.size()) { -+ break; -+ } -+ -+ if (IsFlagSet(filter.flag, ScanFilterFlag::LocalCommunicationId)) { -+ if (filter.network_id.intent_id.local_communication_id != -+ info.network_id.intent_id.local_communication_id) { -+ continue; -+ } -+ } -+ if (IsFlagSet(filter.flag, ScanFilterFlag::SessionId)) { -+ if (filter.network_id.session_id != info.network_id.session_id) { -+ continue; -+ } -+ } -+ if (IsFlagSet(filter.flag, ScanFilterFlag::NetworkType)) { -+ if (filter.network_type != static_cast(info.common.network_type)) { -+ continue; -+ } -+ } -+ if (IsFlagSet(filter.flag, ScanFilterFlag::Ssid)) { -+ if (filter.ssid != info.common.ssid) { -+ continue; -+ } -+ } -+ if (IsFlagSet(filter.flag, ScanFilterFlag::SceneId)) { -+ if (filter.network_id.intent_id.scene_id != info.network_id.intent_id.scene_id) { -+ continue; -+ } -+ } -+ -+ networks[count++] = info; -+ } -+ -+ return ResultSuccess; -+} -+ -+Result LANDiscovery::SetAdvertiseData(std::vector& data) { -+ std::scoped_lock lock{packet_mutex}; -+ std::size_t size = data.size(); -+ if (size > AdvertiseDataSizeMax) { -+ return ResultAdvertiseDataTooLarge; -+ } -+ -+ std::memcpy(network_info.ldn.advertise_data.data(), data.data(), size); -+ network_info.ldn.advertise_data_size = static_cast(size); -+ -+ UpdateNodes(); -+ -+ return ResultSuccess; -+} -+ -+Result LANDiscovery::OpenAccessPoint() { -+ std::scoped_lock lock{packet_mutex}; -+ disconnect_reason = DisconnectReason::None; -+ if (state == State::None) { -+ return ResultBadState; -+ } -+ -+ ResetStations(); -+ SetState(State::AccessPointOpened); -+ -+ return ResultSuccess; -+} -+ -+Result LANDiscovery::CloseAccessPoint() { -+ std::scoped_lock lock{packet_mutex}; -+ if (state == State::None) { -+ return ResultBadState; -+ } -+ -+ if (state == State::AccessPointCreated) { -+ DestroyNetwork(); -+ } -+ -+ ResetStations(); -+ SetState(State::Initialized); -+ -+ return ResultSuccess; -+} -+ -+Result LANDiscovery::OpenStation() { -+ std::scoped_lock lock{packet_mutex}; -+ disconnect_reason = DisconnectReason::None; -+ if (state == State::None) { -+ return ResultBadState; -+ } -+ -+ ResetStations(); -+ SetState(State::StationOpened); -+ -+ return ResultSuccess; -+} -+ -+Result LANDiscovery::CloseStation() { -+ std::scoped_lock lock{packet_mutex}; -+ if (state == State::None) { -+ return ResultBadState; -+ } -+ -+ if (state == State::StationConnected) { -+ Disconnect(); -+ } -+ -+ ResetStations(); -+ SetState(State::Initialized); -+ -+ return ResultSuccess; -+} -+ -+Result LANDiscovery::CreateNetwork(const SecurityConfig& security_config, -+ const UserConfig& user_config, -+ const NetworkConfig& network_config) { -+ std::scoped_lock lock{packet_mutex}; -+ -+ if (state != State::AccessPointOpened) { -+ return ResultBadState; -+ } -+ -+ InitNetworkInfo(); -+ network_info.ldn.node_count_max = network_config.node_count_max; -+ network_info.ldn.security_mode = security_config.security_mode; -+ -+ if (network_config.channel == WifiChannel::Default) { -+ network_info.common.channel = WifiChannel::Wifi24_6; -+ } else { -+ network_info.common.channel = network_config.channel; -+ } -+ -+ std::independent_bits_engine bits_engine; -+ network_info.network_id.session_id.high = bits_engine(); -+ network_info.network_id.session_id.low = bits_engine(); -+ network_info.network_id.intent_id = network_config.intent_id; -+ -+ NodeInfo& node0 = network_info.ldn.nodes[0]; -+ const Result rc2 = GetNodeInfo(node0, user_config, network_config.local_communication_version); -+ if (rc2.IsError()) { -+ return ResultAccessPointConnectionFailed; -+ } -+ -+ SetState(State::AccessPointCreated); -+ -+ InitNodeStateChange(); -+ node0.is_connected = 1; -+ UpdateNodes(); -+ -+ return rc2; -+} -+ -+Result LANDiscovery::DestroyNetwork() { -+ for (auto local_ip : connected_clients) { -+ SendPacket(Network::LDNPacketType::DestroyNetwork, local_ip); -+ } -+ -+ ResetStations(); -+ -+ SetState(State::AccessPointOpened); -+ LanEvent(); -+ -+ return ResultSuccess; -+} -+ -+Result LANDiscovery::Connect(const NetworkInfo& network_info_, const UserConfig& user_config, -+ u16 local_communication_version) { -+ std::scoped_lock lock{packet_mutex}; -+ if (network_info_.ldn.node_count == 0) { -+ return ResultInvalidNodeCount; -+ } -+ -+ Result rc = GetNodeInfo(node_info, user_config, local_communication_version); -+ if (rc.IsError()) { -+ return ResultConnectionFailed; -+ } -+ -+ Ipv4Address node_host = network_info_.ldn.nodes[0].ipv4_address; -+ std::reverse(std::begin(node_host), std::end(node_host)); // htonl -+ host_ip = node_host; -+ SendPacket(Network::LDNPacketType::Connect, node_info, *host_ip); -+ -+ InitNodeStateChange(); -+ -+ std::this_thread::sleep_for(std::chrono::seconds(1)); -+ -+ return ResultSuccess; -+} -+ -+Result LANDiscovery::Disconnect() { -+ if (host_ip) { -+ SendPacket(Network::LDNPacketType::Disconnect, node_info, *host_ip); -+ } -+ -+ SetState(State::StationOpened); -+ LanEvent(); -+ -+ return ResultSuccess; -+} -+ -+Result LANDiscovery::Initialize(LanEventFunc lan_event, bool listening) { -+ std::scoped_lock lock{packet_mutex}; -+ if (inited) { -+ return ResultSuccess; -+ } -+ -+ for (auto& station : stations) { -+ station.discovery = this; -+ station.node_info = &network_info.ldn.nodes[station.node_id]; -+ station.Reset(); -+ } -+ -+ connected_clients.clear(); -+ LanEvent = lan_event; -+ -+ SetState(State::Initialized); -+ -+ inited = true; -+ return ResultSuccess; -+} -+ -+Result LANDiscovery::Finalize() { -+ std::scoped_lock lock{packet_mutex}; -+ Result rc = ResultSuccess; -+ -+ if (inited) { -+ if (state == State::AccessPointCreated) { -+ DestroyNetwork(); -+ } -+ if (state == State::StationConnected) { -+ Disconnect(); -+ } -+ -+ ResetStations(); -+ inited = false; -+ } -+ -+ SetState(State::None); -+ -+ return rc; -+} -+ -+void LANDiscovery::ResetStations() { -+ for (auto& station : stations) { -+ station.Reset(); -+ } -+ connected_clients.clear(); -+} -+ -+void LANDiscovery::UpdateNodes() { -+ u8 count = 0; -+ for (auto& station : stations) { -+ bool connected = station.GetStatus() == NodeStatus::Connected; -+ if (connected) { -+ count++; -+ } -+ station.OverrideInfo(); -+ } -+ network_info.ldn.node_count = count + 1; -+ -+ for (auto local_ip : connected_clients) { -+ SendPacket(Network::LDNPacketType::SyncNetwork, network_info, local_ip); -+ } -+ -+ OnNetworkInfoChanged(); -+} -+ -+void LANDiscovery::OnSyncNetwork(const NetworkInfo& info) { -+ network_info = info; -+ if (state == State::StationOpened) { -+ SetState(State::StationConnected); -+ } -+ OnNetworkInfoChanged(); -+} -+ -+void LANDiscovery::OnDisconnectFromHost() { -+ LOG_INFO(Service_LDN, "OnDisconnectFromHost state: {}", static_cast(state)); -+ host_ip = std::nullopt; -+ if (state == State::StationConnected) { -+ SetState(State::StationOpened); -+ LanEvent(); -+ } -+} -+ -+void LANDiscovery::OnNetworkInfoChanged() { -+ if (IsNodeStateChanged()) { -+ LanEvent(); -+ } -+ return; -+} -+ -+Network::IPv4Address LANDiscovery::GetLocalIp() const { -+ Network::IPv4Address local_ip{0xFF, 0xFF, 0xFF, 0xFF}; -+ if (auto room_member = room_network.GetRoomMember().lock()) { -+ if (room_member->IsConnected()) { -+ local_ip = room_member->GetFakeIpAddress(); -+ } -+ } -+ return local_ip; -+} -+ -+template -+void LANDiscovery::SendPacket(Network::LDNPacketType type, const Data& data, -+ Ipv4Address remote_ip) { -+ Network::LDNPacket packet; -+ packet.type = type; -+ -+ packet.broadcast = false; -+ packet.local_ip = GetLocalIp(); -+ packet.remote_ip = remote_ip; -+ -+ packet.data.clear(); -+ packet.data.resize(sizeof(data)); -+ std::memcpy(packet.data.data(), &data, sizeof(data)); -+ SendPacket(packet); -+} -+ -+void LANDiscovery::SendPacket(Network::LDNPacketType type, Ipv4Address remote_ip) { -+ Network::LDNPacket packet; -+ packet.type = type; -+ -+ packet.broadcast = false; -+ packet.local_ip = GetLocalIp(); -+ packet.remote_ip = remote_ip; -+ -+ packet.data.clear(); -+ SendPacket(packet); -+} -+ -+template -+void LANDiscovery::SendBroadcast(Network::LDNPacketType type, const Data& data) { -+ Network::LDNPacket packet; -+ packet.type = type; -+ -+ packet.broadcast = true; -+ packet.local_ip = GetLocalIp(); -+ -+ packet.data.clear(); -+ packet.data.resize(sizeof(data)); -+ std::memcpy(packet.data.data(), &data, sizeof(data)); -+ SendPacket(packet); -+} -+ -+void LANDiscovery::SendBroadcast(Network::LDNPacketType type) { -+ Network::LDNPacket packet; -+ packet.type = type; -+ -+ packet.broadcast = true; -+ packet.local_ip = GetLocalIp(); -+ -+ packet.data.clear(); -+ SendPacket(packet); -+} -+ -+void LANDiscovery::SendPacket(const Network::LDNPacket& packet) { -+ if (auto room_member = room_network.GetRoomMember().lock()) { -+ if (room_member->IsConnected()) { -+ room_member->SendLdnPacket(packet); -+ } -+ } -+} -+ -+void LANDiscovery::ReceivePacket(const Network::LDNPacket& packet) { -+ std::scoped_lock lock{packet_mutex}; -+ switch (packet.type) { -+ case Network::LDNPacketType::Scan: { -+ LOG_INFO(Frontend, "Scan packet received!"); -+ if (state == State::AccessPointCreated) { -+ // Reply to the sender -+ SendPacket(Network::LDNPacketType::ScanResp, network_info, packet.local_ip); -+ } -+ break; -+ } -+ case Network::LDNPacketType::ScanResp: { -+ LOG_INFO(Frontend, "ScanResp packet received!"); -+ -+ NetworkInfo info{}; -+ std::memcpy(&info, packet.data.data(), sizeof(NetworkInfo)); -+ scan_results.insert({info.common.bssid, info}); -+ -+ break; -+ } -+ case Network::LDNPacketType::Connect: { -+ LOG_INFO(Frontend, "Connect packet received!"); -+ -+ NodeInfo info{}; -+ std::memcpy(&info, packet.data.data(), sizeof(NodeInfo)); -+ -+ connected_clients.push_back(packet.local_ip); -+ -+ for (LanStation& station : stations) { -+ if (station.status != NodeStatus::Connected) { -+ *station.node_info = info; -+ station.status = NodeStatus::Connected; -+ break; -+ } -+ } -+ -+ UpdateNodes(); -+ -+ break; -+ } -+ case Network::LDNPacketType::Disconnect: { -+ LOG_INFO(Frontend, "Disconnect packet received!"); -+ -+ connected_clients.erase( -+ std::remove(connected_clients.begin(), connected_clients.end(), packet.local_ip), -+ connected_clients.end()); -+ -+ NodeInfo info{}; -+ std::memcpy(&info, packet.data.data(), sizeof(NodeInfo)); -+ -+ for (LanStation& station : stations) { -+ if (station.status == NodeStatus::Connected && -+ station.node_info->mac_address == info.mac_address) { -+ station.OnClose(); -+ break; -+ } -+ } -+ -+ break; -+ } -+ case Network::LDNPacketType::DestroyNetwork: { -+ ResetStations(); -+ OnDisconnectFromHost(); -+ break; -+ } -+ case Network::LDNPacketType::SyncNetwork: { -+ if (state == State::StationOpened || state == State::StationConnected) { -+ LOG_INFO(Frontend, "SyncNetwork packet received!"); -+ NetworkInfo info{}; -+ std::memcpy(&info, packet.data.data(), sizeof(NetworkInfo)); -+ -+ OnSyncNetwork(info); -+ } else { -+ LOG_INFO(Frontend, "SyncNetwork packet received but in wrong State!"); -+ } -+ -+ break; -+ } -+ default: { -+ LOG_INFO(Frontend, "ReceivePacket unhandled type {}", static_cast(packet.type)); -+ break; -+ } -+ } -+} -+ -+bool LANDiscovery::IsNodeStateChanged() { -+ bool changed = false; -+ const auto& nodes = network_info.ldn.nodes; -+ for (int i = 0; i < NodeCountMax; i++) { -+ if (nodes[i].is_connected != node_last_states[i]) { -+ if (nodes[i].is_connected) { -+ nodeChanges[i].state_change |= NodeStateChange::Connect; -+ } else { -+ nodeChanges[i].state_change |= NodeStateChange::Disconnect; -+ } -+ node_last_states[i] = nodes[i].is_connected; -+ changed = true; -+ } -+ } -+ return changed; -+} -+ -+bool LANDiscovery::IsFlagSet(ScanFilterFlag flag, ScanFilterFlag search_flag) const { -+ const auto flag_value = static_cast(flag); -+ const auto search_flag_value = static_cast(search_flag); -+ return (flag_value & search_flag_value) == search_flag_value; -+} -+ -+int LANDiscovery::GetStationCount() { -+ int count = 0; -+ for (const auto& station : stations) { -+ if (station.GetStatus() != NodeStatus::Disconnected) { -+ count++; -+ } -+ } -+ -+ return count; -+} -+ -+MacAddress LANDiscovery::GetFakeMac() const { -+ MacAddress mac{}; -+ mac.raw[0] = 0x02; -+ mac.raw[1] = 0x00; -+ -+ const auto ip = GetLocalIp(); -+ memcpy(mac.raw.data() + 2, &ip, sizeof(ip)); -+ -+ return mac; -+} -+ -+Result LANDiscovery::GetNodeInfo(NodeInfo& node, const UserConfig& userConfig, -+ u16 localCommunicationVersion) { -+ const auto network_interface = Network::GetSelectedNetworkInterface(); -+ -+ if (!network_interface) { -+ LOG_ERROR(Service_LDN, "No network interface available"); -+ return ResultNoIpAddress; -+ } -+ -+ node.mac_address = GetFakeMac(); -+ node.is_connected = 1; -+ std::memcpy(node.user_name.data(), userConfig.user_name.data(), UserNameBytesMax + 1); -+ node.local_communication_version = localCommunicationVersion; -+ -+ Ipv4Address current_address = GetLocalIp(); -+ std::reverse(std::begin(current_address), std::end(current_address)); // ntohl -+ node.ipv4_address = current_address; -+ -+ return ResultSuccess; -+} -+ -+} // namespace Service::LDN -diff --git a/src/core/hle/service/ldn/lan_discovery.h b/src/core/hle/service/ldn/lan_discovery.h -new file mode 100644 -index 000000000000..255342456eba ---- /dev/null -+++ b/src/core/hle/service/ldn/lan_discovery.h -@@ -0,0 +1,133 @@ -+// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project -+// SPDX-License-Identifier: GPL-2.0-or-later -+ -+#pragma once -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include "common/logging/log.h" -+#include "common/socket_types.h" -+#include "core/hle/result.h" -+#include "core/hle/service/ldn/ldn_results.h" -+#include "core/hle/service/ldn/ldn_types.h" -+#include "network/network.h" -+ -+namespace Service::LDN { -+ -+class LANDiscovery; -+ -+class LanStation { -+public: -+ LanStation(s8 node_id_, LANDiscovery* discovery_); -+ ~LanStation(); -+ -+ void OnClose(); -+ NodeStatus GetStatus() const; -+ void Reset(); -+ void OverrideInfo(); -+ -+protected: -+ friend class LANDiscovery; -+ NodeInfo* node_info; -+ NodeStatus status; -+ s8 node_id; -+ LANDiscovery* discovery; -+}; -+ -+class LANDiscovery { -+public: -+ typedef std::function LanEventFunc; -+ -+ LANDiscovery(Network::RoomNetwork& room_network_); -+ ~LANDiscovery(); -+ -+ State GetState() const; -+ void SetState(State new_state); -+ -+ Result GetNetworkInfo(NetworkInfo& out_network) const; -+ Result GetNetworkInfo(NetworkInfo& out_network, std::vector& out_updates, -+ std::size_t buffer_count); -+ -+ DisconnectReason GetDisconnectReason() const; -+ Result Scan(std::vector& networks, u16& count, const ScanFilter& filter); -+ Result SetAdvertiseData(std::vector& data); -+ -+ Result OpenAccessPoint(); -+ Result CloseAccessPoint(); -+ -+ Result OpenStation(); -+ Result CloseStation(); -+ -+ Result CreateNetwork(const SecurityConfig& security_config, const UserConfig& user_config, -+ const NetworkConfig& network_config); -+ Result DestroyNetwork(); -+ -+ Result Connect(const NetworkInfo& network_info_, const UserConfig& user_config, -+ u16 local_communication_version); -+ Result Disconnect(); -+ -+ Result Initialize(LanEventFunc lan_event = empty_func, bool listening = true); -+ Result Finalize(); -+ -+ void ReceivePacket(const Network::LDNPacket& packet); -+ -+protected: -+ friend class LanStation; -+ -+ void InitNetworkInfo(); -+ void InitNodeStateChange(); -+ -+ void ResetStations(); -+ void UpdateNodes(); -+ -+ void OnSyncNetwork(const NetworkInfo& info); -+ void OnDisconnectFromHost(); -+ void OnNetworkInfoChanged(); -+ -+ bool IsNodeStateChanged(); -+ bool IsFlagSet(ScanFilterFlag flag, ScanFilterFlag search_flag) const; -+ int GetStationCount(); -+ MacAddress GetFakeMac() const; -+ Result GetNodeInfo(NodeInfo& node, const UserConfig& user_config, -+ u16 local_communication_version); -+ -+ Network::IPv4Address GetLocalIp() const; -+ template -+ void SendPacket(Network::LDNPacketType type, const Data& data, Ipv4Address remote_ip); -+ void SendPacket(Network::LDNPacketType type, Ipv4Address remote_ip); -+ template -+ void SendBroadcast(Network::LDNPacketType type, const Data& data); -+ void SendBroadcast(Network::LDNPacketType type); -+ void SendPacket(const Network::LDNPacket& packet); -+ -+ static const LanEventFunc empty_func; -+ const Ssid fake_ssid{"YuzuFakeSsidForLdn"}; -+ -+ bool inited{}; -+ std::mutex packet_mutex; -+ std::array stations; -+ std::array nodeChanges{}; -+ std::array node_last_states{}; -+ std::unordered_map scan_results{}; -+ NodeInfo node_info{}; -+ NetworkInfo network_info{}; -+ State state{State::None}; -+ DisconnectReason disconnect_reason{DisconnectReason::None}; -+ -+ // TODO (flTobi): Should this be an std::set? -+ std::vector connected_clients; -+ std::optional host_ip = std::nullopt; -+ -+ LanEventFunc LanEvent; -+ -+ Network::RoomNetwork& room_network; -+}; -+} // namespace Service::LDN -diff --git a/src/core/hle/service/ldn/ldn.cpp b/src/core/hle/service/ldn/ldn.cpp -index c11daff547b6..6537f49cf2e9 100644 ---- a/src/core/hle/service/ldn/ldn.cpp -+++ b/src/core/hle/service/ldn/ldn.cpp -@@ -4,11 +4,13 @@ - #include - - #include "core/core.h" -+#include "core/hle/service/ldn/lan_discovery.h" - #include "core/hle/service/ldn/ldn.h" - #include "core/hle/service/ldn/ldn_results.h" - #include "core/hle/service/ldn/ldn_types.h" - #include "core/internal_network/network.h" - #include "core/internal_network/network_interface.h" -+#include "network/network.h" - - // This is defined by synchapi.h and conflicts with ServiceContext::CreateEvent - #undef CreateEvent -@@ -105,13 +107,13 @@ class IUserLocalCommunicationService final - public: - explicit IUserLocalCommunicationService(Core::System& system_) - : ServiceFramework{system_, "IUserLocalCommunicationService", ServiceThreadType::CreateNew}, -- service_context{system, "IUserLocalCommunicationService"}, room_network{ -- system_.GetRoomNetwork()} { -+ service_context{system, "IUserLocalCommunicationService"}, -+ room_network{system_.GetRoomNetwork()}, lan_discovery{room_network} { - // clang-format off - static const FunctionInfo functions[] = { - {0, &IUserLocalCommunicationService::GetState, "GetState"}, - {1, &IUserLocalCommunicationService::GetNetworkInfo, "GetNetworkInfo"}, -- {2, nullptr, "GetIpv4Address"}, -+ {2, &IUserLocalCommunicationService::GetIpv4Address, "GetIpv4Address"}, - {3, &IUserLocalCommunicationService::GetDisconnectReason, "GetDisconnectReason"}, - {4, &IUserLocalCommunicationService::GetSecurityParameter, "GetSecurityParameter"}, - {5, &IUserLocalCommunicationService::GetNetworkConfig, "GetNetworkConfig"}, -@@ -119,7 +121,7 @@ class IUserLocalCommunicationService final - {101, &IUserLocalCommunicationService::GetNetworkInfoLatestUpdate, "GetNetworkInfoLatestUpdate"}, - {102, &IUserLocalCommunicationService::Scan, "Scan"}, - {103, &IUserLocalCommunicationService::ScanPrivate, "ScanPrivate"}, -- {104, nullptr, "SetWirelessControllerRestriction"}, -+ {104, &IUserLocalCommunicationService::SetWirelessControllerRestriction, "SetWirelessControllerRestriction"}, - {200, &IUserLocalCommunicationService::OpenAccessPoint, "OpenAccessPoint"}, - {201, &IUserLocalCommunicationService::CloseAccessPoint, "CloseAccessPoint"}, - {202, &IUserLocalCommunicationService::CreateNetwork, "CreateNetwork"}, -@@ -148,16 +150,30 @@ class IUserLocalCommunicationService final - } - - ~IUserLocalCommunicationService() { -+ if (is_initialized) { -+ if (auto room_member = room_network.GetRoomMember().lock()) { -+ room_member->Unbind(ldn_packet_received); -+ } -+ } -+ - service_context.CloseEvent(state_change_event); - } - -+ /// Callback to parse and handle a received LDN packet. -+ void OnLDNPacketReceived(const Network::LDNPacket& packet) { -+ lan_discovery.ReceivePacket(packet); -+ } -+ - void OnEventFired() { - state_change_event->GetWritableEvent().Signal(); - } - - void GetState(Kernel::HLERequestContext& ctx) { - State state = State::Error; -- LOG_WARNING(Service_LDN, "(STUBBED) called, state = {}", state); -+ -+ if (is_initialized) { -+ state = lan_discovery.GetState(); -+ } - - IPC::ResponseBuilder rb{ctx, 3}; - rb.Push(ResultSuccess); -@@ -175,7 +191,7 @@ class IUserLocalCommunicationService final - } - - NetworkInfo network_info{}; -- const auto rc = ResultSuccess; -+ const auto rc = lan_discovery.GetNetworkInfo(network_info); - if (rc.IsError()) { - LOG_ERROR(Service_LDN, "NetworkInfo is not valid {}", rc.raw); - IPC::ResponseBuilder rb{ctx, 2}; -@@ -183,28 +199,52 @@ class IUserLocalCommunicationService final - return; - } - -- LOG_WARNING(Service_LDN, "(STUBBED) called, ssid='{}', nodes={}", -- network_info.common.ssid.GetStringValue(), network_info.ldn.node_count); -- - ctx.WriteBuffer(network_info); - IPC::ResponseBuilder rb{ctx, 2}; -- rb.Push(rc); -+ rb.Push(ResultSuccess); - } - -- void GetDisconnectReason(Kernel::HLERequestContext& ctx) { -- const auto disconnect_reason = DisconnectReason::None; -+ void GetIpv4Address(Kernel::HLERequestContext& ctx) { -+ LOG_CRITICAL(Service_LDN, "called"); - -- LOG_WARNING(Service_LDN, "(STUBBED) called, disconnect_reason={}", disconnect_reason); -+ const auto network_interface = Network::GetSelectedNetworkInterface(); -+ -+ if (!network_interface) { -+ LOG_ERROR(Service_LDN, "No network interface available"); -+ IPC::ResponseBuilder rb{ctx, 2}; -+ rb.Push(ResultNoIpAddress); -+ return; -+ } -+ -+ Ipv4Address current_address{Network::TranslateIPv4(network_interface->ip_address)}; -+ Ipv4Address subnet_mask{Network::TranslateIPv4(network_interface->subnet_mask)}; -+ -+ // When we're connected to a room, spoof the hosts IP address -+ if (auto room_member = room_network.GetRoomMember().lock()) { -+ if (room_member->IsConnected()) { -+ current_address = room_member->GetFakeIpAddress(); -+ } -+ } -+ -+ std::reverse(std::begin(current_address), std::end(current_address)); // ntohl -+ std::reverse(std::begin(subnet_mask), std::end(subnet_mask)); // ntohl -+ -+ IPC::ResponseBuilder rb{ctx, 4}; -+ rb.Push(ResultSuccess); -+ rb.PushRaw(current_address); -+ rb.PushRaw(subnet_mask); -+ } - -+ void GetDisconnectReason(Kernel::HLERequestContext& ctx) { - IPC::ResponseBuilder rb{ctx, 3}; - rb.Push(ResultSuccess); -- rb.PushEnum(disconnect_reason); -+ rb.PushEnum(lan_discovery.GetDisconnectReason()); - } - - void GetSecurityParameter(Kernel::HLERequestContext& ctx) { - SecurityParameter security_parameter{}; - NetworkInfo info{}; -- const Result rc = ResultSuccess; -+ const Result rc = lan_discovery.GetNetworkInfo(info); - - if (rc.IsError()) { - LOG_ERROR(Service_LDN, "NetworkInfo is not valid {}", rc.raw); -@@ -217,8 +257,6 @@ class IUserLocalCommunicationService final - std::memcpy(security_parameter.data.data(), info.ldn.security_parameter.data(), - sizeof(SecurityParameter::data)); - -- LOG_WARNING(Service_LDN, "(STUBBED) called"); -- - IPC::ResponseBuilder rb{ctx, 10}; - rb.Push(rc); - rb.PushRaw(security_parameter); -@@ -227,7 +265,7 @@ class IUserLocalCommunicationService final - void GetNetworkConfig(Kernel::HLERequestContext& ctx) { - NetworkConfig config{}; - NetworkInfo info{}; -- const Result rc = ResultSuccess; -+ const Result rc = lan_discovery.GetNetworkInfo(info); - - if (rc.IsError()) { - LOG_ERROR(Service_LDN, "NetworkConfig is not valid {}", rc.raw); -@@ -241,12 +279,6 @@ class IUserLocalCommunicationService final - config.node_count_max = info.ldn.node_count_max; - config.local_communication_version = info.ldn.nodes[0].local_communication_version; - -- LOG_WARNING(Service_LDN, -- "(STUBBED) called, intent_id={}/{}, channel={}, node_count_max={}, " -- "local_communication_version={}", -- config.intent_id.local_communication_id, config.intent_id.scene_id, -- config.channel, config.node_count_max, config.local_communication_version); -- - IPC::ResponseBuilder rb{ctx, 10}; - rb.Push(rc); - rb.PushRaw(config); -@@ -265,17 +297,17 @@ class IUserLocalCommunicationService final - const std::size_t node_buffer_count = ctx.GetWriteBufferSize(1) / sizeof(NodeLatestUpdate); - - if (node_buffer_count == 0 || network_buffer_size != sizeof(NetworkInfo)) { -- LOG_ERROR(Service_LDN, "Invalid buffer size {}, {}", network_buffer_size, -+ LOG_ERROR(Service_LDN, "Invalid buffer, size = {}, count = {}", network_buffer_size, - node_buffer_count); - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ResultBadInput); - return; - } - -- NetworkInfo info; -+ NetworkInfo info{}; - std::vector latest_update(node_buffer_count); - -- const auto rc = ResultSuccess; -+ const auto rc = lan_discovery.GetNetworkInfo(info, latest_update, latest_update.size()); - if (rc.IsError()) { - LOG_ERROR(Service_LDN, "NetworkInfo is not valid {}", rc.raw); - IPC::ResponseBuilder rb{ctx, 2}; -@@ -283,9 +315,6 @@ class IUserLocalCommunicationService final - return; - } - -- LOG_WARNING(Service_LDN, "(STUBBED) called, ssid='{}', nodes={}", -- info.common.ssid.GetStringValue(), info.ldn.node_count); -- - ctx.WriteBuffer(info, 0); - ctx.WriteBuffer(latest_update, 1); - -@@ -317,92 +346,78 @@ class IUserLocalCommunicationService final - - u16 count = 0; - std::vector network_infos(network_info_size); -+ Result rc = lan_discovery.Scan(network_infos, count, scan_filter); - -- LOG_WARNING(Service_LDN, -- "(STUBBED) called, channel={}, filter_scan_flag={}, filter_network_type={}", -- channel, scan_filter.flag, scan_filter.network_type); -+ LOG_INFO(Service_LDN, -+ "called, channel={}, filter_scan_flag={}, filter_network_type={}, is_private={}", -+ channel, scan_filter.flag, scan_filter.network_type, is_private); - - ctx.WriteBuffer(network_infos); - - IPC::ResponseBuilder rb{ctx, 3}; -- rb.Push(ResultSuccess); -+ rb.Push(rc); - rb.Push(count); - } - -- void OpenAccessPoint(Kernel::HLERequestContext& ctx) { -+ void SetWirelessControllerRestriction(Kernel::HLERequestContext& ctx) { - LOG_WARNING(Service_LDN, "(STUBBED) called"); - - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ResultSuccess); - } - -+ void OpenAccessPoint(Kernel::HLERequestContext& ctx) { -+ LOG_INFO(Service_LDN, "called"); -+ -+ IPC::ResponseBuilder rb{ctx, 2}; -+ rb.Push(lan_discovery.OpenAccessPoint()); -+ } -+ - void CloseAccessPoint(Kernel::HLERequestContext& ctx) { -- LOG_WARNING(Service_LDN, "(STUBBED) called"); -+ LOG_INFO(Service_LDN, "called"); - - IPC::ResponseBuilder rb{ctx, 2}; -- rb.Push(ResultSuccess); -+ rb.Push(lan_discovery.CloseAccessPoint()); - } - - void CreateNetwork(Kernel::HLERequestContext& ctx) { -- IPC::RequestParser rp{ctx}; -- struct Parameters { -- SecurityConfig security_config; -- UserConfig user_config; -- INSERT_PADDING_WORDS_NOINIT(1); -- NetworkConfig network_config; -- }; -- static_assert(sizeof(Parameters) == 0x98, "Parameters has incorrect size."); -+ LOG_INFO(Service_LDN, "called"); - -- const auto parameters{rp.PopRaw()}; -+ CreateNetworkImpl(ctx); -+ } - -- LOG_WARNING(Service_LDN, -- "(STUBBED) called, passphrase_size={}, security_mode={}, " -- "local_communication_version={}", -- parameters.security_config.passphrase_size, -- parameters.security_config.security_mode, -- parameters.network_config.local_communication_version); -+ void CreateNetworkPrivate(Kernel::HLERequestContext& ctx) { -+ LOG_INFO(Service_LDN, "called"); - -- IPC::ResponseBuilder rb{ctx, 2}; -- rb.Push(ResultSuccess); -+ CreateNetworkImpl(ctx, true); - } - -- void CreateNetworkPrivate(Kernel::HLERequestContext& ctx) { -+ void CreateNetworkImpl(Kernel::HLERequestContext& ctx, bool is_private = false) { - IPC::RequestParser rp{ctx}; -- struct Parameters { -- SecurityConfig security_config; -- SecurityParameter security_parameter; -- UserConfig user_config; -- NetworkConfig network_config; -- }; -- static_assert(sizeof(Parameters) == 0xB8, "Parameters has incorrect size."); -- -- const auto parameters{rp.PopRaw()}; - -- LOG_WARNING(Service_LDN, -- "(STUBBED) called, passphrase_size={}, security_mode={}, " -- "local_communication_version={}", -- parameters.security_config.passphrase_size, -- parameters.security_config.security_mode, -- parameters.network_config.local_communication_version); -+ const auto security_config{rp.PopRaw()}; -+ [[maybe_unused]] const auto security_parameter{is_private ? rp.PopRaw() -+ : SecurityParameter{}}; -+ const auto user_config{rp.PopRaw()}; -+ rp.Pop(); // Padding -+ const auto network_Config{rp.PopRaw()}; - - IPC::ResponseBuilder rb{ctx, 2}; -- rb.Push(ResultSuccess); -+ rb.Push(lan_discovery.CreateNetwork(security_config, user_config, network_Config)); - } - - void DestroyNetwork(Kernel::HLERequestContext& ctx) { -- LOG_WARNING(Service_LDN, "(STUBBED) called"); -+ LOG_INFO(Service_LDN, "called"); - - IPC::ResponseBuilder rb{ctx, 2}; -- rb.Push(ResultSuccess); -+ rb.Push(lan_discovery.DestroyNetwork()); - } - - void SetAdvertiseData(Kernel::HLERequestContext& ctx) { - std::vector read_buffer = ctx.ReadBuffer(); - -- LOG_WARNING(Service_LDN, "(STUBBED) called, size {}", read_buffer.size()); -- - IPC::ResponseBuilder rb{ctx, 2}; -- rb.Push(ResultSuccess); -+ rb.Push(lan_discovery.SetAdvertiseData(read_buffer)); - } - - void SetStationAcceptPolicy(Kernel::HLERequestContext& ctx) { -@@ -420,17 +435,17 @@ class IUserLocalCommunicationService final - } - - void OpenStation(Kernel::HLERequestContext& ctx) { -- LOG_WARNING(Service_LDN, "(STUBBED) called"); -+ LOG_INFO(Service_LDN, "called"); - - IPC::ResponseBuilder rb{ctx, 2}; -- rb.Push(ResultSuccess); -+ rb.Push(lan_discovery.OpenStation()); - } - - void CloseStation(Kernel::HLERequestContext& ctx) { -- LOG_WARNING(Service_LDN, "(STUBBED) called"); -+ LOG_INFO(Service_LDN, "called"); - - IPC::ResponseBuilder rb{ctx, 2}; -- rb.Push(ResultSuccess); -+ rb.Push(lan_discovery.CloseStation()); - } - - void Connect(Kernel::HLERequestContext& ctx) { -@@ -445,16 +460,13 @@ class IUserLocalCommunicationService final - - const auto parameters{rp.PopRaw()}; - -- LOG_WARNING(Service_LDN, -- "(STUBBED) called, passphrase_size={}, security_mode={}, " -- "local_communication_version={}", -- parameters.security_config.passphrase_size, -- parameters.security_config.security_mode, -- parameters.local_communication_version); -+ LOG_INFO(Service_LDN, -+ "called, passphrase_size={}, security_mode={}, " -+ "local_communication_version={}", -+ parameters.security_config.passphrase_size, -+ parameters.security_config.security_mode, parameters.local_communication_version); - - const std::vector read_buffer = ctx.ReadBuffer(); -- NetworkInfo network_info{}; -- - if (read_buffer.size() != sizeof(NetworkInfo)) { - LOG_ERROR(Frontend, "NetworkInfo doesn't match read_buffer size!"); - IPC::ResponseBuilder rb{ctx, 2}; -@@ -462,40 +474,47 @@ class IUserLocalCommunicationService final - return; - } - -+ NetworkInfo network_info{}; - std::memcpy(&network_info, read_buffer.data(), read_buffer.size()); - - IPC::ResponseBuilder rb{ctx, 2}; -- rb.Push(ResultSuccess); -+ rb.Push(lan_discovery.Connect(network_info, parameters.user_config, -+ static_cast(parameters.local_communication_version))); - } - - void Disconnect(Kernel::HLERequestContext& ctx) { -- LOG_WARNING(Service_LDN, "(STUBBED) called"); -+ LOG_INFO(Service_LDN, "called"); - - IPC::ResponseBuilder rb{ctx, 2}; -- rb.Push(ResultSuccess); -+ rb.Push(lan_discovery.Disconnect()); - } -- void Initialize(Kernel::HLERequestContext& ctx) { -- LOG_WARNING(Service_LDN, "(STUBBED) called"); - -+ void Initialize(Kernel::HLERequestContext& ctx) { - const auto rc = InitializeImpl(ctx); -+ if (rc.IsError()) { -+ LOG_ERROR(Service_LDN, "Network isn't initialized, rc={}", rc.raw); -+ } - - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(rc); - } - - void Finalize(Kernel::HLERequestContext& ctx) { -- LOG_WARNING(Service_LDN, "(STUBBED) called"); -+ if (auto room_member = room_network.GetRoomMember().lock()) { -+ room_member->Unbind(ldn_packet_received); -+ } - - is_initialized = false; - - IPC::ResponseBuilder rb{ctx, 2}; -- rb.Push(ResultSuccess); -+ rb.Push(lan_discovery.Finalize()); - } - - void Initialize2(Kernel::HLERequestContext& ctx) { -- LOG_WARNING(Service_LDN, "(STUBBED) called"); -- - const auto rc = InitializeImpl(ctx); -+ if (rc.IsError()) { -+ LOG_ERROR(Service_LDN, "Network isn't initialized, rc={}", rc.raw); -+ } - - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(rc); -@@ -508,14 +527,26 @@ class IUserLocalCommunicationService final - return ResultAirplaneModeEnabled; - } - -+ if (auto room_member = room_network.GetRoomMember().lock()) { -+ ldn_packet_received = room_member->BindOnLdnPacketReceived( -+ [this](const Network::LDNPacket& packet) { OnLDNPacketReceived(packet); }); -+ } else { -+ LOG_ERROR(Service_LDN, "Couldn't bind callback!"); -+ return ResultAirplaneModeEnabled; -+ } -+ -+ lan_discovery.Initialize([&]() { OnEventFired(); }); - is_initialized = true; -- // TODO (flTobi): Change this to ResultSuccess when LDN is fully implemented -- return ResultAirplaneModeEnabled; -+ return ResultSuccess; - } - - KernelHelpers::ServiceContext service_context; - Kernel::KEvent* state_change_event; - Network::RoomNetwork& room_network; -+ LANDiscovery lan_discovery; -+ -+ // Callback identifier for the OnLDNPacketReceived event. -+ Network::RoomMember::CallbackHandle ldn_packet_received; - - bool is_initialized{}; - }; -diff --git a/src/core/hle/service/ldn/ldn_types.h b/src/core/hle/service/ldn/ldn_types.h -index 6231e936dade..d6609fff55fd 100644 ---- a/src/core/hle/service/ldn/ldn_types.h -+++ b/src/core/hle/service/ldn/ldn_types.h -@@ -31,6 +31,14 @@ enum class NodeStateChange : u8 { - DisconnectAndConnect, - }; - -+inline NodeStateChange operator|(NodeStateChange a, NodeStateChange b) { -+ return static_cast(static_cast(a) | static_cast(b)); -+} -+ -+inline NodeStateChange operator|=(NodeStateChange& a, NodeStateChange b) { -+ return a = a | b; -+} -+ - enum class ScanFilterFlag : u32 { - None = 0, - LocalCommunicationId = 1 << 0, -@@ -100,13 +108,13 @@ enum class AcceptPolicy : u8 { - - enum class WifiChannel : s16 { - Default = 0, -- wifi24_1 = 1, -- wifi24_6 = 6, -- wifi24_11 = 11, -- wifi50_36 = 36, -- wifi50_40 = 40, -- wifi50_44 = 44, -- wifi50_48 = 48, -+ Wifi24_1 = 1, -+ Wifi24_6 = 6, -+ Wifi24_11 = 11, -+ Wifi50_36 = 36, -+ Wifi50_40 = 40, -+ Wifi50_44 = 44, -+ Wifi50_48 = 48, - }; - - enum class LinkLevel : s8 { -@@ -116,6 +124,11 @@ enum class LinkLevel : s8 { - Excellent, - }; - -+enum class NodeStatus : u8 { -+ Disconnected, -+ Connected, -+}; -+ - struct NodeLatestUpdate { - NodeStateChange state_change; - INSERT_PADDING_BYTES(0x7); // Unknown -@@ -159,19 +172,14 @@ struct Ssid { - std::string GetStringValue() const { - return std::string(raw.data()); - } --}; --static_assert(sizeof(Ssid) == 0x22, "Ssid is an invalid size"); -- --struct Ipv4Address { -- union { -- u32 raw{}; -- std::array bytes; -- }; - -- std::string GetStringValue() const { -- return fmt::format("{}.{}.{}.{}", bytes[3], bytes[2], bytes[1], bytes[0]); -+ bool operator==(const Ssid& b) const { -+ return (length == b.length) && (std::memcmp(raw.data(), b.raw.data(), length) == 0); - } - }; -+static_assert(sizeof(Ssid) == 0x22, "Ssid is an invalid size"); -+ -+using Ipv4Address = std::array; - static_assert(sizeof(Ipv4Address) == 0x4, "Ipv4Address is an invalid size"); - - struct MacAddress { -@@ -181,6 +189,14 @@ struct MacAddress { - }; - static_assert(sizeof(MacAddress) == 0x6, "MacAddress is an invalid size"); - -+struct MACAddressHash { -+ size_t operator()(const MacAddress& address) const { -+ u64 value{}; -+ std::memcpy(&value, address.raw.data(), sizeof(address.raw)); -+ return value; -+ } -+}; -+ - struct ScanFilter { - NetworkId network_id; - NetworkType network_type; -diff --git a/src/core/internal_network/socket_proxy.cpp b/src/core/internal_network/socket_proxy.cpp -index 0c746bd82427..7d5d37bbcd7f 100644 ---- a/src/core/internal_network/socket_proxy.cpp -+++ b/src/core/internal_network/socket_proxy.cpp -@@ -6,6 +6,7 @@ - - #include "common/assert.h" - #include "common/logging/log.h" -+#include "common/zstd_compression.h" - #include "core/internal_network/network.h" - #include "core/internal_network/network_interface.h" - #include "core/internal_network/socket_proxy.h" -@@ -32,8 +33,11 @@ void ProxySocket::HandleProxyPacket(const ProxyPacket& packet) { - return; - } - -+ auto decompressed = packet; -+ decompressed.data = Common::Compression::DecompressDataZSTD(packet.data); -+ - std::lock_guard guard(packets_mutex); -- received_packets.push(packet); -+ received_packets.push(decompressed); - } - - template -@@ -185,6 +189,8 @@ std::pair ProxySocket::Send(const std::vector& message, int flag - void ProxySocket::SendPacket(ProxyPacket& packet) { - if (auto room_member = room_network.GetRoomMember().lock()) { - if (room_member->IsConnected()) { -+ packet.data = Common::Compression::CompressDataZSTDDefault(packet.data.data(), -+ packet.data.size()); - room_member->SendProxyPacket(packet); - } - } -diff --git a/src/dedicated_room/yuzu_room.cpp b/src/dedicated_room/yuzu_room.cpp -index 7b6deba417fd..8d8ac1ed74f1 100644 ---- a/src/dedicated_room/yuzu_room.cpp -+++ b/src/dedicated_room/yuzu_room.cpp -@@ -76,7 +76,8 @@ static constexpr char BanListMagic[] = "YuzuRoom-BanList-1"; - static constexpr char token_delimiter{':'}; - - static void PadToken(std::string& token) { -- while (token.size() % 4 != 0) { -+ const auto remainder = token.size() % 3; -+ for (size_t i = 0; i < (3 - remainder); i++) { - token.push_back('='); - } - } -diff --git a/src/network/room.cpp b/src/network/room.cpp -index 8c63b255bc29..dc5dbce7fa95 100644 ---- a/src/network/room.cpp -+++ b/src/network/room.cpp -@@ -211,6 +211,12 @@ class Room::RoomImpl { - */ - void HandleProxyPacket(const ENetEvent* event); - -+ /** -+ * Broadcasts this packet to all members except the sender. -+ * @param event The ENet event containing the data -+ */ -+ void HandleLdnPacket(const ENetEvent* event); -+ - /** - * Extracts a chat entry from a received ENet packet and adds it to the chat queue. - * @param event The ENet event that was received. -@@ -247,6 +253,9 @@ void Room::RoomImpl::ServerLoop() { - case IdProxyPacket: - HandleProxyPacket(&event); - break; -+ case IdLdnPacket: -+ HandleLdnPacket(&event); -+ break; - case IdChatMessage: - HandleChatPacket(&event); - break; -@@ -861,6 +870,60 @@ void Room::RoomImpl::HandleProxyPacket(const ENetEvent* event) { - enet_host_flush(server); - } - -+void Room::RoomImpl::HandleLdnPacket(const ENetEvent* event) { -+ Packet in_packet; -+ in_packet.Append(event->packet->data, event->packet->dataLength); -+ -+ in_packet.IgnoreBytes(sizeof(u8)); // Message type -+ -+ in_packet.IgnoreBytes(sizeof(u8)); // LAN packet type -+ in_packet.IgnoreBytes(sizeof(IPv4Address)); // Local IP -+ -+ IPv4Address remote_ip; -+ in_packet.Read(remote_ip); // Remote IP -+ -+ bool broadcast; -+ in_packet.Read(broadcast); // Broadcast -+ -+ Packet out_packet; -+ out_packet.Append(event->packet->data, event->packet->dataLength); -+ ENetPacket* enet_packet = enet_packet_create(out_packet.GetData(), out_packet.GetDataSize(), -+ ENET_PACKET_FLAG_RELIABLE); -+ -+ const auto& destination_address = remote_ip; -+ if (broadcast) { // Send the data to everyone except the sender -+ std::lock_guard lock(member_mutex); -+ bool sent_packet = false; -+ for (const auto& member : members) { -+ if (member.peer != event->peer) { -+ sent_packet = true; -+ enet_peer_send(member.peer, 0, enet_packet); -+ } -+ } -+ -+ if (!sent_packet) { -+ enet_packet_destroy(enet_packet); -+ } -+ } else { -+ std::lock_guard lock(member_mutex); -+ auto member = std::find_if(members.begin(), members.end(), -+ [destination_address](const Member& member_entry) -> bool { -+ return member_entry.fake_ip == destination_address; -+ }); -+ if (member != members.end()) { -+ enet_peer_send(member->peer, 0, enet_packet); -+ } else { -+ LOG_ERROR(Network, -+ "Attempting to send to unknown IP address: " -+ "{}.{}.{}.{}", -+ destination_address[0], destination_address[1], destination_address[2], -+ destination_address[3]); -+ enet_packet_destroy(enet_packet); -+ } -+ } -+ enet_host_flush(server); -+} -+ - void Room::RoomImpl::HandleChatPacket(const ENetEvent* event) { - Packet in_packet; - in_packet.Append(event->packet->data, event->packet->dataLength); -diff --git a/src/network/room.h b/src/network/room.h -index c2a4b1a70240..edbd3ecfb23f 100644 ---- a/src/network/room.h -+++ b/src/network/room.h -@@ -40,6 +40,7 @@ enum RoomMessageTypes : u8 { - IdRoomInformation, - IdSetGameInfo, - IdProxyPacket, -+ IdLdnPacket, - IdChatMessage, - IdNameCollision, - IdIpCollision, -diff --git a/src/network/room_member.cpp b/src/network/room_member.cpp -index 06818af783c7..572e55a5b83c 100644 ---- a/src/network/room_member.cpp -+++ b/src/network/room_member.cpp -@@ -58,6 +58,7 @@ class RoomMember::RoomMemberImpl { - - private: - CallbackSet callback_set_proxy_packet; -+ CallbackSet callback_set_ldn_packet; - CallbackSet callback_set_chat_messages; - CallbackSet callback_set_status_messages; - CallbackSet callback_set_room_information; -@@ -107,6 +108,12 @@ class RoomMember::RoomMemberImpl { - */ - void HandleProxyPackets(const ENetEvent* event); - -+ /** -+ * Extracts an LdnPacket from a received ENet packet. -+ * @param event The ENet event that was received. -+ */ -+ void HandleLdnPackets(const ENetEvent* event); -+ - /** - * Extracts a chat entry from a received ENet packet and adds it to the chat queue. - * @param event The ENet event that was received. -@@ -166,6 +173,9 @@ void RoomMember::RoomMemberImpl::MemberLoop() { - case IdProxyPacket: - HandleProxyPackets(&event); - break; -+ case IdLdnPacket: -+ HandleLdnPackets(&event); -+ break; - case IdChatMessage: - HandleChatPacket(&event); - break; -@@ -372,6 +382,27 @@ void RoomMember::RoomMemberImpl::HandleProxyPackets(const ENetEvent* event) { - Invoke(proxy_packet); - } - -+void RoomMember::RoomMemberImpl::HandleLdnPackets(const ENetEvent* event) { -+ LDNPacket ldn_packet{}; -+ Packet packet; -+ packet.Append(event->packet->data, event->packet->dataLength); -+ -+ // Ignore the first byte, which is the message id. -+ packet.IgnoreBytes(sizeof(u8)); // Ignore the message type -+ -+ u8 packet_type; -+ packet.Read(packet_type); -+ ldn_packet.type = static_cast(packet_type); -+ -+ packet.Read(ldn_packet.local_ip); -+ packet.Read(ldn_packet.remote_ip); -+ packet.Read(ldn_packet.broadcast); -+ -+ packet.Read(ldn_packet.data); -+ -+ Invoke(ldn_packet); -+} -+ - void RoomMember::RoomMemberImpl::HandleChatPacket(const ENetEvent* event) { - Packet packet; - packet.Append(event->packet->data, event->packet->dataLength); -@@ -449,6 +480,11 @@ RoomMember::RoomMemberImpl::CallbackSet& RoomMember::RoomMemberImpl - return callback_set_proxy_packet; - } - -+template <> -+RoomMember::RoomMemberImpl::CallbackSet& RoomMember::RoomMemberImpl::Callbacks::Get() { -+ return callback_set_ldn_packet; -+} -+ - template <> - RoomMember::RoomMemberImpl::CallbackSet& - RoomMember::RoomMemberImpl::Callbacks::Get() { -@@ -607,6 +643,21 @@ void RoomMember::SendProxyPacket(const ProxyPacket& proxy_packet) { - room_member_impl->Send(std::move(packet)); - } - -+void RoomMember::SendLdnPacket(const LDNPacket& ldn_packet) { -+ Packet packet; -+ packet.Write(static_cast(IdLdnPacket)); -+ -+ packet.Write(static_cast(ldn_packet.type)); -+ -+ packet.Write(ldn_packet.local_ip); -+ packet.Write(ldn_packet.remote_ip); -+ packet.Write(ldn_packet.broadcast); -+ -+ packet.Write(ldn_packet.data); -+ -+ room_member_impl->Send(std::move(packet)); -+} -+ - void RoomMember::SendChatMessage(const std::string& message) { - Packet packet; - packet.Write(static_cast(IdChatMessage)); -@@ -663,6 +714,11 @@ RoomMember::CallbackHandle RoomMember::BindOnProxyPacketReceived( - return room_member_impl->Bind(callback); - } - -+RoomMember::CallbackHandle RoomMember::BindOnLdnPacketReceived( -+ std::function callback) { -+ return room_member_impl->Bind(callback); -+} -+ - RoomMember::CallbackHandle RoomMember::BindOnRoomInformationChanged( - std::function callback) { - return room_member_impl->Bind(callback); -@@ -699,6 +755,7 @@ void RoomMember::Leave() { - } - - template void RoomMember::Unbind(CallbackHandle); -+template void RoomMember::Unbind(CallbackHandle); - template void RoomMember::Unbind(CallbackHandle); - template void RoomMember::Unbind(CallbackHandle); - template void RoomMember::Unbind(CallbackHandle); -diff --git a/src/network/room_member.h b/src/network/room_member.h -index f578f7f6a31a..0d6417294579 100644 ---- a/src/network/room_member.h -+++ b/src/network/room_member.h -@@ -17,7 +17,24 @@ namespace Network { - using AnnounceMultiplayerRoom::GameInfo; - using AnnounceMultiplayerRoom::RoomInformation; - --/// Information about the received WiFi packets. -+enum class LDNPacketType : u8 { -+ Scan, -+ ScanResp, -+ Connect, -+ SyncNetwork, -+ Disconnect, -+ DestroyNetwork, -+}; -+ -+struct LDNPacket { -+ LDNPacketType type; -+ IPv4Address local_ip; -+ IPv4Address remote_ip; -+ bool broadcast; -+ std::vector data; -+}; -+ -+/// Information about the received proxy packets. - struct ProxyPacket { - SockAddrIn local_endpoint; - SockAddrIn remote_endpoint; -@@ -151,6 +168,12 @@ class RoomMember final { - */ - void SendProxyPacket(const ProxyPacket& packet); - -+ /** -+ * Sends an LDN packet to the room. -+ * @param packet The WiFi packet to send. -+ */ -+ void SendLdnPacket(const LDNPacket& packet); -+ - /** - * Sends a chat message to the room. - * @param message The contents of the message. -@@ -204,6 +227,16 @@ class RoomMember final { - CallbackHandle BindOnProxyPacketReceived( - std::function callback); - -+ /** -+ * Binds a function to an event that will be triggered every time an LDNPacket is received. -+ * The function wil be called everytime the event is triggered. -+ * The callback function must not bind or unbind a function. Doing so will cause a deadlock -+ * @param callback The function to call -+ * @return A handle used for removing the function from the registered list -+ */ -+ CallbackHandle BindOnLdnPacketReceived( -+ std::function callback); -+ - /** - * Binds a function to an event that will be triggered every time the RoomInformation changes. - * The function wil be called every time the event is triggered. -diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp -index a85adc072429..9dfa8d639c26 100644 ---- a/src/yuzu/main.cpp -+++ b/src/yuzu/main.cpp -@@ -896,8 +896,8 @@ void GMainWindow::InitializeWidgets() { - } - - // TODO (flTobi): Add the widget when multiplayer is fully implemented -- // statusBar()->addPermanentWidget(multiplayer_state->GetStatusText(), 0); -- // statusBar()->addPermanentWidget(multiplayer_state->GetStatusIcon(), 0); -+ statusBar()->addPermanentWidget(multiplayer_state->GetStatusText(), 0); -+ statusBar()->addPermanentWidget(multiplayer_state->GetStatusIcon(), 0); - - tas_label = new QLabel(); - tas_label->setObjectName(QStringLiteral("TASlabel")); -diff --git a/src/yuzu/main.ui b/src/yuzu/main.ui -index cdf31b417d75..60a8deab1c9a 100644 ---- a/src/yuzu/main.ui -+++ b/src/yuzu/main.ui -@@ -120,6 +120,20 @@ - - - -+ -+ -+ true -+ -+ -+ Multiplayer -+ -+ -+ -+ -+ -+ -+ -+ - - - &Tools -diff --git a/src/yuzu/multiplayer/chat_room.cpp b/src/yuzu/multiplayer/chat_room.cpp -index 9e672f82e98d..dec9696c186e 100644 ---- a/src/yuzu/multiplayer/chat_room.cpp -+++ b/src/yuzu/multiplayer/chat_room.cpp -@@ -61,7 +61,10 @@ class ChatMessage { - - /// Format the message using the players color - QString GetPlayerChatMessage(u16 player) const { -- auto color = player_color[player % 16]; -+ const bool is_dark_theme = QIcon::themeName().contains(QStringLiteral("dark")) || -+ QIcon::themeName().contains(QStringLiteral("midnight")); -+ auto color = -+ is_dark_theme ? player_color_dark[player % 16] : player_color_default[player % 16]; - QString name; - if (username.isEmpty() || username == nickname) { - name = nickname; -@@ -84,9 +87,12 @@ class ChatMessage { - } - - private: -- static constexpr std::array player_color = { -+ static constexpr std::array player_color_default = { - {"#0000FF", "#FF0000", "#8A2BE2", "#FF69B4", "#1E90FF", "#008000", "#00FF7F", "#B22222", -- "#DAA520", "#FF4500", "#2E8B57", "#5F9EA0", "#D2691E", "#9ACD32", "#FF7F50", "FFFF00"}}; -+ "#DAA520", "#FF4500", "#2E8B57", "#5F9EA0", "#D2691E", "#9ACD32", "#FF7F50", "#FFFF00"}}; -+ static constexpr std::array player_color_dark = { -+ {"#559AD1", "#4EC9A8", "#D69D85", "#C6C923", "#B975B5", "#D81F1F", "#7EAE39", "#4F8733", -+ "#F7CD8A", "#6FCACF", "#CE4897", "#8A2BE2", "#D2691E", "#9ACD32", "#FF7F50", "#152ccd"}}; - static constexpr char ping_color[] = "#FFFF00"; - - QString timestamp; -diff --git a/src/yuzu/multiplayer/state.cpp b/src/yuzu/multiplayer/state.cpp -index 66e098296d02..3ad8460281db 100644 ---- a/src/yuzu/multiplayer/state.cpp -+++ b/src/yuzu/multiplayer/state.cpp -@@ -249,6 +249,7 @@ void MultiplayerState::ShowNotification() { - return; // Do not show notification if the chat window currently has focus - show_notification = true; - QApplication::alert(nullptr); -+ QApplication::beep(); - status_icon->setPixmap(QIcon::fromTheme(QStringLiteral("connected_notification")).pixmap(16)); - status_text->setText(tr("New Messages Received")); - } - -From 8f207bd93ddb9778f0242fca0dab6ef155bd2a97 Mon Sep 17 00:00:00 2001 -From: german77 -Date: Fri, 9 Sep 2022 15:29:22 -0500 -Subject: [PATCH 2/5] yuzu: Multiple room UI improvements - ---- - src/core/hle/service/hid/hid.cpp | 3 +- - .../internal_network/network_interface.cpp | 10 +++ - src/core/internal_network/network_interface.h | 1 + - src/yuzu/main.cpp | 8 ++ - src/yuzu/main.h | 1 + - src/yuzu/main.ui | 10 +-- - src/yuzu/multiplayer/client_room.cpp | 3 +- - src/yuzu/multiplayer/direct_connect.cpp | 2 + - src/yuzu/multiplayer/direct_connect.h | 1 + - src/yuzu/multiplayer/host_room.cpp | 1 + - src/yuzu/multiplayer/host_room.h | 3 + - src/yuzu/multiplayer/lobby.cpp | 67 +++++++++++----- - src/yuzu/multiplayer/lobby.h | 8 ++ - src/yuzu/multiplayer/lobby_p.h | 16 ++-- - src/yuzu/multiplayer/message.cpp | 6 +- - src/yuzu/multiplayer/state.cpp | 79 +++++++++++++------ - src/yuzu/multiplayer/state.h | 14 ++++ - src/yuzu/uisettings.h | 2 +- - 18 files changed, 176 insertions(+), 59 deletions(-) - -diff --git a/src/core/hle/service/hid/hid.cpp b/src/core/hle/service/hid/hid.cpp -index 3d3457160030..7e923462baf5 100644 ---- a/src/core/hle/service/hid/hid.cpp -+++ b/src/core/hle/service/hid/hid.cpp -@@ -35,7 +35,8 @@ namespace Service::HID { - - // Updating period for each HID device. - // Period time is obtained by measuring the number of samples in a second on HW using a homebrew --constexpr auto pad_update_ns = std::chrono::nanoseconds{4 * 1000 * 1000}; // (4ms, 250Hz) -+// Correct pad_update_ns is 4ms this is overclocked to lower input lag -+constexpr auto pad_update_ns = std::chrono::nanoseconds{1 * 1000 * 1000}; // (1ms, 1000Hz) - constexpr auto mouse_keyboard_update_ns = std::chrono::nanoseconds{8 * 1000 * 1000}; // (8ms, 125Hz) - constexpr auto motion_update_ns = std::chrono::nanoseconds{5 * 1000 * 1000}; // (5ms, 200Hz) - -diff --git a/src/core/internal_network/network_interface.cpp b/src/core/internal_network/network_interface.cpp -index 0f0a661606c8..858ae1cfbbb2 100644 ---- a/src/core/internal_network/network_interface.cpp -+++ b/src/core/internal_network/network_interface.cpp -@@ -206,4 +206,14 @@ std::optional GetSelectedNetworkInterface() { - return *res; - } - -+void SelectFirstNetworkInterface() { -+ const auto network_interfaces = Network::GetAvailableNetworkInterfaces(); -+ -+ if (network_interfaces.size() == 0) { -+ return; -+ } -+ -+ Settings::values.network_interface.SetValue(network_interfaces[0].name); -+} -+ - } // namespace Network -diff --git a/src/core/internal_network/network_interface.h b/src/core/internal_network/network_interface.h -index 9b98b6b4204d..175e61b1f9f6 100644 ---- a/src/core/internal_network/network_interface.h -+++ b/src/core/internal_network/network_interface.h -@@ -24,5 +24,6 @@ struct NetworkInterface { - - std::vector GetAvailableNetworkInterfaces(); - std::optional GetSelectedNetworkInterface(); -+void SelectFirstNetworkInterface(); - - } // namespace Network -diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp -index 9dfa8d639c26..deee1c370fb9 100644 ---- a/src/yuzu/main.cpp -+++ b/src/yuzu/main.cpp -@@ -1296,6 +1296,7 @@ void GMainWindow::ConnectMenuEvents() { - &MultiplayerState::OnDirectConnectToRoom); - connect(ui->action_Show_Room, &QAction::triggered, multiplayer_state, - &MultiplayerState::OnOpenNetworkRoom); -+ connect(multiplayer_state, &MultiplayerState::SaveConfig, this, &GMainWindow::OnSaveConfig); - - // Tools - connect_menu(ui->action_Rederive, std::bind(&GMainWindow::OnReinitializeKeys, this, -@@ -1336,6 +1337,8 @@ void GMainWindow::UpdateMenuState() { - } else { - ui->action_Pause->setText(tr("&Pause")); - } -+ -+ multiplayer_state->UpdateNotificationStatus(); - } - - void GMainWindow::OnDisplayTitleBars(bool show) { -@@ -2766,6 +2769,11 @@ void GMainWindow::OnExit() { - OnStopGame(); - } - -+void GMainWindow::OnSaveConfig() { -+ system->ApplySettings(); -+ config->Save(); -+} -+ - void GMainWindow::ErrorDisplayDisplayError(QString error_code, QString error_text) { - OverlayDialog dialog(render_window, *system, error_code, error_text, QString{}, tr("OK"), - Qt::AlignLeft | Qt::AlignVCenter); -diff --git a/src/yuzu/main.h b/src/yuzu/main.h -index 1ae2b93d9b23..1a756b171e33 100644 ---- a/src/yuzu/main.h -+++ b/src/yuzu/main.h -@@ -169,6 +169,7 @@ public slots: - void OnLoadComplete(); - void OnExecuteProgram(std::size_t program_index); - void OnExit(); -+ void OnSaveConfig(); - void ControllerSelectorReconfigureControllers( - const Core::Frontend::ControllerParameters& parameters); - void SoftwareKeyboardInitialize( -diff --git a/src/yuzu/main.ui b/src/yuzu/main.ui -index 60a8deab1c9a..de1545216a81 100644 ---- a/src/yuzu/main.ui -+++ b/src/yuzu/main.ui -@@ -265,7 +265,7 @@ - true - - -- Browse Public Game Lobby -+ &Browse Public Game Lobby - - - -@@ -273,7 +273,7 @@ - true - - -- Create Room -+ &Create Room - - - -@@ -281,12 +281,12 @@ - false - - -- Leave Room -+ &Leave Room - - - - -- Direct Connect to Room -+ &Direct Connect to Room - - - -@@ -294,7 +294,7 @@ - false - - -- Show Current Room -+ &Show Current Room - - - -diff --git a/src/yuzu/multiplayer/client_room.cpp b/src/yuzu/multiplayer/client_room.cpp -index b34a8d004abf..caf34a414fc6 100644 ---- a/src/yuzu/multiplayer/client_room.cpp -+++ b/src/yuzu/multiplayer/client_room.cpp -@@ -97,8 +97,9 @@ void ClientRoomWindow::UpdateView() { - auto memberlist = member->GetMemberInformation(); - ui->chat->SetPlayerList(memberlist); - const auto information = member->GetRoomInformation(); -- setWindowTitle(QString(tr("%1 (%2/%3 members) - connected")) -+ setWindowTitle(QString(tr("%1 - %2 (%3/%4 members) - connected")) - .arg(QString::fromStdString(information.name)) -+ .arg(QString::fromStdString(information.preferred_game.name)) - .arg(memberlist.size()) - .arg(information.member_slots)); - ui->description->setText(QString::fromStdString(information.description)); -diff --git a/src/yuzu/multiplayer/direct_connect.cpp b/src/yuzu/multiplayer/direct_connect.cpp -index 017063074479..10bf0a4fb3d3 100644 ---- a/src/yuzu/multiplayer/direct_connect.cpp -+++ b/src/yuzu/multiplayer/direct_connect.cpp -@@ -106,6 +106,8 @@ void DirectConnectWindow::Connect() { - UISettings::values.multiplayer_port = UISettings::values.multiplayer_port.GetDefault(); - } - -+ emit SaveConfig(); -+ - // attempt to connect in a different thread - QFuture f = QtConcurrent::run([&] { - if (auto room_member = room_network.GetRoomMember().lock()) { -diff --git a/src/yuzu/multiplayer/direct_connect.h b/src/yuzu/multiplayer/direct_connect.h -index e39dd1e0d6df..b8f66cfb2b1f 100644 ---- a/src/yuzu/multiplayer/direct_connect.h -+++ b/src/yuzu/multiplayer/direct_connect.h -@@ -31,6 +31,7 @@ class DirectConnectWindow : public QDialog { - * connections that it might have. - */ - void Closed(); -+ void SaveConfig(); - - private slots: - void OnConnection(); -diff --git a/src/yuzu/multiplayer/host_room.cpp b/src/yuzu/multiplayer/host_room.cpp -index 0c6adfd04007..a8faa5b248ba 100644 ---- a/src/yuzu/multiplayer/host_room.cpp -+++ b/src/yuzu/multiplayer/host_room.cpp -@@ -232,6 +232,7 @@ void HostRoomWindow::Host() { - } - UISettings::values.multiplayer_room_description = ui->room_description->toPlainText(); - ui->host->setEnabled(true); -+ emit SaveConfig(); - close(); - } - } -diff --git a/src/yuzu/multiplayer/host_room.h b/src/yuzu/multiplayer/host_room.h -index 034cb2eefd31..ae816e2e03c1 100644 ---- a/src/yuzu/multiplayer/host_room.h -+++ b/src/yuzu/multiplayer/host_room.h -@@ -46,6 +46,9 @@ class HostRoomWindow : public QDialog { - void UpdateGameList(QStandardItemModel* list); - void RetranslateUi(); - -+signals: -+ void SaveConfig(); -+ - private: - void Host(); - std::unique_ptr CreateVerifyBackend(bool use_validation) const; -diff --git a/src/yuzu/multiplayer/lobby.cpp b/src/yuzu/multiplayer/lobby.cpp -index 107d40547679..08c275696463 100644 ---- a/src/yuzu/multiplayer/lobby.cpp -+++ b/src/yuzu/multiplayer/lobby.cpp -@@ -7,6 +7,7 @@ - #include "common/logging/log.h" - #include "common/settings.h" - #include "core/core.h" -+#include "core/hle/service/acc/profile_manager.h" - #include "core/internal_network/network_interface.h" - #include "network/network.h" - #include "ui_lobby.h" -@@ -26,9 +27,9 @@ - Lobby::Lobby(QWidget* parent, QStandardItemModel* list, - std::shared_ptr session, Core::System& system_) - : QDialog(parent, Qt::WindowTitleHint | Qt::WindowCloseButtonHint | Qt::WindowSystemMenuHint), -- ui(std::make_unique()), -- announce_multiplayer_session(session), system{system_}, room_network{ -- system.GetRoomNetwork()} { -+ ui(std::make_unique()), announce_multiplayer_session(session), -+ profile_manager(std::make_unique()), system{system_}, -+ room_network{system.GetRoomNetwork()} { - ui->setupUi(this); - - // setup the watcher for background connections -@@ -60,9 +61,17 @@ Lobby::Lobby(QWidget* parent, QStandardItemModel* list, - - ui->nickname->setValidator(validation.GetNickname()); - ui->nickname->setText(UISettings::values.multiplayer_nickname.GetValue()); -- if (ui->nickname->text().isEmpty() && !Settings::values.yuzu_username.GetValue().empty()) { -- // Use yuzu Web Service user name as nickname by default -- ui->nickname->setText(QString::fromStdString(Settings::values.yuzu_username.GetValue())); -+ -+ // Try find the best nickname by default -+ if (ui->nickname->text().isEmpty() || ui->nickname->text() == QStringLiteral("yuzu")) { -+ if (!Settings::values.yuzu_username.GetValue().empty()) { -+ ui->nickname->setText( -+ QString::fromStdString(Settings::values.yuzu_username.GetValue())); -+ } else if (!GetProfileUsername().empty()) { -+ ui->nickname->setText(QString::fromStdString(GetProfileUsername())); -+ } else { -+ ui->nickname->setText(QStringLiteral("yuzu")); -+ } - } - - // UI Buttons -@@ -76,12 +85,6 @@ Lobby::Lobby(QWidget* parent, QStandardItemModel* list, - // Actions - connect(&room_list_watcher, &QFutureWatcher::finished, this, - &Lobby::OnRefreshLobby); -- -- // manually start a refresh when the window is opening -- // TODO(jroweboy): if this refresh is slow for people with bad internet, then don't do it as -- // part of the constructor, but offload the refresh until after the window shown. perhaps emit a -- // refreshroomlist signal from places that open the lobby -- RefreshLobby(); - } - - Lobby::~Lobby() = default; -@@ -96,6 +99,7 @@ void Lobby::UpdateGameList(QStandardItemModel* list) { - } - if (proxy) - proxy->UpdateGameList(game_list); -+ ui->room_list->sortByColumn(Column::GAME_NAME, Qt::AscendingOrder); - } - - void Lobby::RetranslateUi() { -@@ -116,6 +120,11 @@ void Lobby::OnExpandRoom(const QModelIndex& index) { - } - - void Lobby::OnJoinRoom(const QModelIndex& source) { -+ if (!Network::GetSelectedNetworkInterface()) { -+ LOG_INFO(WebService, "Automatically selected network interface for room network."); -+ Network::SelectFirstNetworkInterface(); -+ } -+ - if (!Network::GetSelectedNetworkInterface()) { - NetworkMessage::ErrorManager::ShowError( - NetworkMessage::ErrorManager::NO_INTERFACE_SELECTED); -@@ -197,16 +206,16 @@ void Lobby::OnJoinRoom(const QModelIndex& source) { - proxy->data(connection_index, LobbyItemHost::HostIPRole).toString(); - UISettings::values.multiplayer_port = - proxy->data(connection_index, LobbyItemHost::HostPortRole).toInt(); -+ emit SaveConfig(); - } - - void Lobby::ResetModel() { - model->clear(); - model->insertColumns(0, Column::TOTAL); -- model->setHeaderData(Column::EXPAND, Qt::Horizontal, QString(), Qt::DisplayRole); -+ model->setHeaderData(Column::MEMBER, Qt::Horizontal, tr("Players"), Qt::DisplayRole); - model->setHeaderData(Column::ROOM_NAME, Qt::Horizontal, tr("Room Name"), Qt::DisplayRole); - model->setHeaderData(Column::GAME_NAME, Qt::Horizontal, tr("Preferred Game"), Qt::DisplayRole); - model->setHeaderData(Column::HOST, Qt::Horizontal, tr("Host"), Qt::DisplayRole); -- model->setHeaderData(Column::MEMBER, Qt::Horizontal, tr("Players"), Qt::DisplayRole); - } - - void Lobby::RefreshLobby() { -@@ -229,6 +238,7 @@ void Lobby::OnRefreshLobby() { - for (int r = 0; r < game_list->rowCount(); ++r) { - auto index = game_list->index(r, 0); - auto game_id = game_list->data(index, GameListItemPath::ProgramIdRole).toULongLong(); -+ - if (game_id != 0 && room.information.preferred_game.id == game_id) { - smdh_icon = game_list->data(index, Qt::DecorationRole).value(); - } -@@ -243,17 +253,16 @@ void Lobby::OnRefreshLobby() { - members.append(var); - } - -- auto first_item = new LobbyItem(); -+ auto first_item = new LobbyItemGame( -+ room.information.preferred_game.id, -+ QString::fromStdString(room.information.preferred_game.name), smdh_icon); - auto row = QList({ - first_item, - new LobbyItemName(room.has_password, QString::fromStdString(room.information.name)), -- new LobbyItemGame(room.information.preferred_game.id, -- QString::fromStdString(room.information.preferred_game.name), -- smdh_icon), -+ new LobbyItemMemberList(members, room.information.member_slots), - new LobbyItemHost(QString::fromStdString(room.information.host_username), - QString::fromStdString(room.ip), room.information.port, - QString::fromStdString(room.verify_uid)), -- new LobbyItemMemberList(members, room.information.member_slots), - }); - model->appendRow(row); - // To make the rows expandable, add the member data as a child of the first column of the -@@ -283,6 +292,26 @@ void Lobby::OnRefreshLobby() { - ui->room_list->setFirstColumnSpanned(j, proxy->index(i, 0), true); - } - } -+ -+ ui->room_list->sortByColumn(Column::GAME_NAME, Qt::AscendingOrder); -+} -+ -+std::string Lobby::GetProfileUsername() { -+ const auto& current_user = profile_manager->GetUser(Settings::values.current_user.GetValue()); -+ Service::Account::ProfileBase profile{}; -+ -+ if (!current_user.has_value()) { -+ return ""; -+ } -+ -+ if (!profile_manager->GetProfileBase(*current_user, profile)) { -+ return ""; -+ } -+ -+ const auto text = Common::StringFromFixedZeroTerminatedBuffer( -+ reinterpret_cast(profile.username.data()), profile.username.size()); -+ -+ return text; - } - - LobbyFilterProxyModel::LobbyFilterProxyModel(QWidget* parent, QStandardItemModel* list) -diff --git a/src/yuzu/multiplayer/lobby.h b/src/yuzu/multiplayer/lobby.h -index 2696aec21a52..300dad13e11a 100644 ---- a/src/yuzu/multiplayer/lobby.h -+++ b/src/yuzu/multiplayer/lobby.h -@@ -24,6 +24,10 @@ namespace Core { - class System; - } - -+namespace Service::Account { -+class ProfileManager; -+} -+ - /** - * Listing of all public games pulled from services. The lobby should be simple enough for users to - * find the game they want to play, and join it. -@@ -75,8 +79,11 @@ private slots: - - signals: - void StateChanged(const Network::RoomMember::State&); -+ void SaveConfig(); - - private: -+ std::string GetProfileUsername(); -+ - /** - * Removes all entries in the Lobby before refreshing. - */ -@@ -96,6 +103,7 @@ private slots: - - QFutureWatcher room_list_watcher; - std::weak_ptr announce_multiplayer_session; -+ std::unique_ptr profile_manager; - QFutureWatcher* watcher; - Validation validation; - Core::System& system; -diff --git a/src/yuzu/multiplayer/lobby_p.h b/src/yuzu/multiplayer/lobby_p.h -index 8071cede4d49..8b17075062b3 100644 ---- a/src/yuzu/multiplayer/lobby_p.h -+++ b/src/yuzu/multiplayer/lobby_p.h -@@ -11,11 +11,10 @@ - - namespace Column { - enum List { -- EXPAND, -- ROOM_NAME, - GAME_NAME, -- HOST, -+ ROOM_NAME, - MEMBER, -+ HOST, - TOTAL, - }; - } -@@ -98,7 +97,12 @@ class LobbyItemGame : public LobbyItem { - if (role == Qt::DecorationRole) { - auto val = data(GameIconRole); - if (val.isValid()) { -- val = val.value().scaled(16, 16, Qt::KeepAspectRatio); -+ val = val.value().scaled(32, 32, Qt::KeepAspectRatio, -+ Qt::TransformationMode::SmoothTransformation); -+ } else { -+ auto blank_image = QPixmap(32, 32); -+ blank_image.fill(Qt::black); -+ val = blank_image; - } - return val; - } else if (role != Qt::DisplayRole) { -@@ -191,8 +195,8 @@ class LobbyItemMemberList : public LobbyItem { - return LobbyItem::data(role); - } - auto members = data(MemberListRole).toList(); -- return QStringLiteral("%1 / %2").arg(QString::number(members.size()), -- data(MaxPlayerRole).toString()); -+ return QStringLiteral("%1 / %2 ") -+ .arg(QString::number(members.size()), data(MaxPlayerRole).toString()); - } - - bool operator<(const QStandardItem& other) const override { -diff --git a/src/yuzu/multiplayer/message.cpp b/src/yuzu/multiplayer/message.cpp -index 758b5b731d9a..6d8f18274f56 100644 ---- a/src/yuzu/multiplayer/message.cpp -+++ b/src/yuzu/multiplayer/message.cpp -@@ -49,9 +49,9 @@ const ConnectionError ErrorManager::PERMISSION_DENIED( - QT_TR_NOOP("You do not have enough permission to perform this action.")); - const ConnectionError ErrorManager::NO_SUCH_USER(QT_TR_NOOP( - "The user you are trying to kick/ban could not be found.\nThey may have left the room.")); --const ConnectionError ErrorManager::NO_INTERFACE_SELECTED( -- QT_TR_NOOP("No network interface is selected.\nPlease go to Configure -> System -> Network and " -- "make a selection.")); -+const ConnectionError ErrorManager::NO_INTERFACE_SELECTED(QT_TR_NOOP( -+ "No valid network interface is selected.\nPlease go to Configure -> System -> Network and " -+ "make a selection.")); - - static bool WarnMessage(const std::string& title, const std::string& text) { - return QMessageBox::Ok == QMessageBox::warning(nullptr, QObject::tr(title.c_str()), -diff --git a/src/yuzu/multiplayer/state.cpp b/src/yuzu/multiplayer/state.cpp -index 3ad8460281db..ae2738ad4c17 100644 ---- a/src/yuzu/multiplayer/state.cpp -+++ b/src/yuzu/multiplayer/state.cpp -@@ -44,9 +44,6 @@ MultiplayerState::MultiplayerState(QWidget* parent, QStandardItemModel* game_lis - - status_text = new ClickableLabel(this); - status_icon = new ClickableLabel(this); -- status_text->setToolTip(tr("Current connection status")); -- status_text->setText(tr("Not Connected. Click here to find a room!")); -- status_icon->setPixmap(QIcon::fromTheme(QStringLiteral("disconnected")).pixmap(16)); - - connect(status_text, &ClickableLabel::clicked, this, &MultiplayerState::OnOpenNetworkRoom); - connect(status_icon, &ClickableLabel::clicked, this, &MultiplayerState::OnOpenNetworkRoom); -@@ -57,6 +54,8 @@ MultiplayerState::MultiplayerState(QWidget* parent, QStandardItemModel* game_lis - HideNotification(); - } - }); -+ -+ retranslateUi(); - } - - MultiplayerState::~MultiplayerState() = default; -@@ -90,14 +89,7 @@ void MultiplayerState::Close() { - void MultiplayerState::retranslateUi() { - status_text->setToolTip(tr("Current connection status")); - -- if (current_state == Network::RoomMember::State::Uninitialized) { -- status_text->setText(tr("Not Connected. Click here to find a room!")); -- } else if (current_state == Network::RoomMember::State::Joined || -- current_state == Network::RoomMember::State::Moderator) { -- status_text->setText(tr("Connected")); -- } else { -- status_text->setText(tr("Not Connected")); -- } -+ UpdateNotificationStatus(); - - if (lobby) { - lobby->RetranslateUi(); -@@ -113,21 +105,55 @@ void MultiplayerState::retranslateUi() { - } - } - -+void MultiplayerState::SetNotificationStatus(NotificationStatus status) { -+ notification_status = status; -+ UpdateNotificationStatus(); -+} -+ -+void MultiplayerState::UpdateNotificationStatus() { -+ switch (notification_status) { -+ case NotificationStatus::Unitialized: -+ status_icon->setPixmap(QIcon::fromTheme(QStringLiteral("disconnected")).pixmap(16)); -+ status_text->setText(tr("Not Connected. Click here to find a room!")); -+ leave_room->setEnabled(false); -+ show_room->setEnabled(false); -+ break; -+ case NotificationStatus::Disconnected: -+ status_icon->setPixmap(QIcon::fromTheme(QStringLiteral("disconnected")).pixmap(16)); -+ status_text->setText(tr("Not Connected")); -+ leave_room->setEnabled(false); -+ show_room->setEnabled(false); -+ break; -+ case NotificationStatus::Connected: -+ status_icon->setPixmap(QIcon::fromTheme(QStringLiteral("connected")).pixmap(16)); -+ status_text->setText(tr("Connected")); -+ leave_room->setEnabled(true); -+ show_room->setEnabled(true); -+ break; -+ case NotificationStatus::Notification: -+ status_icon->setPixmap( -+ QIcon::fromTheme(QStringLiteral("connected_notification")).pixmap(16)); -+ status_text->setText(tr("New Messages Received")); -+ leave_room->setEnabled(true); -+ show_room->setEnabled(true); -+ break; -+ } -+ -+ // Clean up status bar if game is running -+ if (system.IsPoweredOn()) { -+ status_text->clear(); -+ } -+} -+ - void MultiplayerState::OnNetworkStateChanged(const Network::RoomMember::State& state) { - LOG_DEBUG(Frontend, "Network State: {}", Network::GetStateStr(state)); - if (state == Network::RoomMember::State::Joined || - state == Network::RoomMember::State::Moderator) { - - OnOpenNetworkRoom(); -- status_icon->setPixmap(QIcon::fromTheme(QStringLiteral("connected")).pixmap(16)); -- status_text->setText(tr("Connected")); -- leave_room->setEnabled(true); -- show_room->setEnabled(true); -+ SetNotificationStatus(NotificationStatus::Connected); - } else { -- status_icon->setPixmap(QIcon::fromTheme(QStringLiteral("disconnected")).pixmap(16)); -- status_text->setText(tr("Not Connected")); -- leave_room->setEnabled(false); -- show_room->setEnabled(false); -+ SetNotificationStatus(NotificationStatus::Disconnected); - } - - current_state = state; -@@ -185,6 +211,10 @@ void MultiplayerState::OnAnnounceFailed(const WebService::WebResult& result) { - QMessageBox::Ok); - } - -+void MultiplayerState::OnSaveConfig() { -+ emit SaveConfig(); -+} -+ - void MultiplayerState::UpdateThemedIcons() { - if (show_notification) { - status_icon->setPixmap( -@@ -209,13 +239,16 @@ static void BringWidgetToFront(QWidget* widget) { - void MultiplayerState::OnViewLobby() { - if (lobby == nullptr) { - lobby = new Lobby(this, game_list_model, announce_multiplayer_session, system); -+ connect(lobby, &Lobby::SaveConfig, this, &MultiplayerState::OnSaveConfig); - } -+ lobby->RefreshLobby(); - BringWidgetToFront(lobby); - } - - void MultiplayerState::OnCreateRoom() { - if (host_room == nullptr) { - host_room = new HostRoomWindow(this, game_list_model, announce_multiplayer_session, system); -+ connect(host_room, &HostRoomWindow::SaveConfig, this, &MultiplayerState::OnSaveConfig); - } - BringWidgetToFront(host_room); - } -@@ -250,14 +283,12 @@ void MultiplayerState::ShowNotification() { - show_notification = true; - QApplication::alert(nullptr); - QApplication::beep(); -- status_icon->setPixmap(QIcon::fromTheme(QStringLiteral("connected_notification")).pixmap(16)); -- status_text->setText(tr("New Messages Received")); -+ SetNotificationStatus(NotificationStatus::Notification); - } - - void MultiplayerState::HideNotification() { - show_notification = false; -- status_icon->setPixmap(QIcon::fromTheme(QStringLiteral("connected")).pixmap(16)); -- status_text->setText(tr("Connected")); -+ SetNotificationStatus(NotificationStatus::Connected); - } - - void MultiplayerState::OnOpenNetworkRoom() { -@@ -280,6 +311,8 @@ void MultiplayerState::OnOpenNetworkRoom() { - void MultiplayerState::OnDirectConnectToRoom() { - if (direct_connect == nullptr) { - direct_connect = new DirectConnectWindow(system, this); -+ connect(direct_connect, &DirectConnectWindow::SaveConfig, this, -+ &MultiplayerState::OnSaveConfig); - } - BringWidgetToFront(direct_connect); - } -diff --git a/src/yuzu/multiplayer/state.h b/src/yuzu/multiplayer/state.h -index c92496413ca5..5d681c5c6131 100644 ---- a/src/yuzu/multiplayer/state.h -+++ b/src/yuzu/multiplayer/state.h -@@ -22,6 +22,13 @@ class MultiplayerState : public QWidget { - Q_OBJECT; - - public: -+ enum class NotificationStatus { -+ Unitialized, -+ Disconnected, -+ Connected, -+ Notification, -+ }; -+ - explicit MultiplayerState(QWidget* parent, QStandardItemModel* game_list, QAction* leave_room, - QAction* show_room, Core::System& system_); - ~MultiplayerState(); -@@ -31,6 +38,10 @@ class MultiplayerState : public QWidget { - */ - void Close(); - -+ void SetNotificationStatus(NotificationStatus state); -+ -+ void UpdateNotificationStatus(); -+ - ClickableLabel* GetStatusText() const { - return status_text; - } -@@ -64,6 +75,7 @@ public slots: - void OnOpenNetworkRoom(); - void OnDirectConnectToRoom(); - void OnAnnounceFailed(const WebService::WebResult&); -+ void OnSaveConfig(); - void UpdateThemedIcons(); - void ShowNotification(); - void HideNotification(); -@@ -72,6 +84,7 @@ public slots: - void NetworkStateChanged(const Network::RoomMember::State&); - void NetworkError(const Network::RoomMember::Error&); - void AnnounceFailed(const WebService::WebResult&); -+ void SaveConfig(); - - private: - Lobby* lobby = nullptr; -@@ -85,6 +98,7 @@ public slots: - QAction* show_room; - std::shared_ptr announce_multiplayer_session; - Network::RoomMember::State current_state = Network::RoomMember::State::Uninitialized; -+ NotificationStatus notification_status = NotificationStatus::Unitialized; - bool has_mod_perms = false; - Network::RoomMember::CallbackHandle state_callback_handle; - Network::RoomMember::CallbackHandle error_callback_handle; -diff --git a/src/yuzu/uisettings.h b/src/yuzu/uisettings.h -index e12d414d96b7..753797efc4d9 100644 ---- a/src/yuzu/uisettings.h -+++ b/src/yuzu/uisettings.h -@@ -102,7 +102,7 @@ struct Values { - Settings::Setting callout_flags{0, "calloutFlags"}; - - // multiplayer settings -- Settings::Setting multiplayer_nickname{QStringLiteral("yuzu"), "nickname"}; -+ Settings::Setting multiplayer_nickname{{}, "nickname"}; - Settings::Setting multiplayer_ip{{}, "ip"}; - Settings::SwitchableSetting multiplayer_port{24872, 0, UINT16_MAX, "port"}; - Settings::Setting multiplayer_room_nickname{{}, "room_nickname"}; - -From 1694c55d62d44730d760371d1bf2559de1b191dd Mon Sep 17 00:00:00 2001 -From: Narr the Reg -Date: Sat, 10 Sep 2022 12:57:19 -0500 -Subject: [PATCH 3/5] fix black icon - ---- - src/yuzu/multiplayer/lobby_p.h | 2 ++ - 1 file changed, 2 insertions(+) - -diff --git a/src/yuzu/multiplayer/lobby_p.h b/src/yuzu/multiplayer/lobby_p.h -index 8b17075062b3..068c95acad75 100644 ---- a/src/yuzu/multiplayer/lobby_p.h -+++ b/src/yuzu/multiplayer/lobby_p.h -@@ -90,6 +90,8 @@ class LobbyItemGame : public LobbyItem { - setData(game_name, GameNameRole); - if (!smdh_icon.isNull()) { - setData(smdh_icon, GameIconRole); -+ } else { -+ setData(QIcon::fromTheme(QStringLiteral("chip")).pixmap(32), GameIconRole); - } - } - - -From aa11d73bba386076973010ba4c60d5b04ba828a3 Mon Sep 17 00:00:00 2001 -From: liushuyu -Date: Sat, 10 Sep 2022 17:38:36 -0600 -Subject: [PATCH 4/5] dedicated_room: fix token padding ... - -... mebedtls' base64 routine has a strange behavioral issue where if the -input is invalid, it will not report it as invalid, but rather returning -a bunch of garbage data. This new round-tripping padding method should -eliminate such issue. ---- - src/dedicated_room/yuzu_room.cpp | 14 ++++++++++++-- - 1 file changed, 12 insertions(+), 2 deletions(-) - -diff --git a/src/dedicated_room/yuzu_room.cpp b/src/dedicated_room/yuzu_room.cpp -index 8d8ac1ed74f1..359891883c4a 100644 ---- a/src/dedicated_room/yuzu_room.cpp -+++ b/src/dedicated_room/yuzu_room.cpp -@@ -76,8 +76,18 @@ static constexpr char BanListMagic[] = "YuzuRoom-BanList-1"; - static constexpr char token_delimiter{':'}; - - static void PadToken(std::string& token) { -- const auto remainder = token.size() % 3; -- for (size_t i = 0; i < (3 - remainder); i++) { -+ std::size_t outlen = 0; -+ -+ std::array output{}; -+ std::array roundtrip{}; -+ for (size_t i = 0; i < 3; i++) { -+ mbedtls_base64_decode(output.data(), output.size(), &outlen, -+ reinterpret_cast(token.c_str()), -+ token.length()); -+ mbedtls_base64_encode(roundtrip.data(), roundtrip.size(), &outlen, output.data(), outlen); -+ if (memcmp(roundtrip.data(), token.data(), token.size()) == 0) { -+ break; -+ } - token.push_back('='); - } - } - -From 6b9e6953e8bb91df1ae7c1a6a6076f57ad628c44 Mon Sep 17 00:00:00 2001 -From: FearlessTobi -Date: Mon, 12 Sep 2022 22:39:18 +0200 -Subject: [PATCH 5/5] Address some review comments - ---- - src/core/hle/service/ldn/lan_discovery.cpp | 41 +++++++------------ - src/core/hle/service/ldn/lan_discovery.h | 13 +++--- - src/core/hle/service/ldn/ldn.cpp | 2 - - src/core/hle/service/ldn/ldn_types.h | 8 +--- - .../internal_network/network_interface.cpp | 4 +- - src/network/room_member.cpp | 2 +- - 6 files changed, 26 insertions(+), 44 deletions(-) - -diff --git a/src/core/hle/service/ldn/lan_discovery.cpp b/src/core/hle/service/ldn/lan_discovery.cpp -index b04c990771ad..5f3222217f00 100644 ---- a/src/core/hle/service/ldn/lan_discovery.cpp -+++ b/src/core/hle/service/ldn/lan_discovery.cpp -@@ -35,12 +35,9 @@ void LanStation::OverrideInfo() { - - LANDiscovery::LANDiscovery(Network::RoomNetwork& room_network_) - : stations({{{1, this}, {2, this}, {3, this}, {4, this}, {5, this}, {6, this}, {7, this}}}), -- room_network{room_network_} { -- LOG_INFO(Service_LDN, "LANDiscovery"); --} -+ room_network{room_network_} {} - - LANDiscovery::~LANDiscovery() { -- LOG_INFO(Service_LDN, "~LANDiscovery"); - if (inited) { - Result rc = Finalize(); - LOG_INFO(Service_LDN, "Finalize: {}", rc.raw); -@@ -62,7 +59,7 @@ void LANDiscovery::InitNetworkInfo() { - } - - void LANDiscovery::InitNodeStateChange() { -- for (auto& node_update : nodeChanges) { -+ for (auto& node_update : node_changes) { - node_update.state_change = NodeStateChange::None; - } - for (auto& node_state : node_last_states) { -@@ -97,8 +94,8 @@ Result LANDiscovery::GetNetworkInfo(NetworkInfo& out_network, - if (state == State::AccessPointCreated || state == State::StationConnected) { - std::memcpy(&out_network, &network_info, sizeof(network_info)); - for (std::size_t i = 0; i < buffer_count; i++) { -- out_updates[i].state_change = nodeChanges[i].state_change; -- nodeChanges[i].state_change = NodeStateChange::None; -+ out_updates[i].state_change = node_changes[i].state_change; -+ node_changes[i].state_change = NodeStateChange::None; - } - return ResultSuccess; - } -@@ -168,9 +165,9 @@ Result LANDiscovery::Scan(std::vector& networks, u16& count, - return ResultSuccess; - } - --Result LANDiscovery::SetAdvertiseData(std::vector& data) { -+Result LANDiscovery::SetAdvertiseData(std::span data) { - std::scoped_lock lock{packet_mutex}; -- std::size_t size = data.size(); -+ const std::size_t size = data.size(); - if (size > AdvertiseDataSizeMax) { - return ResultAdvertiseDataTooLarge; - } -@@ -328,7 +325,7 @@ Result LANDiscovery::Disconnect() { - return ResultSuccess; - } - --Result LANDiscovery::Initialize(LanEventFunc lan_event, bool listening) { -+Result LANDiscovery::Initialize(LanEventFunc lan_event_, bool listening) { - std::scoped_lock lock{packet_mutex}; - if (inited) { - return ResultSuccess; -@@ -341,7 +338,7 @@ Result LANDiscovery::Initialize(LanEventFunc lan_event, bool listening) { - } - - connected_clients.clear(); -- LanEvent = lan_event; -+ LanEvent = lan_event_; - - SetState(State::Initialized); - -@@ -439,7 +436,6 @@ void LANDiscovery::SendPacket(Network::LDNPacketType type, const Data& data, - packet.local_ip = GetLocalIp(); - packet.remote_ip = remote_ip; - -- packet.data.clear(); - packet.data.resize(sizeof(data)); - std::memcpy(packet.data.data(), &data, sizeof(data)); - SendPacket(packet); -@@ -453,7 +449,6 @@ void LANDiscovery::SendPacket(Network::LDNPacketType type, Ipv4Address remote_ip - packet.local_ip = GetLocalIp(); - packet.remote_ip = remote_ip; - -- packet.data.clear(); - SendPacket(packet); - } - -@@ -465,7 +460,6 @@ void LANDiscovery::SendBroadcast(Network::LDNPacketType type, const Data& data) - packet.broadcast = true; - packet.local_ip = GetLocalIp(); - -- packet.data.clear(); - packet.data.resize(sizeof(data)); - std::memcpy(packet.data.data(), &data, sizeof(data)); - SendPacket(packet); -@@ -478,7 +472,6 @@ void LANDiscovery::SendBroadcast(Network::LDNPacketType type) { - packet.broadcast = true; - packet.local_ip = GetLocalIp(); - -- packet.data.clear(); - SendPacket(packet); - } - -@@ -581,9 +574,9 @@ bool LANDiscovery::IsNodeStateChanged() { - for (int i = 0; i < NodeCountMax; i++) { - if (nodes[i].is_connected != node_last_states[i]) { - if (nodes[i].is_connected) { -- nodeChanges[i].state_change |= NodeStateChange::Connect; -+ node_changes[i].state_change |= NodeStateChange::Connect; - } else { -- nodeChanges[i].state_change |= NodeStateChange::Disconnect; -+ node_changes[i].state_change |= NodeStateChange::Disconnect; - } - node_last_states[i] = nodes[i].is_connected; - changed = true; -@@ -598,15 +591,11 @@ bool LANDiscovery::IsFlagSet(ScanFilterFlag flag, ScanFilterFlag search_flag) co - return (flag_value & search_flag_value) == search_flag_value; - } - --int LANDiscovery::GetStationCount() { -- int count = 0; -- for (const auto& station : stations) { -- if (station.GetStatus() != NodeStatus::Disconnected) { -- count++; -- } -- } -- -- return count; -+int LANDiscovery::GetStationCount() const { -+ return static_cast( -+ std::count_if(stations.begin(), stations.end(), [](const auto& station) { -+ return station.GetStatus() != NodeStatus::Disconnected; -+ })); - } - - MacAddress LANDiscovery::GetFakeMac() const { -diff --git a/src/core/hle/service/ldn/lan_discovery.h b/src/core/hle/service/ldn/lan_discovery.h -index 255342456eba..e64e89424542 100644 ---- a/src/core/hle/service/ldn/lan_discovery.h -+++ b/src/core/hle/service/ldn/lan_discovery.h -@@ -10,6 +10,7 @@ - #include - #include - #include -+#include - #include - #include - -@@ -44,7 +45,7 @@ class LanStation { - - class LANDiscovery { - public: -- typedef std::function LanEventFunc; -+ using LanEventFunc = std::function; - - LANDiscovery(Network::RoomNetwork& room_network_); - ~LANDiscovery(); -@@ -58,7 +59,7 @@ class LANDiscovery { - - DisconnectReason GetDisconnectReason() const; - Result Scan(std::vector& networks, u16& count, const ScanFilter& filter); -- Result SetAdvertiseData(std::vector& data); -+ Result SetAdvertiseData(std::span data); - - Result OpenAccessPoint(); - Result CloseAccessPoint(); -@@ -74,7 +75,7 @@ class LANDiscovery { - u16 local_communication_version); - Result Disconnect(); - -- Result Initialize(LanEventFunc lan_event = empty_func, bool listening = true); -+ Result Initialize(LanEventFunc lan_event_ = empty_func, bool listening = true); - Result Finalize(); - - void ReceivePacket(const Network::LDNPacket& packet); -@@ -94,7 +95,7 @@ class LANDiscovery { - - bool IsNodeStateChanged(); - bool IsFlagSet(ScanFilterFlag flag, ScanFilterFlag search_flag) const; -- int GetStationCount(); -+ int GetStationCount() const; - MacAddress GetFakeMac() const; - Result GetNodeInfo(NodeInfo& node, const UserConfig& user_config, - u16 local_communication_version); -@@ -114,7 +115,7 @@ class LANDiscovery { - bool inited{}; - std::mutex packet_mutex; - std::array stations; -- std::array nodeChanges{}; -+ std::array node_changes{}; - std::array node_last_states{}; - std::unordered_map scan_results{}; - NodeInfo node_info{}; -@@ -124,7 +125,7 @@ class LANDiscovery { - - // TODO (flTobi): Should this be an std::set? - std::vector connected_clients; -- std::optional host_ip = std::nullopt; -+ std::optional host_ip; - - LanEventFunc LanEvent; - -diff --git a/src/core/hle/service/ldn/ldn.cpp b/src/core/hle/service/ldn/ldn.cpp -index 6537f49cf2e9..ea3e7e55af62 100644 ---- a/src/core/hle/service/ldn/ldn.cpp -+++ b/src/core/hle/service/ldn/ldn.cpp -@@ -205,8 +205,6 @@ class IUserLocalCommunicationService final - } - - void GetIpv4Address(Kernel::HLERequestContext& ctx) { -- LOG_CRITICAL(Service_LDN, "called"); -- - const auto network_interface = Network::GetSelectedNetworkInterface(); - - if (!network_interface) { -diff --git a/src/core/hle/service/ldn/ldn_types.h b/src/core/hle/service/ldn/ldn_types.h -index d6609fff55fd..de3cd6b762fd 100644 ---- a/src/core/hle/service/ldn/ldn_types.h -+++ b/src/core/hle/service/ldn/ldn_types.h -@@ -31,13 +31,7 @@ enum class NodeStateChange : u8 { - DisconnectAndConnect, - }; - --inline NodeStateChange operator|(NodeStateChange a, NodeStateChange b) { -- return static_cast(static_cast(a) | static_cast(b)); --} -- --inline NodeStateChange operator|=(NodeStateChange& a, NodeStateChange b) { -- return a = a | b; --} -+DECLARE_ENUM_FLAG_OPERATORS(NodeStateChange) - - enum class ScanFilterFlag : u32 { - None = 0, -diff --git a/src/core/internal_network/network_interface.cpp b/src/core/internal_network/network_interface.cpp -index 858ae1cfbbb2..057fd3661748 100644 ---- a/src/core/internal_network/network_interface.cpp -+++ b/src/core/internal_network/network_interface.cpp -@@ -188,7 +188,7 @@ std::vector GetAvailableNetworkInterfaces() { - std::optional GetSelectedNetworkInterface() { - const auto& selected_network_interface = Settings::values.network_interface.GetValue(); - const auto network_interfaces = Network::GetAvailableNetworkInterfaces(); -- if (network_interfaces.size() == 0) { -+ if (network_interfaces.empty()) { - LOG_ERROR(Network, "GetAvailableNetworkInterfaces returned no interfaces"); - return std::nullopt; - } -@@ -209,7 +209,7 @@ std::optional GetSelectedNetworkInterface() { - void SelectFirstNetworkInterface() { - const auto network_interfaces = Network::GetAvailableNetworkInterfaces(); - -- if (network_interfaces.size() == 0) { -+ if (network_interfaces.empty()) { - return; - } - -diff --git a/src/network/room_member.cpp b/src/network/room_member.cpp -index 572e55a5b83c..b94cb24ad74c 100644 ---- a/src/network/room_member.cpp -+++ b/src/network/room_member.cpp -@@ -716,7 +716,7 @@ RoomMember::CallbackHandle RoomMember::BindOnProxyPacketReceived( - - RoomMember::CallbackHandle RoomMember::BindOnLdnPacketReceived( - std::function callback) { -- return room_member_impl->Bind(callback); -+ return room_member_impl->Bind(std::move(callback)); - } - - RoomMember::CallbackHandle RoomMember::BindOnRoomInformationChanged(