mirror of
https://github.com/daffyyyy/CS2-SimpleAdmin.git
synced 2026-11-07 20:17:04 +01:00
Migrate menus and votes to Panorama UI Kit
Replace MenuManagerCS2 with Panorama UI Kit for the admin menus and css_vote. Layout names (menu, vote, banner, toast) are configurable under MenuConfig and preloaded on startup; MenuType is removed and ConfigVersion bumped to 26. - Drop MenuManagerApi.dll and the old chat menu classes - Reference PanoramaUiKit.Shared.dll, bump CounterStrikeSharp to 1.0.376 - Add .editorconfig and CODING_CONVENTIONS.md, apply them codebase-wide - Remove the CS2-SimpleAdmin-docs site - Rewrite README for the fork
This commit is contained in:
parent
03a454b1b5
commit
460d8b2b85
112 changed files with 5559 additions and 36371 deletions
|
|
@ -1,17 +1,29 @@
|
|||
using CounterStrikeSharp.API.Core;
|
||||
using CounterStrikeSharp.API.Core.Translations;
|
||||
using CounterStrikeSharp.API.Modules.Admin;
|
||||
using CounterStrikeSharp.API.Modules.Entities;
|
||||
using Microsoft.Extensions.Localization;
|
||||
using PanoramaUiKit.Shared.Api;
|
||||
using PanoramaUiKit.Shared.Menus;
|
||||
|
||||
namespace CS2_SimpleAdmin.Menus;
|
||||
|
||||
/// <summary>
|
||||
/// Describes a menu and renders it through the Panorama UI Kit.
|
||||
/// Sub-menus are pushed on top of their parent, the kit draws the back button.
|
||||
/// </summary>
|
||||
public class MenuBuilder
|
||||
{
|
||||
/// <summary>
|
||||
/// Bumped every time a menu is opened for a player, so an option can tell whether its action opened another one.
|
||||
/// </summary>
|
||||
private static readonly Dictionary<ulong, int> OpenCounters = [];
|
||||
|
||||
private readonly string _title;
|
||||
private readonly CCSPlayerController? _player;
|
||||
private readonly IStringLocalizer? _localizer;
|
||||
private readonly List<MenuOption> _options = [];
|
||||
private MenuBuilder? _parentMenu;
|
||||
private Action<CCSPlayerController>? _backAction;
|
||||
private Action<CCSPlayerController>? _resetAction;
|
||||
private bool _isSubMenu;
|
||||
|
||||
/// <summary>
|
||||
/// Constructor for player-localized menu with translation key
|
||||
|
|
@ -24,7 +36,7 @@ public class MenuBuilder
|
|||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructor for static title (backward compatibility)
|
||||
/// Constructor for static title
|
||||
/// </summary>
|
||||
public MenuBuilder(string title)
|
||||
{
|
||||
|
|
@ -33,21 +45,6 @@ public class MenuBuilder
|
|||
_localizer = null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the localized title for the player
|
||||
/// </summary>
|
||||
private string GetLocalizedTitle()
|
||||
{
|
||||
if (_player != null && _localizer != null)
|
||||
{
|
||||
using (new WithTemporaryCulture(_player.GetLanguage()))
|
||||
{
|
||||
return _localizer[_title];
|
||||
}
|
||||
}
|
||||
return _title;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds a menu option with an action.
|
||||
/// </summary>
|
||||
|
|
@ -56,7 +53,9 @@ public class MenuBuilder
|
|||
/// <param name="disabled">Whether the option is disabled</param>
|
||||
/// <param name="permission">Required permission</param>
|
||||
/// <param name="isTranslationKey">If true, name is a translation key to be localized</param>
|
||||
public MenuBuilder AddOption(string name, Action<CCSPlayerController> action, bool disabled = false, string? permission = null, bool isTranslationKey = false)
|
||||
/// <param name="keepOpen">If true, the menu stays open after the action</param>
|
||||
public MenuBuilder AddOption(string name, Action<CCSPlayerController> action, bool disabled = false, string? permission = null,
|
||||
bool isTranslationKey = false, bool keepOpen = false)
|
||||
{
|
||||
_options.Add(new MenuOption
|
||||
{
|
||||
|
|
@ -64,46 +63,18 @@ public class MenuBuilder
|
|||
Action = action,
|
||||
Disabled = disabled,
|
||||
Permission = permission,
|
||||
IsTranslationKey = isTranslationKey
|
||||
IsTranslationKey = isTranslationKey,
|
||||
KeepOpen = keepOpen
|
||||
});
|
||||
return this;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the localized name for a menu option
|
||||
/// </summary>
|
||||
private string GetLocalizedOptionName(MenuOption option)
|
||||
{
|
||||
if (option.IsTranslationKey && _player != null && _localizer != null)
|
||||
{
|
||||
using (new WithTemporaryCulture(_player.GetLanguage()))
|
||||
{
|
||||
return _localizer[option.Name];
|
||||
}
|
||||
}
|
||||
return option.Name;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds a menu option that opens a submenu.
|
||||
/// </summary>
|
||||
public MenuBuilder AddSubMenu(string name, Func<MenuBuilder> subMenuFactory, bool disabled = false, string? permission = null)
|
||||
{
|
||||
_options.Add(new MenuOption
|
||||
{
|
||||
Name = name,
|
||||
Action = player =>
|
||||
{
|
||||
var subMenu = subMenuFactory();
|
||||
subMenu.SetParent(this);
|
||||
// Automatically add back button to submenu
|
||||
subMenu.WithBackButton();
|
||||
subMenu.OpenMenu(player);
|
||||
},
|
||||
Disabled = disabled,
|
||||
Permission = permission
|
||||
});
|
||||
return this;
|
||||
return AddSubMenu(name, _ => subMenuFactory(), disabled, permission);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
@ -114,14 +85,7 @@ public class MenuBuilder
|
|||
_options.Add(new MenuOption
|
||||
{
|
||||
Name = name,
|
||||
Action = player =>
|
||||
{
|
||||
var subMenu = subMenuFactory(player);
|
||||
subMenu.SetParent(this);
|
||||
// Automatically add back button to submenu
|
||||
subMenu.WithBackButton();
|
||||
subMenu.OpenMenu(player);
|
||||
},
|
||||
SubMenuFactory = subMenuFactory,
|
||||
Disabled = disabled,
|
||||
Permission = permission
|
||||
});
|
||||
|
|
@ -129,66 +93,50 @@ public class MenuBuilder
|
|||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds a back button to return to the previous menu.
|
||||
/// Opens this menu on top of the current one, with a back button.
|
||||
/// </summary>
|
||||
public MenuBuilder WithBackButton()
|
||||
{
|
||||
if (_parentMenu != null)
|
||||
{
|
||||
_backAction = player => _parentMenu.OpenMenu(player);
|
||||
|
||||
// Add back option at the end of menu
|
||||
// AddOption(backButtonText, _backAction);
|
||||
}
|
||||
_isSubMenu = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the parent menu (for navigation).
|
||||
/// </summary>
|
||||
private void SetParent(MenuBuilder parent)
|
||||
{
|
||||
_parentMenu = parent;
|
||||
_backAction = player => _parentMenu.OpenMenu(player);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Opens the menu for a player.
|
||||
/// </summary>
|
||||
/// <param name="player">The player to open the menu for.</param>
|
||||
public void OpenMenu(CCSPlayerController player)
|
||||
{
|
||||
if (!player.IsValid) return;
|
||||
|
||||
// Get localized title
|
||||
var localizedTitle = GetLocalizedTitle();
|
||||
|
||||
// Use MenuManager dependency
|
||||
var menu = Helper.CreateMenu(localizedTitle, _backAction);
|
||||
if (menu == null) return;
|
||||
|
||||
foreach (var option in _options)
|
||||
if (!player.IsValid)
|
||||
{
|
||||
// Check permissions if required
|
||||
if (!string.IsNullOrEmpty(option.Permission))
|
||||
{
|
||||
var steamId = new CounterStrikeSharp.API.Modules.Entities.SteamID(player.SteamID);
|
||||
if (!CounterStrikeSharp.API.Modules.Admin.AdminManager.PlayerHasPermissions(steamId, option.Permission))
|
||||
{
|
||||
continue; // Skip option if player doesn't have permission
|
||||
}
|
||||
}
|
||||
|
||||
// Get localized option name
|
||||
var localizedName = GetLocalizedOptionName(option);
|
||||
|
||||
menu.AddMenuOption(localizedName, (menuPlayer, menuOption) =>
|
||||
{
|
||||
option.Action?.Invoke(menuPlayer);
|
||||
}, option.Disabled);
|
||||
return;
|
||||
}
|
||||
|
||||
menu.Open(player);
|
||||
IPanoramaUiKit? kit = UiKit.Instance;
|
||||
if (kit == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
MenuOptions menu = Build(player);
|
||||
BumpOpenCounter(player);
|
||||
|
||||
if (_isSubMenu)
|
||||
{
|
||||
kit.Menus.Push(player, menu);
|
||||
}
|
||||
else
|
||||
{
|
||||
kit.Menus.Open(player, menu);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Closes any SimpleAdmin menu open for the player.
|
||||
/// </summary>
|
||||
public static void CloseMenu(CCSPlayerController player)
|
||||
{
|
||||
UiKit.Instance?.Menus.Close(player, UiKit.MenuLayout);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
@ -201,26 +149,101 @@ public class MenuBuilder
|
|||
return this;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets a reset action for the menu.
|
||||
/// </summary>
|
||||
/// <param name="resetAction">The action to execute on reset.</param>
|
||||
/// <returns>This MenuBuilder instance for chaining.</returns>
|
||||
public MenuBuilder WithResetAction(Action<CCSPlayerController> resetAction)
|
||||
private MenuOptions Build(CCSPlayerController player)
|
||||
{
|
||||
_resetAction = resetAction;
|
||||
return this;
|
||||
List<MenuEntry> entries = [];
|
||||
SteamID steamId = new SteamID(player.SteamID);
|
||||
|
||||
foreach (MenuOption option in _options)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(option.Permission) && !AdminManager.PlayerHasPermissions(steamId, option.Permission))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
string label = GetLocalizedOptionName(option);
|
||||
MenuEntry entry;
|
||||
|
||||
if (option.SubMenuFactory != null)
|
||||
{
|
||||
Func<CCSPlayerController, MenuBuilder> subMenuFactory = option.SubMenuFactory;
|
||||
entry = MenuEntry.Open(label, menuPlayer =>
|
||||
{
|
||||
BumpOpenCounter(menuPlayer);
|
||||
return subMenuFactory(menuPlayer).Build(menuPlayer);
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
entry = MenuEntry.Button(label, menuPlayer => RunOption(option, menuPlayer));
|
||||
}
|
||||
|
||||
if (option.Disabled)
|
||||
{
|
||||
entry = entry with { Disabled = true };
|
||||
}
|
||||
|
||||
entries.Add(entry);
|
||||
}
|
||||
|
||||
return new MenuOptions
|
||||
{
|
||||
Layout = UiKit.MenuLayout,
|
||||
Title = GetLocalizedTitle(),
|
||||
Entries = entries
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Sets a custom back action for the menu.
|
||||
/// Runs the option, then closes the menu unless the option keeps it open or its action opened another menu.
|
||||
/// </summary>
|
||||
/// <param name="backAction">The action to execute when going back (nullable).</param>
|
||||
/// <returns>This MenuBuilder instance for chaining.</returns>
|
||||
public MenuBuilder WithBackAction(Action<CCSPlayerController>? backAction)
|
||||
private static void RunOption(MenuOption option, CCSPlayerController player)
|
||||
{
|
||||
_backAction = backAction;
|
||||
return this;
|
||||
int counterBefore = GetOpenCounter(player);
|
||||
|
||||
option.Action?.Invoke(player);
|
||||
|
||||
if (!option.KeepOpen && player.IsValid && GetOpenCounter(player) == counterBefore)
|
||||
{
|
||||
CloseMenu(player);
|
||||
}
|
||||
}
|
||||
|
||||
private static int GetOpenCounter(CCSPlayerController player)
|
||||
{
|
||||
OpenCounters.TryGetValue(player.SteamID, out int counter);
|
||||
return counter;
|
||||
}
|
||||
|
||||
private static void BumpOpenCounter(CCSPlayerController player)
|
||||
{
|
||||
OpenCounters[player.SteamID] = GetOpenCounter(player) + 1;
|
||||
}
|
||||
|
||||
private string GetLocalizedTitle()
|
||||
{
|
||||
if (_player == null || _localizer == null)
|
||||
{
|
||||
return _title;
|
||||
}
|
||||
|
||||
using (new WithTemporaryCulture(_player.GetLanguage()))
|
||||
{
|
||||
return _localizer[_title];
|
||||
}
|
||||
}
|
||||
|
||||
private string GetLocalizedOptionName(MenuOption option)
|
||||
{
|
||||
if (!option.IsTranslationKey || _player == null || _localizer == null)
|
||||
{
|
||||
return option.Name;
|
||||
}
|
||||
|
||||
using (new WithTemporaryCulture(_player.GetLanguage()))
|
||||
{
|
||||
return _localizer[option.Name];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -231,8 +254,9 @@ public class MenuOption
|
|||
{
|
||||
public string Name { get; set; } = string.Empty;
|
||||
public Action<CCSPlayerController>? Action { get; set; }
|
||||
public Func<CCSPlayerController, MenuBuilder>? SubMenuFactory { get; set; }
|
||||
public bool Disabled { get; set; }
|
||||
public string? Permission { get; set; }
|
||||
public bool IsTranslationKey { get; set; }
|
||||
public bool KeepOpen { get; set; }
|
||||
}
|
||||
|
||||
Loading…
Add table
Add a link
Reference in a new issue