Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 39 additions & 0 deletions SSMP/Api/Client/IUiManager.cs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
using System;

namespace SSMP.Api.Client;

/// <summary>
Expand All @@ -8,4 +10,41 @@ public interface IUiManager {
/// The message box that shows information related to SSMP.
/// </summary>
IChatBox ChatBox { get; }

/// <summary>
/// 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.
/// </summary>
event Action? MultiplayerButtonPressed;

/// <summary>
/// Registers a hook that is invoked when the multiplayer button is pressed.
/// </summary>
/// <remarks>
/// Hooks are executed in reverse order (last registered runs first).
///
/// Example (informational hook):
/// <code>
/// RegisterMultiplayerMenuHook(next => {
/// MyNonMandatoryDependencyPopup.Show(
/// "Addon X unavailable",
/// onAccept: _ => {continue; },
/// onDecline: _ => { continue; });
/// });
/// </code>
///
/// Example (blocking hook):
/// <code>
/// RegisterMultiplayerMenuHook(next => {
/// MyMandatoryDependencyPopup.Show(
/// "Addon X unavailable",
/// onConfirm: agreed => { if (agreed) continue; });
/// onDecline: agreed => { if (!agreed) return; });
/// });
/// </code>
/// </remarks>
/// <param name="hook">
/// The hook to register. Receives a callback to invoke when ready to proceed.
/// </param>
void RegisterMultiplayerMenuHook(Action<Action> hook);
}
26 changes: 25 additions & 1 deletion SSMP/Ui/UiManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,9 @@ internal class UiManager : IUiManager {
/// </summary>
public event Action? RequestClientDisconnectEvent;

/// <inheritdoc />
public event Action? MultiplayerButtonPressed;

#endregion

#region Fields
Expand Down Expand Up @@ -207,6 +210,12 @@ internal class UiManager : IUiManager {
/// </summary>
private bool _isSlotSelectionActive;

/// <summary>
/// The head of the multiplayer menu hook chain.
/// Starts as the bare transition; each registered hook wraps it.
/// </summary>
private Action _multiplayerMenuChain;

#endregion

#region Properties
Expand Down Expand Up @@ -243,6 +252,13 @@ public IChatBox ChatBox {
public UiManager(ModSettings modSettings, NetClient netClient) {
_modSettings = modSettings;
_netClient = netClient;
_multiplayerMenuChain = () => UM.StartCoroutine(GoToMultiplayerMenu());
}

/// <inheritdoc />
public void RegisterMultiplayerMenuHook(Action<Action> hook) {
var previous = _multiplayerMenuChain;
_multiplayerMenuChain = () => hook(previous);
}

#endregion
Expand Down Expand Up @@ -738,7 +754,7 @@ private void ConfigureButtonTriggers(GameObject button) {
if (eventTrigger == null) return;

eventTrigger.triggers.Clear();
AddButtonTriggers(eventTrigger, () => UM.StartCoroutine(GoToMultiplayerMenu()));
AddButtonTriggers(eventTrigger, OnMultiplayerMenuRequested);
}

/// <summary>
Expand Down Expand Up @@ -777,6 +793,14 @@ private void SetNavigation(MenuButton button, MenuButton? selectOnUp = null, Men
button.navigation = nav;
}

/// <summary>
/// Handles the multiplayer menu request by firing the notification event, then invoking the hook chain.
/// </summary>
private void OnMultiplayerMenuRequested() {
MultiplayerButtonPressed?.Invoke();
_multiplayerMenuChain.Invoke();
}

#endregion

#region Menu Navigation
Expand Down