From c0b6076bbcd71221654c71c9abfc85fec45f75a1 Mon Sep 17 00:00:00 2001 From: Liparakis Date: Sat, 28 Mar 2026 21:58:40 +0200 Subject: [PATCH 1/2] feat: Added multiplayer button hooks to UiManager --- SSMP/Api/Client/IUiManager.cs | 39 +++++++++++++++++++++++++++++++++++ SSMP/Ui/UiManager.cs | 26 ++++++++++++++++++++++- 2 files changed, 64 insertions(+), 1 deletion(-) diff --git a/SSMP/Api/Client/IUiManager.cs b/SSMP/Api/Client/IUiManager.cs index e4a35c0..c9f4fff 100644 --- a/SSMP/Api/Client/IUiManager.cs +++ b/SSMP/Api/Client/IUiManager.cs @@ -1,3 +1,5 @@ +using System; + namespace SSMP.Api.Client; /// @@ -8,4 +10,41 @@ public interface IUiManager { /// The message box that shows information related to SSMP. /// IChatBox ChatBox { get; } + + /// + /// Fired when the multiplayer button is pressed, before any blocking hooks run. + /// Use this for fire-and-forget reactions such as logging or showing a notification? + /// + event Action? MultiplayerButtonPressed; + + /// + /// Registers a hook that is invoked when the multiplayer button is pressed. + /// + /// + /// Hooks are executed in reverse order (last registered runs first). + /// + /// Example (informational hook): + /// + /// RegisterMultiplayerMenuHook(next => { + /// MyNonMandatoryDependencyPopup.Show( + /// "Addon X unavailable", + /// onAccept: _ => {continue; }, + /// onDecline: _ => { continue; }); + /// }); + /// + /// + /// Example (blocking hook): + /// + /// RegisterMultiplayerMenuHook(next => { + /// MyMandatoryDependencyPopup.Show( + /// "Addon X unavailable", + /// onConfirm: agreed => { if (agreed) continue; }); + /// onDecline: agreed => { if (!agreed) return; }); + /// }); + /// + /// + /// + /// The hook to register. Receives a callback to invoke when ready to proceed. + /// + void RegisterMultiplayerMenuHook(Action hook); } diff --git a/SSMP/Ui/UiManager.cs b/SSMP/Ui/UiManager.cs index a0d1219..f49b85f 100644 --- a/SSMP/Ui/UiManager.cs +++ b/SSMP/Ui/UiManager.cs @@ -142,6 +142,9 @@ internal class UiManager : IUiManager { /// public event Action? RequestClientDisconnectEvent; + /// + public event Action? MultiplayerButtonPressed; + #endregion #region Fields @@ -207,6 +210,12 @@ internal class UiManager : IUiManager { /// private bool _isSlotSelectionActive; + /// + /// The head of the multiplayer menu hook chain. + /// Starts as the bare transition; each registered hook wraps it. + /// + private Action _multiplayerMenuChain; + #endregion #region Properties @@ -243,6 +252,13 @@ public IChatBox ChatBox { public UiManager(ModSettings modSettings, NetClient netClient) { _modSettings = modSettings; _netClient = netClient; + _multiplayerMenuChain = () => UM.StartCoroutine(GoToMultiplayerMenu()); + } + + /// + public void RegisterMultiplayerMenuHook(Action hook) { + var previous = _multiplayerMenuChain; + _multiplayerMenuChain = () => hook(previous); } #endregion @@ -738,7 +754,7 @@ private void ConfigureButtonTriggers(GameObject button) { if (eventTrigger == null) return; eventTrigger.triggers.Clear(); - AddButtonTriggers(eventTrigger, () => UM.StartCoroutine(GoToMultiplayerMenu())); + AddButtonTriggers(eventTrigger, OnMultiplayerMenuRequested); } /// @@ -777,6 +793,14 @@ private void SetNavigation(MenuButton button, MenuButton? selectOnUp = null, Men button.navigation = nav; } + /// + /// Handles the multiplayer menu request by firing the notification event, then invoking the hook chain. + /// + private void OnMultiplayerMenuRequested() { + MultiplayerButtonPressed?.Invoke(); + _multiplayerMenuChain(); + } + #endregion #region Menu Navigation From 2c63b389fd29ef192b5aa77df2e4117e72dcd51f Mon Sep 17 00:00:00 2001 From: Liparakis Date: Sat, 28 Mar 2026 22:24:19 +0200 Subject: [PATCH 2/2] chore: Suggested fixes --- SSMP/Api/Client/IUiManager.cs | 2 +- SSMP/Ui/UiManager.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/SSMP/Api/Client/IUiManager.cs b/SSMP/Api/Client/IUiManager.cs index c9f4fff..049c0dd 100644 --- a/SSMP/Api/Client/IUiManager.cs +++ b/SSMP/Api/Client/IUiManager.cs @@ -13,7 +13,7 @@ public interface IUiManager { /// /// Fired when the multiplayer button is pressed, before any blocking hooks run. - /// Use this for fire-and-forget reactions such as logging or showing a notification? + /// Use this for fire-and-forget reactions such as logging or showing a notification. /// event Action? MultiplayerButtonPressed; diff --git a/SSMP/Ui/UiManager.cs b/SSMP/Ui/UiManager.cs index f49b85f..29292a8 100644 --- a/SSMP/Ui/UiManager.cs +++ b/SSMP/Ui/UiManager.cs @@ -798,7 +798,7 @@ private void SetNavigation(MenuButton button, MenuButton? selectOnUp = null, Men /// private void OnMultiplayerMenuRequested() { MultiplayerButtonPressed?.Invoke(); - _multiplayerMenuChain(); + _multiplayerMenuChain.Invoke(); } #endregion