From e68ffdbc81df87529f4e72afc20f5a3ea2c5cd4f Mon Sep 17 00:00:00 2001 From: RipleyTom Date: Tue, 17 May 2022 16:35:41 +0200 Subject: [PATCH] Add a message overlay --- rpcs3/Emu/CMakeLists.txt | 1 + rpcs3/Emu/NP/np_handler.cpp | 5 + rpcs3/Emu/NP/rpcn_client.cpp | 29 +++++- rpcs3/Emu/NP/rpcn_client.h | 4 + rpcs3/Emu/RSX/Overlays/overlay_message.cpp | 108 +++++++++++++++++++++ rpcs3/Emu/RSX/Overlays/overlay_message.h | 75 ++++++++++++++ rpcs3/Emu/localized_string_id.h | 14 +++ rpcs3/emucore.vcxproj | 2 + rpcs3/emucore.vcxproj.filters | 6 ++ rpcs3/rpcs3qt/localized_emu.h | 14 ++- rpcs3/rpcs3qt/rpcn_settings_dialog.cpp | 28 +----- 11 files changed, 259 insertions(+), 27 deletions(-) create mode 100644 rpcs3/Emu/RSX/Overlays/overlay_message.cpp create mode 100644 rpcs3/Emu/RSX/Overlays/overlay_message.h diff --git a/rpcs3/Emu/CMakeLists.txt b/rpcs3/Emu/CMakeLists.txt index 5e1d40e0a9..87f835941f 100644 --- a/rpcs3/Emu/CMakeLists.txt +++ b/rpcs3/Emu/CMakeLists.txt @@ -431,6 +431,7 @@ target_sources(rpcs3_emu PRIVATE RSX/Overlays/overlay_fonts.cpp RSX/Overlays/overlay_list_view.cpp RSX/Overlays/overlay_media_list_dialog.cpp + RSX/Overlays/overlay_message.cpp RSX/Overlays/overlay_message_dialog.cpp RSX/Overlays/overlay_osk.cpp RSX/Overlays/overlay_osk_panel.cpp diff --git a/rpcs3/Emu/NP/np_handler.cpp b/rpcs3/Emu/NP/np_handler.cpp index c8187a2b04..5da0b71d70 100644 --- a/rpcs3/Emu/NP/np_handler.cpp +++ b/rpcs3/Emu/NP/np_handler.cpp @@ -13,6 +13,7 @@ #include "Emu/NP/rpcn_config.h" #include "Emu/NP/np_contexts.h" #include "Emu/NP/np_helpers.h" +#include "Emu/RSX/Overlays/overlay_message.h" #ifdef _WIN32 #include @@ -591,6 +592,7 @@ namespace np if (auto state = rpcn->wait_for_connection(); state != rpcn::rpcn_state::failure_no_failure) { + rsx::overlays::queue_message(rpcn::rpcn_state_to_localized_string_id(state)); rpcn_log.error("Connection to RPCN Failed!"); is_psn_active = false; return; @@ -598,11 +600,14 @@ namespace np if (auto state = rpcn->wait_for_authentified(); state != rpcn::rpcn_state::failure_no_failure) { + rsx::overlays::queue_message(rpcn::rpcn_state_to_localized_string_id(state)); rpcn_log.error("RPCN login attempt failed!"); is_psn_active = false; return; } + rsx::overlays::queue_message(localized_string_id::RPCN_SUCCESS_LOGGED_ON); + string_to_online_name(rpcn->get_online_name(), &online_name); string_to_avatar_url(rpcn->get_avatar_url(), &avatar_url); public_ip_addr = rpcn->get_addr_sig(); diff --git a/rpcs3/Emu/NP/rpcn_client.cpp b/rpcs3/Emu/NP/rpcn_client.cpp index 2981d1b50e..8406d76d5d 100644 --- a/rpcs3/Emu/NP/rpcn_client.cpp +++ b/rpcs3/Emu/NP/rpcn_client.cpp @@ -49,6 +49,31 @@ std::vector> get_rpcn_msgs(); namespace rpcn { + localized_string_id rpcn_state_to_localized_string_id(rpcn::rpcn_state state) + { + switch (state) + { + case rpcn::rpcn_state::failure_no_failure: return localized_string_id::RPCN_NO_ERROR; + case rpcn::rpcn_state::failure_input: return localized_string_id::RPCN_ERROR_INVALID_INPUT; + case rpcn::rpcn_state::failure_wolfssl: return localized_string_id::RPCN_ERROR_WOLFSSL; + case rpcn::rpcn_state::failure_resolve: return localized_string_id::RPCN_ERROR_RESOLVE; + case rpcn::rpcn_state::failure_connect: return localized_string_id::RPCN_ERROR_CONNECT; + case rpcn::rpcn_state::failure_id: return localized_string_id::RPCN_ERROR_LOGIN_ERROR; + case rpcn::rpcn_state::failure_id_already_logged_in: return localized_string_id::RPCN_ERROR_ALREADY_LOGGED; + case rpcn::rpcn_state::failure_id_username: return localized_string_id::RPCN_ERROR_INVALID_LOGIN; + case rpcn::rpcn_state::failure_id_password: return localized_string_id::RPCN_ERROR_INVALID_PASSWORD; + case rpcn::rpcn_state::failure_id_token: return localized_string_id::RPCN_ERROR_INVALID_TOKEN; + case rpcn::rpcn_state::failure_protocol: return localized_string_id::RPCN_ERROR_INVALID_PROTOCOL_VERSION; + case rpcn::rpcn_state::failure_other: return localized_string_id::RPCN_ERROR_UNKNOWN; + default: return localized_string_id::INVALID; + } + } + + std::string rpcn_state_to_string(rpcn::rpcn_state state) + { + return get_localized_string(rpcn_state_to_localized_string_id(state)); + } + constexpr u32 RPCN_PROTOCOL_VERSION = 15; constexpr usz RPCN_HEADER_SIZE = 13; constexpr usz COMMUNICATION_ID_SIZE = 9; @@ -1592,7 +1617,7 @@ namespace rpcn std::copy(service_id.begin(), service_id.end(), std::back_inserter(data)); data.push_back(0); const le_t size = cookie.size(); - std::copy(reinterpret_cast(&size), reinterpret_cast(&size) + sizeof(le_t), std::back_inserter(data)); + std::copy(reinterpret_cast(&size), reinterpret_cast(&size) + sizeof(le_t), std::back_inserter(data)); std::copy(cookie.begin(), cookie.end(), std::back_inserter(data)); if (!forge_send(CommandType::RequestTicket, req_id, data)) @@ -1620,7 +1645,7 @@ namespace rpcn } auto npids_vector = builder.CreateVector(davec); - //auto npids = builder.Create + // auto npids = builder.Create auto fb_sendmessage = CreateSendMessageRequest(builder, nested_flatbuffer_vector, npids_vector); builder.Finish(fb_sendmessage); diff --git a/rpcs3/Emu/NP/rpcn_client.h b/rpcs3/Emu/NP/rpcn_client.h index 091ec06f47..d1e7e7b11d 100644 --- a/rpcs3/Emu/NP/rpcn_client.h +++ b/rpcs3/Emu/NP/rpcn_client.h @@ -5,6 +5,7 @@ #include #include #include "Utilities/mutex.h" +#include "Emu/localized_string.h" #include "util/asm.hpp" @@ -218,6 +219,9 @@ namespace rpcn std::set blocked; }; + localized_string_id rpcn_state_to_localized_string_id(rpcn::rpcn_state state); + std::string rpcn_state_to_string(rpcn::rpcn_state state); + class rpcn_client { private: diff --git a/rpcs3/Emu/RSX/Overlays/overlay_message.cpp b/rpcs3/Emu/RSX/Overlays/overlay_message.cpp new file mode 100644 index 0000000000..44a998b1dd --- /dev/null +++ b/rpcs3/Emu/RSX/Overlays/overlay_message.cpp @@ -0,0 +1,108 @@ +#include "stdafx.h" +#include "overlay_message.h" +#include "Emu/RSX/RSXThread.h" + +namespace rsx +{ + namespace overlays + { + message_item::message_item(localized_string_id msg_id) + { + m_expiration_time = get_system_time() + 5'000'000; + + m_text.set_font("Arial", 16); + m_text.set_text(msg_id); + m_text.auto_resize(); + m_text.back_color.a = 0.f; + + m_fade_animation.current = color4f(1.f); + m_fade_animation.end = color4f(1.0f, 1.0f, 1.0f, 0.f); + m_fade_animation.duration = 2.f; + m_fade_animation.active = true; + } + + u64 message_item::get_expiration() const + { + return m_expiration_time; + } + + compiled_resource message_item::get_compiled() + { + if (!m_processed) + { + return {}; + } + + auto cr = m_text.get_compiled(); + m_fade_animation.apply(cr); + + return cr; + } + + void message_item::update(usz index, u64 time) + { + if (m_cur_pos != index) + { + m_cur_pos = index; + m_text.set_pos(10, index * 18); + } + + if ((m_expiration_time - time) < 2'000'000) + { + m_fade_animation.update(rsx::get_current_renderer()->vblank_count); + } + + m_processed = true; + } + + void message::update() + { + if (!visible) + { + return; + } + + std::lock_guard lock(m_mutex_queue); + u64 cur_time = get_system_time(); + + while (!m_queue.empty() && m_queue.front().get_expiration() < cur_time) + { + m_queue.pop_front(); + } + + if (m_queue.empty()) + { + visible = false; + return; + } + + usz index = 0; + + for (auto& item : m_queue) + { + item.update(index, cur_time); + index++; + } + } + + compiled_resource message::get_compiled() + { + if (!visible) + { + return {}; + } + + std::lock_guard lock(m_mutex_queue); + + compiled_resource cr{}; + + for (auto& item : m_queue) + { + cr.add(item.get_compiled()); + } + + return cr; + } + + } // namespace overlays +} // namespace rsx diff --git a/rpcs3/Emu/RSX/Overlays/overlay_message.h b/rpcs3/Emu/RSX/Overlays/overlay_message.h new file mode 100644 index 0000000000..2c34813ebb --- /dev/null +++ b/rpcs3/Emu/RSX/Overlays/overlay_message.h @@ -0,0 +1,75 @@ +#pragma once + +#include "overlays.h" +#include + +namespace rsx +{ + namespace overlays + { + class message_item + { + public: + message_item(localized_string_id msg_id); + void update(usz index, u64 time); + + u64 get_expiration() const; + compiled_resource get_compiled(); + + private: + label m_text{}; + animation_color_interpolate m_fade_animation; + + u64 m_expiration_time = 0; + bool m_processed = false; + usz m_cur_pos = umax; + }; + + class message final : public user_interface + { + public: + void update() override; + compiled_resource get_compiled() override; + + template + void queue_message(T msg_id) + { + std::lock_guard lock(m_mutex_queue); + + if constexpr (std::is_same_v>) + { + for (auto id : msg_id) + { + m_queue.emplace_back(id); + } + } + else + { + m_queue.emplace_back(msg_id); + } + + visible = true; + } + + private: + shared_mutex m_mutex_queue; + std::deque m_queue; + }; + + template + void queue_message(T msg_id) + { + if (auto manager = g_fxo->try_get()) + { + auto msg_overlay = manager->get(); + if (!msg_overlay) + { + msg_overlay = std::make_shared(); + msg_overlay = manager->add(msg_overlay); + } + msg_overlay->queue_message(msg_id); + } + } + + } // namespace overlays +} // namespace rsx diff --git a/rpcs3/Emu/localized_string_id.h b/rpcs3/Emu/localized_string_id.h index d948160633..b523705905 100644 --- a/rpcs3/Emu/localized_string_id.h +++ b/rpcs3/Emu/localized_string_id.h @@ -128,4 +128,18 @@ enum class localized_string_id CELL_SAVEDATA_SAVE, CELL_SAVEDATA_LOAD, CELL_SAVEDATA_OVERWRITE, + + RPCN_NO_ERROR, + RPCN_ERROR_INVALID_INPUT, + RPCN_ERROR_WOLFSSL, + RPCN_ERROR_RESOLVE, + RPCN_ERROR_CONNECT, + RPCN_ERROR_LOGIN_ERROR, + RPCN_ERROR_ALREADY_LOGGED, + RPCN_ERROR_INVALID_LOGIN, + RPCN_ERROR_INVALID_PASSWORD, + RPCN_ERROR_INVALID_TOKEN, + RPCN_ERROR_INVALID_PROTOCOL_VERSION, + RPCN_ERROR_UNKNOWN, + RPCN_SUCCESS_LOGGED_ON, }; diff --git a/rpcs3/emucore.vcxproj b/rpcs3/emucore.vcxproj index 59074f80f3..35d01d6b92 100644 --- a/rpcs3/emucore.vcxproj +++ b/rpcs3/emucore.vcxproj @@ -379,6 +379,7 @@ + @@ -513,6 +514,7 @@ + diff --git a/rpcs3/emucore.vcxproj.filters b/rpcs3/emucore.vcxproj.filters index 942d76727f..080583ddcc 100644 --- a/rpcs3/emucore.vcxproj.filters +++ b/rpcs3/emucore.vcxproj.filters @@ -831,6 +831,9 @@ Emu\GPU\RSX\Overlays + + Emu\GPU\RSX\Overlays + Emu\GPU\RSX\Overlays @@ -1863,6 +1866,9 @@ Emu\GPU\RSX\Overlays + + Emu\GPU\RSX\Overlays + Emu\GPU\RSX\Overlays diff --git a/rpcs3/rpcs3qt/localized_emu.h b/rpcs3/rpcs3qt/localized_emu.h index 05efd1b5de..03aa2fa767 100644 --- a/rpcs3/rpcs3qt/localized_emu.h +++ b/rpcs3/rpcs3qt/localized_emu.h @@ -151,7 +151,19 @@ private: case localized_string_id::CELL_SAVEDATA_DELETE: return tr("Delete this data?\n\n%0", "Savedata entry info").arg(std::forward(args)...); case localized_string_id::CELL_SAVEDATA_LOAD: return tr("Load this data?\n\n%0", "Savedata entry info").arg(std::forward(args)...); case localized_string_id::CELL_SAVEDATA_OVERWRITE: return tr("Do you want to overwrite the saved data?\n\n%0", "Savedata entry info").arg(std::forward(args)...); - + case localized_string_id::RPCN_NO_ERROR: return tr("RPCN: No Error"); + case localized_string_id::RPCN_ERROR_INVALID_INPUT: return tr("RPCN: Invalid Input (Wrong Host/Port)"); + case localized_string_id::RPCN_ERROR_WOLFSSL: return tr("RPCN Connection Error: WolfSSL Error"); + case localized_string_id::RPCN_ERROR_RESOLVE: return tr("RPCN Connection Error: Resolve Error"); + case localized_string_id::RPCN_ERROR_CONNECT: return tr("RPCN Connection Error"); + case localized_string_id::RPCN_ERROR_LOGIN_ERROR: return tr("RPCN Login Error: Identification Error"); + case localized_string_id::RPCN_ERROR_ALREADY_LOGGED: return tr("RPCN Login Error: User Already Logged In"); + case localized_string_id::RPCN_ERROR_INVALID_LOGIN: return tr("RPCN Login Error: Invalid Username"); + case localized_string_id::RPCN_ERROR_INVALID_PASSWORD: return tr("RPCN Login Error: Invalid Password"); + case localized_string_id::RPCN_ERROR_INVALID_TOKEN: return tr("RPCN Login Error: Invalid Token"); + case localized_string_id::RPCN_ERROR_INVALID_PROTOCOL_VERSION: return tr("RPCN Misc Error: Protocol Version Error (outdated RPCS3?)"); + case localized_string_id::RPCN_ERROR_UNKNOWN: return tr("RPCN: Unknown Error"); + case localized_string_id::RPCN_SUCCESS_LOGGED_ON: return tr("Successfully logged on RPCN!"); case localized_string_id::INVALID: return tr("Invalid"); default: return tr("Unknown"); } diff --git a/rpcs3/rpcs3qt/rpcn_settings_dialog.cpp b/rpcs3/rpcs3qt/rpcn_settings_dialog.cpp index 857de64182..7b0aaaf560 100644 --- a/rpcs3/rpcs3qt/rpcn_settings_dialog.cpp +++ b/rpcs3/rpcs3qt/rpcn_settings_dialog.cpp @@ -18,26 +18,6 @@ LOG_CHANNEL(rpcn_settings_log, "rpcn settings dlg"); -const QString rpcn_state_to_qstr(rpcn::rpcn_state state) -{ - switch (state) - { - case rpcn::rpcn_state::failure_no_failure: return QObject::tr("No Error"); - case rpcn::rpcn_state::failure_input: return QObject::tr("Invalid Input"); - case rpcn::rpcn_state::failure_wolfssl: return QObject::tr("WolfSSL Error"); - case rpcn::rpcn_state::failure_resolve: return QObject::tr("Resolve Error"); - case rpcn::rpcn_state::failure_connect: return QObject::tr("Connect Error"); - case rpcn::rpcn_state::failure_id: return QObject::tr("Identification Error"); - case rpcn::rpcn_state::failure_id_already_logged_in: return QObject::tr("Identification Error: User Already Logged In"); - case rpcn::rpcn_state::failure_id_username: return QObject::tr("Identification Error: Invalid Username"); - case rpcn::rpcn_state::failure_id_password: return QObject::tr("Identification Error: Invalid Password"); - case rpcn::rpcn_state::failure_id_token: return QObject::tr("Identification Error: Invalid Token"); - case rpcn::rpcn_state::failure_protocol: return QObject::tr("Protocol Version Error"); - case rpcn::rpcn_state::failure_other: return QObject::tr("Unknown Error"); - default: return QObject::tr("Unhandled rpcn state!"); - } -} - bool validate_rpcn_username(const std::string& input) { if (input.length() < 3 || input.length() > 16) @@ -258,7 +238,7 @@ void rpcn_account_dialog::create_account() if (auto result = rpcn->wait_for_connection(); result != rpcn::rpcn_state::failure_no_failure) { - const QString error_message = tr("Failed to connect to RPCN server:\n%0").arg(rpcn_state_to_qstr(result)); + const QString error_message = tr("Failed to connect to RPCN server:\n%0").arg(QString::fromStdString(rpcn::rpcn_state_to_string(result))); QMessageBox::critical(this, tr("Error Connecting"), error_message, QMessageBox::Ok); return; } @@ -293,7 +273,7 @@ void rpcn_account_dialog::resend_token() if (auto result = rpcn->wait_for_connection(); result != rpcn::rpcn_state::failure_no_failure) { - const QString error_message = tr("Failed to connect to RPCN server:\n%0").arg(rpcn_state_to_qstr(result)); + const QString error_message = tr("Failed to connect to RPCN server:\n%0").arg(QString::fromStdString(rpcn::rpcn_state_to_string(result))); QMessageBox::critical(this, tr("Error Connecting"), error_message, QMessageBox::Ok); return; } @@ -436,13 +416,13 @@ rpcn_friends_dialog::rpcn_friends_dialog(QWidget* parent) if (auto res = m_rpcn->wait_for_connection(); res != rpcn::rpcn_state::failure_no_failure) { - const QString error_msg = tr("Failed to connect to RPCN:\n%0").arg(rpcn_state_to_qstr(res)); + const QString error_msg = tr("Failed to connect to RPCN:\n%0").arg(QString::fromStdString(rpcn::rpcn_state_to_string(res))); QMessageBox::warning(parent, tr("Error connecting to RPCN!"), error_msg, QMessageBox::Ok); return; } if (auto res = m_rpcn->wait_for_authentified(); res != rpcn::rpcn_state::failure_no_failure) { - const QString error_msg = tr("Failed to authentify to RPCN:\n%0").arg(rpcn_state_to_qstr(res)); + const QString error_msg = tr("Failed to authentify to RPCN:\n%0").arg(QString::fromStdString(rpcn::rpcn_state_to_string(res))); QMessageBox::warning(parent, tr("Error authentifying to RPCN!"), error_msg, QMessageBox::Ok); return; }