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
66 changes: 51 additions & 15 deletions managed/src/SwiftlyS2.Core/Modules/Menus/MenuAPI.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
using SwiftlyS2.Shared;
using SwiftlyS2.Shared.Menus;
using SwiftlyS2.Core.Natives;
using SwiftlyS2.Core.Menus.OptionsBase;
using SwiftlyS2.Shared.Players;
using SwiftlyS2.Shared.SchemaDefinitions;

Expand Down Expand Up @@ -41,6 +42,11 @@ internal sealed class MenuAPI : IMenuAPI, IDisposable
/// </summary>
public IMenuBuilderAPI? Builder { get; init; }

/// <summary>
/// Gets or sets the default comment text to use when a menu option's Comment is not set.
/// </summary>
public string DefaultComment { get; set; } = $"Powered by <font color='#ff3c00'>❤️</font> {HtmlGradient.GenerateGradientText("SwiftlyS2", "#ffffff", "#96d5ff")}";

/// <summary>
/// Gets or sets an object that contains data about this menu.
/// </summary>
Expand Down Expand Up @@ -252,9 +258,10 @@ private void OnRender()

foreach (var option in options)
{
if (option is OptionsBase.MenuOptionBase optionBase)
if (option is MenuOptionBase optionBase)
{
optionBase.UpdateDynamicText(now);
optionBase.UpdateCustomAnimations(now);
}
}

Expand Down Expand Up @@ -418,22 +425,47 @@ private string BuildMenuHtml( IPlayer player, IReadOnlyList<IMenuOption> visible
option.GetDisplayText(player, 0)
)));

var currentOption = visibleOptions.Count > 0 ? visibleOptions[arrowPosition] : null;
var optionBase = currentOption as MenuOptionBase;

var comment = !string.IsNullOrWhiteSpace(optionBase?.Comment)
? string.Concat(
"<br>",
guideLine,
"<br>",
$"<font class='fontSize-s'>{optionBase.Comment}</font><br>"
)
: string.Concat(
"<br>",
guideLine,
"<br>",
$"<font class='fontSize-s'>{DefaultComment}</font><br>"
);

var claimInfo = optionBase?.InputClaimInfo ?? MenuInputClaimInfo.Empty;

var footerSection = Configuration.HideFooter ? string.Empty :
core.MenusAPI.Configuration.InputMode switch {
"wasd" => string.Concat(
"<br>", guideLine, "<br>",
"<font class='fontSize-s' color='#FFFFFF'>",
$"<font color='{footerColor}'>Move:</font> W/S",
$" | <font color='{footerColor}'>Use:</font> D",
Configuration.DisableExit ? string.Empty : $" | <font color='{footerColor}'>Exit:</font> A",
claimInfo.ClaimsUse
? $" | <font color='{footerColor}'>{claimInfo.UseLabel ?? "Use"}:</font> D"
: $" | <font color='{footerColor}'>Use:</font> D",
claimInfo.ClaimsExit
? $" | <font color='{footerColor}'>{claimInfo.ExitLabel ?? "Exit"}:</font> A"
: (Configuration.DisableExit ? string.Empty : $" | <font color='{footerColor}'>Exit:</font> A"),
"</font>"
),
_ => string.Concat(
"<br>", guideLine, "<br>",
"<font class='fontSize-s' color='#FFFFFF'>",
$"<font color='{footerColor}'>Move:</font> {KeybindOverrides.Move?.ToString() ?? core.MenusAPI.Configuration.ButtonsScroll.ToUpper()}/{KeybindOverrides.MoveBack?.ToString() ?? core.MenusAPI.Configuration.ButtonsScrollBack.ToUpper()}",
$" | <font color='{footerColor}'>Use:</font> {KeybindOverrides.Select?.ToString() ?? core.MenusAPI.Configuration.ButtonsUse.ToUpper()}",
Configuration.DisableExit ? string.Empty : $" | <font color='{footerColor}'>Exit:</font> {KeybindOverrides.Exit?.ToString() ?? core.MenusAPI.Configuration.ButtonsExit.ToUpper()}",
claimInfo.ClaimsUse
? $" | <font color='{footerColor}'>{claimInfo.UseLabel ?? "Use"}:</font> {KeybindOverrides.Select?.ToString() ?? core.MenusAPI.Configuration.ButtonsUse.ToUpper()}"
: $" | <font color='{footerColor}'>Use:</font> {KeybindOverrides.Select?.ToString() ?? core.MenusAPI.Configuration.ButtonsUse.ToUpper()}",
claimInfo.ClaimsExit
? $" | <font color='{footerColor}'>{claimInfo.ExitLabel ?? "Exit"}:</font> {KeybindOverrides.Exit?.ToString() ?? core.MenusAPI.Configuration.ButtonsExit.ToUpper()}"
: (Configuration.DisableExit ? string.Empty : $" | <font color='{footerColor}'>Exit:</font> {KeybindOverrides.Exit?.ToString() ?? core.MenusAPI.Configuration.ButtonsExit.ToUpper()}"),
"</font>"
)
};
Expand All @@ -443,6 +475,7 @@ private string BuildMenuHtml( IPlayer player, IReadOnlyList<IMenuOption> visible
"<font color='#FFFFFF' class='fontSize-sm'>",
menuItems,
"</font>",
comment,
footerSection
);
}
Expand Down Expand Up @@ -499,7 +532,7 @@ public void ShowForPlayer( IPlayer player )

