From d76f2faa69d5902150658b5266a29c28d84687e5 Mon Sep 17 00:00:00 2001 From: collecting Date: Fri, 24 Oct 2025 00:08:25 +0000 Subject: [PATCH] feat: Add multiplayer-room-overlay --- src/citron/main.h | 322 +++++++--------------------------------------- 1 file changed, 48 insertions(+), 274 deletions(-) diff --git a/src/citron/main.h b/src/citron/main.h index 30ab3f2cc..a994a583b 100644 --- a/src/citron/main.h +++ b/src/citron/main.h @@ -6,14 +6,12 @@ #include #include - #include #include #include #include #include #include - #include "common/announce_multiplayer_room.h" #include "common/common_types.h" #include "configuration/qt_config.h" @@ -39,11 +37,9 @@ class LoadingScreen; class MicroProfileDialog; class OverlayDialog; class PerformanceOverlay; +class MultiplayerRoomOverlay; class VramOverlay; class ProfilerWidget; - -// Forward declaration -class PerformanceOverlay; class ControllerDialog; class QLabel; class MultiplayerState; @@ -58,7 +54,6 @@ enum class GameListShortcutTarget; enum class DumpRomFSTarget; enum class InstalledEntryType; class GameListPlaceholder; - class QtAmiiboSettingsDialog; class QtControllerSelectorDialog; class QtProfileSelectionDialog; @@ -66,75 +61,21 @@ class QtSoftwareKeyboardDialog; class QtNXWebEngineView; class UpdaterDialog; -enum class StartGameType { - Normal, // Can use custom configuration - Global, // Only uses global configuration -}; +enum class StartGameType { Normal, Global }; -namespace Core { - enum class SystemResultStatus : u32; - class System; -} // namespace Core - -namespace Core::Frontend { - struct CabinetParameters; - struct ControllerParameters; - struct InlineAppearParameters; - struct InlineTextParameters; - struct KeyboardInitializeParameters; - struct ProfileSelectParameters; -} // namespace Core::Frontend - -namespace DiscordRPC { - class DiscordInterface; -} - -namespace PlayTime { - class PlayTimeManager; -} - -namespace FileSys { - class ContentProvider; - class ManualContentProvider; - class VfsFilesystem; -} // namespace FileSys - -namespace InputCommon { - class InputSubsystem; -} - -namespace Service::AM { - struct FrontendAppletParameters; - enum class AppletId : u32; -} // namespace Service::AM - -namespace Service::AM::Frontend { - enum class SwkbdResult : u32; - enum class SwkbdTextCheckResult : u32; - enum class SwkbdReplyType : u32; - enum class WebExitReason : u32; -} // namespace Service::AM::Frontend - -namespace Service::NFC { - class NfcDevice; -} // namespace Service::NFC - -namespace Service::NFP { - enum class CabinetMode : u8; -} // namespace Service::NFP - -namespace Ui { - class MainWindow; -} - -enum class EmulatedDirectoryTarget { - NAND, - SDMC, -}; - -namespace VkDeviceInfo { - class Record; -} +namespace Core { enum class SystemResultStatus : u32; class System; } +namespace Core::Frontend { struct CabinetParameters; struct ControllerParameters; struct InlineAppearParameters; struct InlineTextParameters; struct KeyboardInitializeParameters; struct ProfileSelectParameters; } +namespace DiscordRPC { class DiscordInterface; } +namespace PlayTime { class PlayTimeManager; } +namespace FileSys { class ContentProvider; class ManualContentProvider; class VfsFilesystem; } +namespace InputCommon { class InputSubsystem; } +namespace Service::AM { struct FrontendAppletParameters; enum class AppletId : u32; } +namespace Service::AM::Frontend { enum class SwkbdResult : u32; enum class SwkbdTextCheckResult : u32; enum class SwkbdReplyType : u32; enum class WebExitReason : u32; } +namespace Service::NFC { class NfcDevice; } +namespace Service::NFP { enum class CabinetMode : u8; } +namespace Ui { class MainWindow; } +enum class EmulatedDirectoryTarget { NAND, SDMC }; +namespace VkDeviceInfo { class Record; } class VolumeButton : public QPushButton { Q_OBJECT @@ -142,16 +83,12 @@ public: explicit VolumeButton(QWidget* parent = nullptr) : QPushButton(parent), scroll_multiplier(1) { connect(&scroll_timer, &QTimer::timeout, this, &VolumeButton::ResetMultiplier); } - signals: void VolumeChanged(); - protected: void wheelEvent(QWheelEvent* event) override; - private slots: void ResetMultiplier(); - private: int scroll_multiplier; QTimer scroll_timer; @@ -160,94 +97,45 @@ private: class GMainWindow : public QMainWindow { Q_OBJECT - - /// Max number of recently loaded items to keep track of static const int max_recent_files_item = 10; - friend class PerformanceOverlay; friend class VramOverlay; - - enum { - CREATE_SHORTCUT_MSGBOX_FULLSCREEN_YES, - CREATE_SHORTCUT_MSGBOX_SUCCESS, - CREATE_SHORTCUT_MSGBOX_ERROR, - CREATE_SHORTCUT_MSGBOX_APPVOLATILE_WARNING, - }; - + enum { CREATE_SHORTCUT_MSGBOX_FULLSCREEN_YES, CREATE_SHORTCUT_MSGBOX_SUCCESS, CREATE_SHORTCUT_MSGBOX_ERROR, CREATE_SHORTCUT_MSGBOX_APPVOLATILE_WARNING }; public: void filterBarSetChecked(bool state); void UpdateUITheme(); explicit GMainWindow(std::unique_ptr config_, bool has_broken_vulkan); ~GMainWindow() override; - bool DropAction(QDropEvent* event); void AcceptDropEvent(QDropEvent* event); - - /** - * This is the new function to provide access to the MultiplayerState. - */ - MultiplayerState* GetMultiplayerState() { - return multiplayer_state; - } - + MultiplayerState* GetMultiplayerState() { return multiplayer_state; } + bool IsEmulationRunning() const { return emulation_running; } signals: - - /** - * Signal that is emitted when a new EmuThread has been created and an emulation session is - * about to start. At this time, the core system emulation has been initialized, and all - * emulation handles and memory should be valid. - * - * @param emu_thread Pointer to the newly created EmuThread (to be used by widgets that need to - * access/change emulation state). - */ void EmulationStarting(EmuThread* emu_thread); - - /** - * Signal that is emitted when emulation is about to stop. At this time, the EmuThread and core - * system emulation handles and memory are still valid, but are about become invalid. - */ void EmulationStopping(); - - // Signal that tells widgets to update icons to use the current theme void UpdateThemedIcons(); - void UpdateInstallProgress(); - void AmiiboSettingsFinished(bool is_success, const std::string& name); - void ControllerSelectorReconfigureFinished(bool is_success); - void ErrorDisplayFinished(); - void ProfileSelectorFinishedSelection(std::optional uuid); - - void SoftwareKeyboardSubmitNormalText(Service::AM::Frontend::SwkbdResult result, - std::u16string submitted_text, bool confirmed); - void SoftwareKeyboardSubmitInlineText(Service::AM::Frontend::SwkbdReplyType reply_type, - std::u16string submitted_text, s32 cursor_position); - + void SoftwareKeyboardSubmitNormalText(Service::AM::Frontend::SwkbdResult result, std::u16string submitted_text, bool confirmed); + void SoftwareKeyboardSubmitInlineText(Service::AM::Frontend::SwkbdReplyType reply_type, std::u16string submitted_text, s32 cursor_position); void WebBrowserExtractOfflineRomFS(); void WebBrowserClosed(Service::AM::Frontend::WebExitReason exit_reason, std::string last_url); - void SigInterrupt(); - public slots: void OnLoadComplete(); void OnExecuteProgram(std::size_t program_index); void OnExit(); void OnSaveConfig(); - void AmiiboSettingsShowDialog(const Core::Frontend::CabinetParameters& parameters, - std::shared_ptr nfp_device); + void AmiiboSettingsShowDialog(const Core::Frontend::CabinetParameters& parameters, std::shared_ptr nfp_device); void AmiiboSettingsRequestExit(); - void ControllerSelectorReconfigureControllers( - const Core::Frontend::ControllerParameters& parameters); + void ControllerSelectorReconfigureControllers(const Core::Frontend::ControllerParameters& parameters); void ControllerSelectorRequestExit(); - void SoftwareKeyboardInitialize( - bool is_inline, Core::Frontend::KeyboardInitializeParameters initialize_parameters); + void SoftwareKeyboardInitialize(bool is_inline, Core::Frontend::KeyboardInitializeParameters initialize_parameters); void SoftwareKeyboardShowNormal(); - void SoftwareKeyboardShowTextCheck( - Service::AM::Frontend::SwkbdTextCheckResult text_check_result, - std::u16string text_check_message); + void SoftwareKeyboardShowTextCheck(Service::AM::Frontend::SwkbdTextCheckResult text_check_result, std::u16string text_check_message); void SoftwareKeyboardShowInline(Core::Frontend::InlineAppearParameters appear_parameters); void SoftwareKeyboardHideInline(); void SoftwareKeyboardInlineTextChanged(Core::Frontend::InlineTextParameters text_parameters); @@ -256,98 +144,51 @@ public slots: void ErrorDisplayRequestExit(); void ProfileSelectorSelectProfile(const Core::Frontend::ProfileSelectParameters& parameters); void ProfileSelectorRequestExit(); - void WebBrowserOpenWebPage(const std::string& main_url, const std::string& additional_args, - bool is_local); + void WebBrowserOpenWebPage(const std::string& main_url, const std::string& additional_args, bool is_local); void WebBrowserRequestExit(); void OnAppFocusStateChanged(Qt::ApplicationState state); void OnTasStateChanged(); - private: - /// Updates an action's shortcut and text to reflect an updated hotkey from the hotkey registry. - void LinkActionShortcut(QAction* action, const QString& action_name, - const bool tas_allowed = false); - + void LinkActionShortcut(QAction* action, const QString& action_name, const bool tas_allowed = false); void RegisterMetaTypes(); void RegisterAutoloaderContents(); - void InitializeWidgets(); void InitializeDebugWidgets(); void InitializeRecentFileMenuActions(); - void SetDefaultUIGeometry(); void RestoreUIState(); - void ConnectWidgetEvents(); void ConnectMenuEvents(); void UpdateMenuState(); - void SetupPrepareForSleep(); - void PreventOSSleep(); void AllowOSSleep(); - bool LoadROM(const QString& filename, Service::AM::FrontendAppletParameters params); - void BootGame(const QString& filename, Service::AM::FrontendAppletParameters params, - StartGameType with_config = StartGameType::Normal); + void BootGame(const QString& filename, Service::AM::FrontendAppletParameters params, StartGameType with_config = StartGameType::Normal); void BootGameFromList(const QString& filename, StartGameType with_config); void ShutdownGame(); - void ShowTelemetryCallout(); void SetDiscordEnabled(bool state); void LoadAmiibo(const QString& filename); - bool SelectAndSetCurrentUser(const Core::Frontend::ProfileSelectParameters& parameters); - - /** - * Stores the filename in the recently loaded files list. - * The new filename is stored at the beginning of the recently loaded files list. - * After inserting the new entry, duplicates are removed meaning that if - * this was inserted from \a OnMenuRecentFile(), the entry will be put on top - * and remove from its previous position. - * - * Finally, this function calls \a UpdateRecentFiles() to update the UI. - * - * @param filename the filename to store - */ void StoreRecentFile(const QString& filename); - - /** - * Updates the recent files menu. - * Menu entries are rebuilt from the configuration file. - * If there is no entry in the menu, the menu is greyed out. - */ void UpdateRecentFiles(); - - /** - * If the emulation is running, - * asks the user if he really want to close the emulator - * - * @return true if the user confirmed - */ bool ConfirmClose(); bool ConfirmChangeGame(); bool ConfirmForceLockedExit(); void RequestGameExit(); void changeEvent(QEvent* event) override; void closeEvent(QCloseEvent* event) override; - - std::string CreateTASFramesString( - std::array frames) const; - - #ifdef __unix__ - void SetupSigInterrupts(); - static void HandleSigInterrupt(int); - void OnSigInterruptNotifierActivated(); - void SetGamemodeEnabled(bool state); - #endif - - Service::AM::FrontendAppletParameters ApplicationAppletParameters(); - Service::AM::FrontendAppletParameters LibraryAppletParameters(u64 program_id, - Service::AM::AppletId applet_id); - - // This will hold and provide all discovered Autoloader content. - std::unique_ptr autoloader_provider; - + std::string CreateTASFramesString(std::array frames) const; + #ifdef __unix__ + void SetupSigInterrupts(); + static void HandleSigInterrupt(int); + void OnSigInterruptNotifierActivated(); + void SetGamemodeEnabled(bool state); + #endif + Service::AM::FrontendAppletParameters ApplicationAppletParameters(); + Service::AM::FrontendAppletParameters LibraryAppletParameters(u64 program_id, Service::AM::AppletId applet_id); + std::unique_ptr autoloader_provider; private slots: void OnStartGame(); void OnRestartGame(); @@ -357,22 +198,17 @@ private slots: void OnPrepareForSleep(bool prepare_sleep); void OnMenuReportCompatibility(); void OnOpenSupport(); - /// Called whenever a user selects a game in the game list widget. void OnGameListLoadFile(QString game_path, u64 program_id); - void OnGameListOpenFolder(u64 program_id, GameListOpenTarget target, - const std::string& game_path); + void OnGameListOpenFolder(u64 program_id, GameListOpenTarget target, const std::string& game_path); void OnTransferableShaderCacheOpenFile(u64 program_id); void OnGameListRemoveInstalledEntry(u64 program_id, InstalledEntryType type); - void OnGameListRemoveFile(u64 program_id, GameListRemoveTarget target, - const std::string& game_path); + void OnGameListRemoveFile(u64 program_id, GameListRemoveTarget target, const std::string& game_path); void OnGameListRemovePlayTimeData(u64 program_id); void OnGameListDumpRomFS(u64 program_id, const std::string& game_path, DumpRomFSTarget target); void OnGameListVerifyIntegrity(const std::string& game_path); void OnGameListCopyTID(u64 program_id); - void OnGameListNavigateToGamedbEntry(u64 program_id, - const CompatibilityList& compatibility_list); - void OnGameListCreateShortcut(u64 program_id, const std::string& game_path, - GameListShortcutTarget target); + void OnGameListNavigateToGamedbEntry(u64 program_id, const CompatibilityList& compatibility_list); + void OnGameListCreateShortcut(u64 program_id, const std::string& game_path, GameListShortcutTarget target); void OnGameListOpenDirectory(const QString& directory); void OnGameListAddDirectory(); void OnGameListShowList(bool show); @@ -411,16 +247,13 @@ private slots: void OnToggleGridView(); void OnToggleStatusBar(); void OnTogglePerformanceOverlay(); + void OnToggleMultiplayerRoomOverlay(); void OnToggleVramOverlay(); void OnDisplayTitleBars(bool); - - // Performance overlay access methods double GetCurrentFPS() const; double GetCurrentFrameTime() const; u32 GetShadersBuilding() const; double GetEmulationSpeed() const; - - // VRAM overlay access methods u64 GetTotalVram() const; u64 GetUsedVram() const; u64 GetBufferMemoryUsage() const; @@ -448,7 +281,6 @@ private slots: void OnShutdownBeginDialog(); void OnEmulationStopped(); void OnEmulationStopTimeExpired(); - private: QString GetGameListErrorRemoving(InstalledEntryType type) const; void RemoveBaseContent(u64 program_id, InstalledEntryType type); @@ -460,12 +292,10 @@ private: void RemoveCustomConfiguration(u64 program_id, const std::string& game_path); void RemovePlayTimeData(u64 program_id); void RemoveCacheStorage(u64 program_id); - bool SelectRomFSDumpTarget(const FileSys::ContentProvider&, u64 program_id, - u64* selected_title_id, u8* selected_content_record_type); + bool SelectRomFSDumpTarget(const FileSys::ContentProvider&, u64 program_id, u64* selected_title_id, u8* selected_content_record_type); ContentManager::InstallResult InstallNCA(const QString& filename); void MigrateConfigFiles(); - void UpdateWindowTitle(std::string_view title_name = {}, std::string_view title_version = {}, - std::string_view gpu_vendor = {}); + void UpdateWindowTitle(std::string_view title_name = {}, std::string_view title_version = {}, std::string_view gpu_vendor = {}); void UpdateDockedButton(); void UpdateAPIText(); void UpdateFilterText(); @@ -485,54 +315,28 @@ private: bool CheckFirmwarePresence(); void SetFirmwareVersion(); void ConfigureFilesystemProvider(const std::string& filepath); - /** - * Open (or not) the right confirm dialog based on current setting and game exit lock - * @returns true if the player confirmed or the settings do no require it - */ bool ConfirmShutdownGame(); - QString GetTasStateDescription() const; bool CreateShortcutMessagesGUI(QWidget* parent, int imsg, const QString& game_title); - bool MakeShortcutIcoPath(const u64 program_id, const std::string_view game_file_name, - std::filesystem::path& out_icon_path); - bool CreateShortcutLink(const std::filesystem::path& shortcut_path, const std::string& comment, - const std::filesystem::path& icon_path, - const std::filesystem::path& command, const std::string& arguments, - const std::string& categories, const std::string& keywords, - const std::string& name); - /** - * Mimic the behavior of QMessageBox::question but link controller navigation to the dialog - * The only difference is that it returns a boolean. - * - * @returns true if buttons contains QMessageBox::Yes and the user clicks on the "Yes" button. - */ - bool question(QWidget* parent, const QString& title, const QString& text, - QMessageBox::StandardButtons buttons = - QMessageBox::StandardButtons(QMessageBox::Yes | QMessageBox::No), - QMessageBox::StandardButton defaultButton = QMessageBox::NoButton); - + bool MakeShortcutIcoPath(const u64 program_id, const std::string_view game_file_name, std::filesystem::path& out_icon_path); + bool CreateShortcutLink(const std::filesystem::path& shortcut_path, const std::string& comment, const std::filesystem::path& icon_path, const std::filesystem::path& command, const std::string& arguments, const std::string& categories, const std::string& keywords, const std::string& name); + bool question(QWidget* parent, const QString& title, const QString& text, QMessageBox::StandardButtons buttons = QMessageBox::StandardButtons(QMessageBox::Yes | QMessageBox::No), QMessageBox::StandardButton defaultButton = QMessageBox::NoButton); std::unique_ptr ui; - std::unique_ptr system; std::unique_ptr discord_rpc; std::unique_ptr play_time_manager; std::shared_ptr input_subsystem; - MultiplayerState* multiplayer_state = nullptr; - GRenderWindow* render_window; GameList* game_list; LoadingScreen* loading_screen; QTimer shutdown_timer; OverlayDialog* shutdown_dialog{}; PerformanceOverlay* performance_overlay{}; + MultiplayerRoomOverlay* multiplayer_room_overlay{}; VramOverlay* vram_overlay{}; - GameListPlaceholder* game_list_placeholder; - std::vector vk_device_records; - - // Status bar elements QLabel* message_label = nullptr; QLabel* shader_building_label = nullptr; QLabel* res_scale_label = nullptr; @@ -550,72 +354,42 @@ private: QWidget* volume_popup = nullptr; QSlider* volume_slider = nullptr; QTimer status_bar_update_timer; - std::unique_ptr config; - - // Whether emulation is currently running in citron. bool emulation_running = false; std::unique_ptr emu_thread; - // The path to the game currently running QString current_game_path; - // Whether a user was set on the command line (skips UserSelector if it's forced to show up) bool user_flag_cmd_line = false; - bool auto_paused = false; bool auto_muted = false; QTimer mouse_hide_timer; QTimer update_input_timer; - QString startup_icon_theme; bool os_dark_mode = false; - - // FS std::shared_ptr vfs; std::unique_ptr provider; - - // Debugger panes ProfilerWidget* profilerWidget; MicroProfileDialog* microProfileDialog; WaitTreeWidget* waitTreeWidget; ControllerDialog* controller_dialog; - QAction* actions_recent_files[max_recent_files_item]; - - // stores default icon theme search paths for the platform QStringList default_theme_paths; - HotkeyRegistry hotkey_registry; - QTranslator translator; - - // Install progress dialog QProgressDialog* install_progress; - - // Last game booted, used for multi-process apps QString last_filename_booted; - - // Applets QtAmiiboSettingsDialog* cabinet_applet = nullptr; QtControllerSelectorDialog* controller_applet = nullptr; QtProfileSelectionDialog* profile_select_applet = nullptr; QDialog* error_applet = nullptr; QtSoftwareKeyboardDialog* software_keyboard = nullptr; QtNXWebEngineView* web_applet = nullptr; - - // True if amiibo file select is visible bool is_amiibo_file_select_active{}; - - // True if load file select is visible bool is_load_file_select_active{}; - - // True if TAS recording dialog is visible bool is_tas_recording_dialog_active{}; - #ifdef __unix__ QSocketNotifier* sig_interrupt_notifier; static std::array sig_interrupt_fds; #endif - protected: void dropEvent(QDropEvent* event) override; void dragEnterEvent(QDragEnterEvent* event) override;