From 0a57c459b6fcadc553effb16902974bed72bd9ff Mon Sep 17 00:00:00 2001 From: Megamouse Date: Tue, 1 Oct 2024 01:44:39 +0200 Subject: [PATCH] overlays: add friends list to home menu --- rpcs3/Emu/CMakeLists.txt | 1 + rpcs3/Emu/NP/np_handler.cpp | 2 +- rpcs3/Emu/NP/rpcn_client.cpp | 32 +- rpcs3/Emu/NP/rpcn_client.h | 1 + .../overlay_friends_list_dialog.cpp | 679 ++++++++++++++++++ .../FriendsList/overlay_friends_list_dialog.h | 64 ++ .../HomeMenu/overlay_home_menu_main_menu.cpp | 25 +- .../Network/overlay_sendmessage_dialog.cpp | 1 + rpcs3/Emu/RSX/Overlays/overlay_controls.cpp | 4 +- rpcs3/Emu/localized_string_id.h | 16 + rpcs3/emucore.vcxproj | 2 + rpcs3/emucore.vcxproj.filters | 9 + rpcs3/main_application.cpp | 2 + rpcs3/rpcs3qt/localized_emu.h | 16 + rpcs3/rpcs3qt/rpcn_settings_dialog.cpp | 18 +- rpcs3/rpcs3qt/rpcn_settings_dialog.h | 14 +- rpcs3/rpcs3qt/sendmessage_dialog_frame.cpp | 1 + 17 files changed, 858 insertions(+), 29 deletions(-) create mode 100644 rpcs3/Emu/RSX/Overlays/FriendsList/overlay_friends_list_dialog.cpp create mode 100644 rpcs3/Emu/RSX/Overlays/FriendsList/overlay_friends_list_dialog.h diff --git a/rpcs3/Emu/CMakeLists.txt b/rpcs3/Emu/CMakeLists.txt index 0f4c32b54b..3bd62e9ed6 100644 --- a/rpcs3/Emu/CMakeLists.txt +++ b/rpcs3/Emu/CMakeLists.txt @@ -512,6 +512,7 @@ target_sources(rpcs3_emu PRIVATE RSX/NV47/HW/nv308a.cpp RSX/NV47/HW/nv406e.cpp RSX/NV47/HW/nv4097.cpp + RSX/Overlays/FriendsList/overlay_friends_list_dialog.cpp RSX/Overlays/HomeMenu/overlay_home_menu.cpp RSX/Overlays/HomeMenu/overlay_home_menu_components.cpp RSX/Overlays/HomeMenu/overlay_home_menu_main_menu.cpp diff --git a/rpcs3/Emu/NP/np_handler.cpp b/rpcs3/Emu/NP/np_handler.cpp index c8ac3799b1..e3eafc7b9d 100644 --- a/rpcs3/Emu/NP/np_handler.cpp +++ b/rpcs3/Emu/NP/np_handler.cpp @@ -768,7 +768,7 @@ namespace np if (g_cfg.net.psn_status >= np_psn_status::psn_fake) { g_cfg_rpcn.load(); // Ensures config is loaded even if rpcn is not running for simulated - std::string s_npid = g_cfg_rpcn.get_npid(); + const std::string s_npid = g_cfg_rpcn.get_npid(); ensure(!s_npid.empty()); // It should have been generated before this string_to_npid(s_npid, npid); diff --git a/rpcs3/Emu/NP/rpcn_client.cpp b/rpcs3/Emu/NP/rpcn_client.cpp index 6244978c56..ac23dcca18 100644 --- a/rpcs3/Emu/NP/rpcn_client.cpp +++ b/rpcs3/Emu/NP/rpcn_client.cpp @@ -75,7 +75,7 @@ namespace rpcn } } - void overlay_friend_callback(void* param, rpcn::NotificationType ntype, const std::string& username, bool status) + void overlay_friend_callback(void* /*param*/, rpcn::NotificationType ntype, const std::string& username, bool status) { if (!g_cfg.misc.show_rpcn_popups) return; @@ -88,6 +88,7 @@ namespace rpcn case rpcn::NotificationType::FriendNew: loc_id = localized_string_id::RPCN_FRIEND_ADDED; break; case rpcn::NotificationType::FriendLost: loc_id = localized_string_id::RPCN_FRIEND_LOST; break; case rpcn::NotificationType::FriendStatus: loc_id = status ? localized_string_id::RPCN_FRIEND_LOGGED_IN : localized_string_id::RPCN_FRIEND_LOGGED_OUT; break; + case rpcn::NotificationType::FriendPresenceChanged: return; default: rpcn_log.fatal("An unhandled notification type was received by the overlay friend callback!"); break; } @@ -2572,6 +2573,12 @@ namespace rpcn return state; } + void rpcn_client::get_friends(friend_data& friend_infos) + { + std::lock_guard lock(mutex_friends); + friend_infos = this->friend_infos; + } + void rpcn_client::get_friends_and_register_cb(friend_data& friend_infos, friend_cb_func cb_func, void* cb_param) { std::lock_guard lock(mutex_friends); @@ -2619,7 +2626,7 @@ namespace rpcn { case NotificationType::FriendQuery: // Other user sent a friend request { - std::string username = vdata.get_string(false); + const std::string username = vdata.get_string(false); if (vdata.is_error()) { rpcn_log.error("Error parsing FriendQuery notification"); @@ -2632,8 +2639,8 @@ namespace rpcn } case NotificationType::FriendNew: // Add a friend to the friendlist(either accepted a friend request or friend accepted it) { - bool online = !!vdata.get(); - std::string username = vdata.get_string(false); + const bool online = !!vdata.get(); + const std::string username = vdata.get_string(false); if (vdata.is_error()) { rpcn_log.error("Error parsing FriendNew notification"); @@ -2649,22 +2656,24 @@ namespace rpcn } case NotificationType::FriendLost: // Remove friend from the friendlist(user removed friend or friend removed friend) { - std::string username = vdata.get_string(false); + const std::string username = vdata.get_string(false); if (vdata.is_error()) { rpcn_log.error("Error parsing FriendLost notification"); break; } + friend_infos.requests_received.erase(username); + friend_infos.requests_sent.erase(username); friend_infos.friends.erase(username); call_callbacks(ntype, username, false); break; } case NotificationType::FriendStatus: // Set status of friend to Offline or Online { - bool online = !!vdata.get(); - u64 timestamp = vdata.get(); - std::string username = vdata.get_string(false); + const bool online = !!vdata.get(); + const u64 timestamp = vdata.get(); + const std::string username = vdata.get_string(false); if (vdata.is_error()) { rpcn_log.error("Error parsing FriendStatus notification"); @@ -2692,7 +2701,7 @@ namespace rpcn } case NotificationType::FriendPresenceChanged: { - std::string npid = vdata.get_string(true); + const std::string username = vdata.get_string(true); SceNpCommunicationId pr_com_id = vdata.get_com_id(); std::string pr_title = fmt::truncate(vdata.get_string(true), SCE_NP_BASIC_PRESENCE_TITLE_SIZE_MAX - 1); std::string pr_status = fmt::truncate(vdata.get_string(true), SCE_NP_BASIC_PRESENCE_EXTENDED_STATUS_SIZE_MAX - 1); @@ -2709,7 +2718,7 @@ namespace rpcn break; } - if (auto u = friend_infos.friends.find(npid); u != friend_infos.friends.end()) + if (auto u = friend_infos.friends.find(username); u != friend_infos.friends.end()) { u->second.pr_com_id = std::move(pr_com_id); u->second.pr_title = std::move(pr_title); @@ -2718,9 +2727,10 @@ namespace rpcn u->second.pr_data = std::move(pr_data); std::lock_guard lock(mutex_presence_updates); - presence_updates.insert_or_assign(std::move(npid), u->second); + presence_updates.insert_or_assign(username, u->second); } + call_callbacks(ntype, username, false); break; } default: diff --git a/rpcs3/Emu/NP/rpcn_client.h b/rpcs3/Emu/NP/rpcn_client.h index 02e900989f..4f772f04c4 100644 --- a/rpcs3/Emu/NP/rpcn_client.h +++ b/rpcs3/Emu/NP/rpcn_client.h @@ -439,6 +439,7 @@ namespace rpcn rpcn_state wait_for_authentified(); bool terminate_connection(); + void get_friends(friend_data& friend_infos); void get_friends_and_register_cb(friend_data& friend_infos, friend_cb_func cb_func, void* cb_param); void register_friend_cb(friend_cb_func, void* cb_param); void remove_friend_cb(friend_cb_func, void* cb_param); diff --git a/rpcs3/Emu/RSX/Overlays/FriendsList/overlay_friends_list_dialog.cpp b/rpcs3/Emu/RSX/Overlays/FriendsList/overlay_friends_list_dialog.cpp new file mode 100644 index 0000000000..0e6feaa2a7 --- /dev/null +++ b/rpcs3/Emu/RSX/Overlays/FriendsList/overlay_friends_list_dialog.cpp @@ -0,0 +1,679 @@ +#include "stdafx.h" +#include "../overlay_manager.h" +#include "overlay_friends_list_dialog.h" +#include "Emu/System.h" +#include "Emu/NP/rpcn_config.h" +#include "Emu/vfs_config.h" + +namespace rsx +{ + namespace overlays + { + void friend_callback(void* param, rpcn::NotificationType ntype, const std::string& username, bool status) + { + auto* dlg = static_cast(param); + dlg->callback_handler(ntype, username, status); + } + + friends_list_dialog::friends_list_entry::friends_list_entry(friends_list_dialog_page page, const std::string& username, const rpcn::friend_online_data& data) + { + std::unique_ptr image = std::make_unique(); + image->set_size(160, 110); + image->set_padding(36, 36, 11, 11); // Square image, 88x88 + + std::string avatar_path = g_cfg_vfs.get_dev_flash() + "vsh/resource/explore/user/"; + std::string text; + + switch (page) + { + case friends_list_dialog_page::friends: + { + avatar_path += data.online ? "013.png" : "009.png"; + text = get_localized_string(data.online ? localized_string_id::HOME_MENU_FRIENDS_STATUS_ONLINE : localized_string_id::HOME_MENU_FRIENDS_STATUS_OFFLINE); + + if (data.online) + { + if (!data.pr_title.empty()) + { + fmt::append(text, " - %s", data.pr_title); + } + + if (!data.pr_status.empty()) + { + fmt::append(text, " - %s", data.pr_status); + } + } + break; + } + case friends_list_dialog_page::invites: + { + // We use "online" to show whether an invite was sent or received + avatar_path += data.online ? "012.png" : "011.png"; + text = get_localized_string(data.online ? localized_string_id::HOME_MENU_FRIENDS_REQUEST_RECEIVED : localized_string_id::HOME_MENU_FRIENDS_REQUEST_SENT); + break; + } + case friends_list_dialog_page::blocked: + { + avatar_path += "010.png"; + text = get_localized_string(localized_string_id::HOME_MENU_FRIENDS_STATUS_BLOCKED); + break; + } + } + + if (fs::exists(avatar_path)) + { + icon_data = std::make_unique(avatar_path.c_str()); + static_cast(image.get())->set_raw_image(icon_data.get()); + } + else + { + // Fallback + // TODO: use proper icon + static_cast(image.get())->set_image_resource(resource_config::standard_image_resource::square); + } + + std::unique_ptr text_stack = std::make_unique(); + std::unique_ptr padding = std::make_unique(); + std::unique_ptr header_text = std::make_unique