lock (optionsLock)
{
options.OfType<OptionsBase.MenuOptionBase>().ToList().ForEach(option => option.ResumeTextAnimation());
options.OfType<MenuOptionBase>().ToList().ForEach(option => option.ResumeTextAnimation());
}
}
}
Expand Down Expand Up @@ -556,7 +589,7 @@ public void HideForPlayer( IPlayer player )

lock (optionsLock)
{
options.OfType<OptionsBase.MenuOptionBase>().ToList().ForEach(option => option.PauseTextAnimation());
options.OfType<MenuOptionBase>().ToList().ForEach(option => option.PauseTextAnimation());
}
}
}
Expand Down Expand Up @@ -588,7 +621,7 @@ public void AddOption( IMenuOption option )
// {
// submenuOption.SubmenuRequested += OnSubmenuRequested;
// }
if (option is OptionsBase.MenuOptionBase baseOption)
if (option is MenuOptionBase baseOption)
{
baseOption.Menu = this;
}
Expand Down Expand Up @@ -667,17 +700,20 @@ public int GetCurrentOptionIndex( IPlayer player )
// return selectedDisplayLine.TryGetValue(player, out var line) ? line : -1;
// }

private static void SetFreezeState( IPlayer player, bool freeze )
private void SetFreezeState( IPlayer player, bool freeze )
{
if (!player.IsValid || player.IsFakeClient || !(player.PlayerPawn?.IsValid ?? false))
{
return;
}

var moveType = freeze ? MoveType_t.MOVETYPE_NONE : MoveType_t.MOVETYPE_WALK;
player.PlayerPawn.MoveType = moveType;
player.PlayerPawn.ActualMoveType = moveType;
player.PlayerPawn.MoveTypeUpdated();
core.Scheduler.NextTick(() =>
{
var moveType = freeze ? MoveType_t.MOVETYPE_NONE : MoveType_t.MOVETYPE_WALK;
player.PlayerPawn.MoveType = moveType;
player.PlayerPawn.ActualMoveType = moveType;
player.PlayerPawn.MoveTypeUpdated();
});
}

// private ValueTask OnOptionClick( object? sender, MenuOptionClickEventArgs args )
Expand Down
60 changes: 60 additions & 0 deletions managed/src/SwiftlyS2.Core/Modules/Menus/MenuInputClaim.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
namespace SwiftlyS2.Core.Menus;

[Flags]
internal enum MenuInputClaim
{
/// <summary>
/// No input claimed.
/// </summary>
None = 0,

/// <summary>
/// Claims the Exit key (A in WASD mode).
/// </summary>
Exit = 1 << 0,

/// <summary>
/// Claims the Use/Select key (D in WASD mode).
/// </summary>
Use = 1 << 1
}

internal readonly record struct MenuInputClaimInfo
{
/// <summary>
/// The input types being claimed.
/// </summary>
public MenuInputClaim Claims { get; init; }

/// <summary>
/// The display label for the Exit key when claimed.
/// Shown in the menu footer instead of "Exit".
/// </summary>
public string? ExitLabel { get; init; }

/// <summary>
/// The display label for the Use key when claimed.
/// Shown in the menu footer instead of "Use".
/// </summary>
public string? UseLabel { get; init; }

/// <summary>
/// Returns true if any input is claimed.
/// </summary>
public bool HasClaims => Claims != MenuInputClaim.None;

/// <summary>
/// Returns true if the Exit input is claimed.
/// </summary>
public bool ClaimsExit => (Claims & MenuInputClaim.Exit) != 0;

/// <summary>
/// Returns true if the Use input is claimed.
/// </summary>
public bool ClaimsUse => (Claims & MenuInputClaim.Use) != 0;

/// <summary>
/// Creates an empty claim info with no claims.
/// </summary>
public static MenuInputClaimInfo Empty => new() { Claims = MenuInputClaim.None };
}
82 changes: 74 additions & 8 deletions managed/src/SwiftlyS2.Core/Modules/Menus/MenuManagerAPI.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
using System.Collections.Concurrent;
using SwiftlyS2.Shared;
using SwiftlyS2.Core.Natives;
using SwiftlyS2.Core.Menus.OptionsBase;
using SwiftlyS2.Shared.Menus;
using SwiftlyS2.Shared.Events;
using SwiftlyS2.Shared.Sounds;
Expand Down Expand Up @@ -113,9 +114,13 @@ internal void OnClientKeyStateChanged( IOnClientKeyStateChangedEvent @event )
}

var player = Core.PlayerManager.GetPlayer(@event.PlayerId);
var menu = GetCurrentMenu(player);
if (player == null || !player.IsValid || player.IsFakeClient || player.IsFakeClient || !@event.Pressed)
{
return;
}

if (menu == null || !player.IsValid || player.IsFakeClient || !@event.Pressed)
var menu = GetCurrentMenu(player);
if (menu == null)
{
return;
}
Expand Down Expand Up @@ -151,7 +156,22 @@ internal void OnClientKeyStateChanged( IOnClientKeyStateChangedEvent @event )
}
else if (exitKey.HasFlag(@event.Key.ToKeyBind()))
{
if (!menu.Configuration.DisableExit)
var option = menu.GetCurrentOption(player);
var optionBase = option as MenuOptionBase;
var claimInfo = optionBase?.InputClaimInfo ?? MenuInputClaimInfo.Empty;

if (claimInfo.ClaimsExit && optionBase != null)
{
optionBase.OnClaimedExit(player);

if (menu.Configuration.PlaySound && option!.PlaySound)
{
useSound.Recipients.AddRecipient(@event.PlayerId);
_ = useSound.Emit();
useSound.Recipients.RemoveRecipient(@event.PlayerId);
}
}
else if (!menu.Configuration.DisableExit)
{
CloseMenuForPlayerInternal(player, menu, true);

Expand All @@ -166,7 +186,21 @@ internal void OnClientKeyStateChanged( IOnClientKeyStateChangedEvent @event )
else if (useKey.HasFlag(@event.Key.ToKeyBind()))
{
var option = menu.GetCurrentOption(player);
if (option != null && option.Enabled && option.GetEnabled(player) && option.IsClickTaskCompleted(player))
var optionBase = option as MenuOptionBase;
var claimInfo = optionBase?.InputClaimInfo ?? MenuInputClaimInfo.Empty;

if (claimInfo.ClaimsUse && optionBase != null)
{
optionBase.OnClaimedUse(player);

if (menu.Configuration.PlaySound && option!.PlaySound)
{
useSound.Recipients.AddRecipient(@event.PlayerId);
_ = useSound.Emit();
useSound.Recipients.RemoveRecipient(@event.PlayerId);
}
}
else if (option != null && option.Enabled && option.GetEnabled(player) && option.IsClickTaskCompleted(player))
{
_ = Task.Run(async () => await option.OnClickAsync(player));

Expand Down Expand Up @@ -205,7 +239,22 @@ internal void OnClientKeyStateChanged( IOnClientKeyStateChangedEvent @event )
}
else if (KeyBind.A.HasFlag(@event.Key.ToKeyBind()))
{
if (!menu.Configuration.DisableExit)
var option = menu.GetCurrentOption(player);
var optionBase = option as MenuOptionBase;
var claimInfo = optionBase?.InputClaimInfo ?? MenuInputClaimInfo.Empty;

if (claimInfo.ClaimsExit && optionBase != null)
{
optionBase.OnClaimedExit(player);

if (menu.Configuration.PlaySound && option!.PlaySound)
{
useSound.Recipients.AddRecipient(@event.PlayerId);
_ = useSound.Emit();
useSound.Recipients.RemoveRecipient(@event.PlayerId);
}
}
else if (!menu.Configuration.DisableExit)
{
CloseMenuForPlayerInternal(player, menu, true);

Expand All @@ -220,7 +269,21 @@ internal void OnClientKeyStateChanged( IOnClientKeyStateChangedEvent @event )
else if (KeyBind.D.HasFlag(@event.Key.ToKeyBind()))
{
var option = menu.GetCurrentOption(player);
if (option != null && option.Enabled && option.GetEnabled(player) && option.IsClickTaskCompleted(player))
var optionBase = option as MenuOptionBase;
var claimInfo = optionBase?.InputClaimInfo ?? MenuInputClaimInfo.Empty;

if (claimInfo.ClaimsUse && optionBase != null)
{
optionBase.OnClaimedUse(player);

if (menu.Configuration.PlaySound && option!.PlaySound)
{
useSound.Recipients.AddRecipient(@event.PlayerId);
_ = useSound.Emit();
useSound.Recipients.RemoveRecipient(@event.PlayerId);
}
}
else if (option != null && option.Enabled && option.GetEnabled(player) && option.IsClickTaskCompleted(player))
{
_ = Task.Run(async () => await option.OnClickAsync(player));

Expand Down Expand Up @@ -376,8 +439,11 @@ public void CloseAllMenus()
while (currentMenu != null)
{
var player = Core.PlayerManager.GetPlayer(kvp.Key);
currentMenu.HideForPlayer(player);
MenuClosed?.Invoke(this, new MenuManagerEventArgs { Player = player, Menu = currentMenu });
if (player?.IsValid ?? false)
{
currentMenu.HideForPlayer(player);
MenuClosed?.Invoke(this, new MenuManagerEventArgs { Player = player, Menu = currentMenu });
}
currentMenu = currentMenu.Parent.ParentMenu;
}
_ = openMenus.TryRemove(kvp.Key, out _);
Expand Down
Loading
Loading