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:
Salvatore 2026-10-21 18:51:18 +02:00
parent 03a454b1b5
commit 460d8b2b85
112 changed files with 5559 additions and 36371 deletions

View file

@ -1,75 +0,0 @@
using CounterStrikeSharp.API.Core;
using CounterStrikeSharp.API.Modules.Admin;
using CounterStrikeSharp.API.Modules.Entities;
using CounterStrikeSharp.API.Modules.Menu;
namespace CS2_SimpleAdmin.Menus;
public static class AdminMenu
{
public static void OpenMenu(CCSPlayerController admin)
{
MenuManager.Instance.OpenMainMenu(admin);
}
public static IMenu? CreateMenu(string title, Action<CCSPlayerController>? backAction = null)
{
return Helper.CreateMenu(title, backAction);
// return CS2_SimpleAdmin.Instance.Config.UseChatMenu ? new ChatMenu(title) : new CenterHtmlMenu(title, CS2_SimpleAdmin.Instance);
}
public static void OpenMenu(CCSPlayerController player, IMenu menu)
{
menu.Open(player);
// switch (menu)
// {
// case CenterHtmlMenu centerHtmlMenu:
// MenuManager.OpenCenterHtmlMenu(CS2_SimpleAdmin.Instance, player, centerHtmlMenu);
// break;
// case ChatMenu chatMenu:
// MenuManager.OpenChatMenu(player, chatMenu);
// break;
// }
}
// public static void OpenMenu(CCSPlayerController admin)
// {
// if (admin.IsValid == false)
// return;
//
// var localizer = CS2_SimpleAdmin._localizer;
// if (AdminManager.PlayerHasPermissions(new SteamID(admin.SteamID), "@css/generic") == false)
// {
// admin.PrintToChat(localizer?["sa_prefix"] ??
// "[SimpleAdmin] " +
// (localizer?["sa_no_permission"] ?? "You do not have permissions to use this command")
// );
// return;
// }
//
// var menu = CreateMenu(localizer?["sa_title"] ?? "SimpleAdmin");
// List<ChatMenuOptionData> options =
// [
// new(localizer?["sa_menu_players_manage"] ?? "Players Manage", () => ManagePlayersMenu.OpenMenu(admin)),
// new(localizer?["sa_menu_server_manage"] ?? "Server Manage", () => ManageServerMenu.OpenMenu(admin)),
// new(localizer?["sa_menu_fun_commands"] ?? "Fun Commands", () => FunActionsMenu.OpenMenu(admin)),
// ];
//
// var customCommands = CS2_SimpleAdmin.Instance.Config.CustomServerCommands;
// if (customCommands.Count > 0)
// {
// options.Add(new ChatMenuOptionData(localizer?["sa_menu_custom_commands"] ?? "Custom Commands", () => CustomCommandsMenu.OpenMenu(admin)));
// }
//
// if (AdminManager.PlayerHasPermissions(new SteamID(admin.SteamID), "@css/root"))
// options.Add(new ChatMenuOptionData(localizer?["sa_menu_admins_manage"] ?? "Admins Manage", () => ManageAdminsMenu.OpenMenu(admin)));
//
// foreach (var menuOptionData in options)
// {
// var menuName = menuOptionData.Name;
// menu?.AddMenuOption(menuName, (_, _) => { menuOptionData.Action.Invoke(); }, menuOptionData.Disabled);
// }
//
// if (menu != null) OpenMenu(admin, menu);
// }
}

File diff suppressed because it is too large Load diff

View file

@ -1,8 +0,0 @@
namespace CS2_SimpleAdmin.Menus;
public class ChatMenuOptionData(string name, Action action, bool disabled = false)
{
public readonly string Name = name;
public readonly Action Action = action;
public readonly bool Disabled = disabled;
}

View file

@ -1,51 +0,0 @@
using CounterStrikeSharp.API;
using CounterStrikeSharp.API.Core;
using CounterStrikeSharp.API.Modules.Admin;
using CounterStrikeSharp.API.Modules.Entities;
namespace CS2_SimpleAdmin.Menus;
public static class CustomCommandsMenu
{
public static void OpenMenu(CCSPlayerController admin)
{
if (!admin.IsValid)
return;
var localizer = CS2_SimpleAdmin._localizer;
if (!AdminManager.PlayerHasPermissions(new SteamID(admin.SteamID), "@css/generic"))
{
admin.PrintToChat(localizer?["sa_prefix"] ??
"[SimpleAdmin] " +
(localizer?["sa_no_permission"] ?? "You do not have permissions to use this command")
);
return;
}
var menu = AdminMenu.CreateMenu(localizer?["sa_menu_custom_commands"] ?? "Custom Commands");
List<ChatMenuOptionData> options = [];
var customCommands = CS2_SimpleAdmin.Instance.Config.CustomServerCommands;
options.AddRange(from customCommand in customCommands
where !string.IsNullOrEmpty(customCommand.DisplayName) && !string.IsNullOrEmpty(customCommand.Command)
let hasRights = AdminManager.PlayerHasPermissions(new SteamID(admin.SteamID), customCommand.Flag)
where hasRights
select new ChatMenuOptionData(customCommand.DisplayName, () =>
{
Helper.TryLogCommandOnDiscord(admin, customCommand.Command);
if (customCommand.ExecuteOnClient)
admin.ExecuteClientCommandFromServer(customCommand.Command);
else
Server.ExecuteCommand(customCommand.Command);
}));
foreach (var menuOptionData in options)
{
var menuName = menuOptionData.Name;
menu?.AddMenuOption(menuName, (_, _) => { menuOptionData.Action(); }, menuOptionData.Disabled);
}
if (menu != null) AdminMenu.OpenMenu(admin, menu);
}
}

View file

@ -1,46 +0,0 @@
using CounterStrikeSharp.API.Core;
using CS2_SimpleAdmin.Models;
namespace CS2_SimpleAdmin.Menus;
public static class DurationMenu
{
public static void OpenMenu(CCSPlayerController admin, string menuName, CCSPlayerController player, Action<CCSPlayerController, CCSPlayerController, int> onSelectAction)
{
var menu = AdminMenu.CreateMenu(menuName);
if (menu == null)
return;
var durations = CS2_SimpleAdmin.Instance.Config.MenuConfigs.Durations;
// Capture admin and player to avoid closure issues
var capturedAdmin = admin;
var capturedPlayer = player;
var capturedAction = onSelectAction;
foreach (var durationItem in durations)
{
var duration = durationItem.Duration; // Capture in local variable
var name = durationItem.Name;
menu.AddMenuOption(name, (controller, option) =>
{
capturedAction(capturedAdmin, capturedPlayer, duration);
});
}
AdminMenu.OpenMenu(admin, menu);
}
public static void OpenMenu(CCSPlayerController admin, string menuName, DisconnectedPlayer player, Action<CCSPlayerController, DisconnectedPlayer, int> onSelectAction)
{
var menu = AdminMenu.CreateMenu(menuName);
foreach (var durationItem in CS2_SimpleAdmin.Instance.Config.MenuConfigs.Durations)
{
menu?.AddMenuOption(durationItem.Name, (_, _) => { onSelectAction(admin, player, durationItem.Duration); });
}
if (menu != null) AdminMenu.OpenMenu(admin, menu);
}
}

View file

@ -264,4 +264,4 @@
// {
// CS2_SimpleAdmin.SetMoney(admin, player, money);
// }
// }
// }

View file

@ -1,72 +0,0 @@
using CounterStrikeSharp.API.Core;
using CounterStrikeSharp.API.Modules.Admin;
using CounterStrikeSharp.API.Modules.Entities;
namespace CS2_SimpleAdmin.Menus;
public static class ManageAdminsMenu
{
public static void OpenMenu(CCSPlayerController admin)
{
if (!admin.IsValid)
return;
var localizer = CS2_SimpleAdmin._localizer;
if (!AdminManager.PlayerHasPermissions(new SteamID(admin.SteamID), "@css/root"))
{
admin.PrintToChat(localizer?["sa_prefix"] ??
"[SimpleAdmin] " +
(localizer?["sa_no_permission"] ?? "You do not have permissions to use this command")
);
return;
}
var menu = AdminMenu.CreateMenu(localizer?["sa_menu_admins_manage"] ?? "Admins Manage");
List<ChatMenuOptionData> options =
[
new(localizer?["sa_admin_add"] ?? "Add Admin",
() => PlayersMenu.OpenRealPlayersMenu(admin, localizer?["sa_admin_add"] ?? "Add Admin", AddAdminMenu)),
new(localizer?["sa_admin_remove"] ?? "Remove Admin",
() => PlayersMenu.OpenAdminPlayersMenu(admin, localizer?["sa_admin_remove"] ?? "Remove Admin", RemoveAdmin,
player => player != admin && admin.CanTarget(player))),
new(localizer?["sa_admin_reload"] ?? "Reload Admins", () => ReloadAdmins(admin))
];
foreach (var menuOptionData in options)
{
var menuName = menuOptionData.Name;
menu?.AddMenuOption(menuName, (_, _) => { menuOptionData.Action.Invoke(); }, menuOptionData.Disabled);
}
if (menu != null) AdminMenu.OpenMenu(admin, menu);
}
private static void AddAdminMenu(CCSPlayerController admin, CCSPlayerController player)
{
var menu = AdminMenu.CreateMenu($"{CS2_SimpleAdmin._localizer?["sa_admin_add"] ?? "Add Admin"}: {player.PlayerName}");
foreach (var adminFlag in CS2_SimpleAdmin.Instance.Config.MenuConfigs.AdminFlags)
{
var disabled = AdminManager.PlayerHasPermissions(player, adminFlag.Flag);
menu?.AddMenuOption(adminFlag.Name, (_, _) => { AddAdmin(admin, player, adminFlag.Flag); }, disabled);
}
if (menu != null) AdminMenu.OpenMenu(admin, menu);
}
private static void AddAdmin(CCSPlayerController admin, CCSPlayerController player, string flag)
{
// TODO: Change default immunity?
CS2_SimpleAdmin.AddAdmin(admin, player.SteamID.ToString(), player.PlayerName, flag, 10);
}
private static void RemoveAdmin(CCSPlayerController admin, CCSPlayerController player)
{
CS2_SimpleAdmin.Instance.RemoveAdmin(admin, player.SteamID.ToString());
}
private static void ReloadAdmins(CCSPlayerController admin)
{
CS2_SimpleAdmin.Instance.ReloadAdmins(admin);
}
}

View file

@ -1,325 +0,0 @@
using CounterStrikeSharp.API.Core;
using CounterStrikeSharp.API.Modules.Admin;
using CounterStrikeSharp.API.Modules.Entities;
using CounterStrikeSharp.API.Modules.Utils;
using CS2_SimpleAdminApi;
namespace CS2_SimpleAdmin.Menus;
public static class ManagePlayersMenu
{
public static void OpenMenu(CCSPlayerController admin)
{
if (!admin.IsValid)
return;
var localizer = CS2_SimpleAdmin._localizer;
if (!AdminManager.PlayerHasPermissions(new SteamID(admin.SteamID), "@css/generic"))
{
admin.PrintToChat(localizer?["sa_prefix"] ??
"[SimpleAdmin] " +
(localizer?["sa_no_permission"] ?? "You do not have permissions to use this command")
);
return;
}
var menu = AdminMenu.CreateMenu(localizer?["sa_menu_players_manage"] ?? "Manage Players");
List<ChatMenuOptionData> options = [];
// permissions
var hasSlay = AdminManager.CommandIsOverriden("css_slay") ? AdminManager.PlayerHasPermissions(new SteamID(admin.SteamID), AdminManager.GetPermissionOverrides("css_slay")) : AdminManager.PlayerHasPermissions(new SteamID(admin.SteamID), "@css/slay");
var hasKick = AdminManager.CommandIsOverriden("css_kick") ? AdminManager.PlayerHasPermissions(new SteamID(admin.SteamID), AdminManager.GetPermissionOverrides("css_kick")) : AdminManager.PlayerHasPermissions(new SteamID(admin.SteamID), "@css/kick");
var hasBan = AdminManager.CommandIsOverriden("css_ban") ? AdminManager.PlayerHasPermissions(new SteamID(admin.SteamID), AdminManager.GetPermissionOverrides("css_ban")) : AdminManager.PlayerHasPermissions(new SteamID(admin.SteamID), "@css/ban");
var hasChat = AdminManager.CommandIsOverriden("css_gag") ? AdminManager.PlayerHasPermissions(new SteamID(admin.SteamID), AdminManager.GetPermissionOverrides("css_gag")) : AdminManager.PlayerHasPermissions(new SteamID(admin.SteamID), "@css/chat");
// TODO: Localize options
// options added in order
if (hasSlay)
{
options.Add(new ChatMenuOptionData(localizer?["sa_slap"] ?? "Slap", () => PlayersMenu.OpenMenu(admin, localizer?["sa_slap"] ?? "Slap", SlapMenu)));
options.Add(new ChatMenuOptionData(localizer?["sa_slay"] ?? "Slay", () => PlayersMenu.OpenMenu(admin, localizer?["sa_slay"] ?? "Slay", Slay)));
}
if (hasKick)
{
options.Add(new ChatMenuOptionData(localizer?["sa_kick"] ?? "Kick", () => PlayersMenu.OpenMenu(admin, localizer?["sa_kick"] ?? "Kick", KickMenu)));
}
if (AdminManager.CommandIsOverriden("css_warn")
? AdminManager.PlayerHasPermissions(new SteamID(admin.SteamID), AdminManager.GetPermissionOverrides("css_warn"))
: AdminManager.PlayerHasPermissions(new SteamID(admin.SteamID), "@css/kick"))
options.Add(new ChatMenuOptionData(localizer?["sa_warn"] ?? "Warn", () => PlayersMenu.OpenRealPlayersMenu(admin, localizer?["sa_warn"] ?? "Warn", (a, p) => DurationMenu.OpenMenu(a, $"{localizer?["sa_warn"] ?? "Warn"}: {p.PlayerName}", p, WarnMenu))));
if (hasBan)
options.Add(new ChatMenuOptionData(localizer?["sa_ban"] ?? "Ban", () =>
PlayersMenu.OpenRealPlayersMenu(admin, localizer?["sa_ban"] ?? "Ban", (a, p) =>
DurationMenu.OpenMenu(a, $"{localizer?["sa_ban"] ?? "Ban"}: {p.PlayerName}", p, BanMenu))));
if (hasChat)
{
if (AdminManager.CommandIsOverriden("css_gag")
? AdminManager.PlayerHasPermissions(new SteamID(admin.SteamID), AdminManager.GetPermissionOverrides("css_gag"))
: AdminManager.PlayerHasPermissions(new SteamID(admin.SteamID), "@css/chat"))
options.Add(new ChatMenuOptionData(localizer?["sa_gag"] ?? "Gag", () => PlayersMenu.OpenRealPlayersMenu(admin, localizer?["sa_gag"] ?? "Gag", (a, p) => DurationMenu.OpenMenu(a, $"{localizer?["sa_gag"] ?? "Gag"}: {p.PlayerName}", p, GagMenu))));
if (AdminManager.CommandIsOverriden("css_mute")
? AdminManager.PlayerHasPermissions(new SteamID(admin.SteamID), AdminManager.GetPermissionOverrides("css_mute"))
: AdminManager.PlayerHasPermissions(new SteamID(admin.SteamID), "@css/chat"))
options.Add(new ChatMenuOptionData(localizer?["sa_mute"] ?? "Mute", () => PlayersMenu.OpenRealPlayersMenu(admin, localizer?["sa_mute"] ?? "Mute", (a, p) => DurationMenu.OpenMenu(a, $"{localizer?["sa_mute"] ?? "Mute"}: {p.PlayerName}", p, MuteMenu))));
if (AdminManager.CommandIsOverriden("css_silence")
? AdminManager.PlayerHasPermissions(new SteamID(admin.SteamID), AdminManager.GetPermissionOverrides("css_silence"))
: AdminManager.PlayerHasPermissions(new SteamID(admin.SteamID), "@css/chat"))
options.Add(new ChatMenuOptionData(localizer?["sa_silence"] ?? "Silence", () => PlayersMenu.OpenRealPlayersMenu(admin, localizer?["sa_silence"] ?? "Silence", (a, p) => DurationMenu.OpenMenu(a, $"{localizer?["sa_silence"] ?? "Silence"}: {p.PlayerName}", p, SilenceMenu))));
}
if (AdminManager.CommandIsOverriden("css_team")
? AdminManager.PlayerHasPermissions(new SteamID(admin.SteamID), AdminManager.GetPermissionOverrides("css_team"))
: AdminManager.PlayerHasPermissions(new SteamID(admin.SteamID), "@css/kick"))
options.Add(new ChatMenuOptionData(localizer?["sa_team_force"] ?? "Force Team", () => PlayersMenu.OpenMenu(admin, localizer?["sa_team_force"] ?? "Force Team", ForceTeamMenu)));
foreach (var menuOptionData in options)
{
var menuName = menuOptionData.Name;
menu?.AddMenuOption(menuName, (_, _) => { menuOptionData.Action.Invoke(); }, menuOptionData.Disabled);
}
if (menu != null) AdminMenu.OpenMenu(admin, menu);
}
private static void SlapMenu(CCSPlayerController admin, CCSPlayerController player)
{
var menu = AdminMenu.CreateMenu($"{CS2_SimpleAdmin._localizer?["sa_slap"] ?? "Slap"}: {player.PlayerName}");
List<ChatMenuOptionData> options =
[
// options added in order
new("0 hp", () => ApplySlapAndKeepMenu(admin, player, 0)),
new("1 hp", () => ApplySlapAndKeepMenu(admin, player, 1)),
new("5 hp", () => ApplySlapAndKeepMenu(admin, player, 5)),
new("10 hp", () => ApplySlapAndKeepMenu(admin, player, 10)),
new("50 hp", () => ApplySlapAndKeepMenu(admin, player, 50)),
new("100 hp", () => ApplySlapAndKeepMenu(admin, player, 100)),
];
foreach (var menuOptionData in options)
{
var menuName = menuOptionData.Name;
menu?.AddMenuOption(menuName, (_, _) => { menuOptionData.Action.Invoke(); }, menuOptionData.Disabled);
}
if (menu != null) AdminMenu.OpenMenu(admin, menu);
}
private static void ApplySlapAndKeepMenu(CCSPlayerController admin, CCSPlayerController player, int damage)
{
if (player is not { IsValid: true }) return;
CS2_SimpleAdmin.Slap(admin, player, damage);
SlapMenu(admin, player);
}
private static void Slay(CCSPlayerController admin, CCSPlayerController player)
{
if (player is not { IsValid: true }) return;
CS2_SimpleAdmin.Slay(admin, player);
}
private static void KickMenu(CCSPlayerController admin, CCSPlayerController player)
{
ReasonMenu.OpenMenu(admin, PenaltyType.Kick,
$"{CS2_SimpleAdmin._localizer?["sa_kick"] ?? "Kick"}: {player.PlayerName}", player, (_, _, reason) =>
{
if (player is { IsValid: true })
Kick(admin, player, reason);
});
// var menu = AdminMenu.CreateMenu($"{CS2_SimpleAdmin._localizer?["sa_kick"] ?? "Kick"}: {player?.PlayerName}");
//
// foreach (var option in CS2_SimpleAdmin.Instance.Config.MenuConfigs.KickReasons)
// {
// menu?.AddMenuOption(option, (_, _) =>
// {
// if (player is { IsValid: true })
// Kick(admin, player, option);
// });
// }
//
// if (menu != null) AdminMenu.OpenMenu(admin, menu);
}
private static void Kick(CCSPlayerController admin, CCSPlayerController player, string? reason)
{
if (player is not { IsValid: true }) return;
CS2_SimpleAdmin.Instance.Kick(admin, player, reason, admin.PlayerName);
}
internal static void BanMenu(CCSPlayerController admin, CCSPlayerController player, int duration)
{
ReasonMenu.OpenMenu(admin, PenaltyType.Ban,
$"{CS2_SimpleAdmin._localizer?["sa_ban"] ?? "Ban"}: {player.PlayerName}", player, (_, _, reason) =>
{
if (player is { IsValid: true })
Ban(admin, player, duration, reason);
CS2_SimpleAdmin.MenuApi?.CloseMenu(admin);
});
}
private static void Ban(CCSPlayerController admin, CCSPlayerController player, int duration, string reason)
{
if (player is not { IsValid: true }) return;
CS2_SimpleAdmin.Instance.Ban(admin, player, duration, reason, admin.PlayerName);
}
private static void WarnMenu(CCSPlayerController admin, CCSPlayerController player, int duration)
{
ReasonMenu.OpenMenu(admin, PenaltyType.Warn,
$"{CS2_SimpleAdmin._localizer?["sa_warn"] ?? "Warn"}: {player.PlayerName}", player, (_, _, reason) =>
{
if (player is { IsValid: true })
Warn(admin, player, duration, reason);
});
// var menu = AdminMenu.CreateMenu($"{CS2_SimpleAdmin._localizer?["sa_warn"] ?? "Warn"}: {player?.PlayerName}");
//
// foreach (var option in CS2_SimpleAdmin.Instance.Config.MenuConfigs.WarnReasons)
// {
// menu?.AddMenuOption(option, (_, _) =>
// {
// if (player is { IsValid: true })
// Warn(admin, player, duration, option);
// });
// }
//
// if (menu != null) AdminMenu.OpenMenu(admin, menu);
}
private static void Warn(CCSPlayerController admin, CCSPlayerController player, int duration, string reason)
{
if (player is not { IsValid: true }) return;
CS2_SimpleAdmin.Instance.Warn(admin, player, duration, reason, admin.PlayerName);
}
internal static void GagMenu(CCSPlayerController admin, CCSPlayerController player, int duration)
{
ReasonMenu.OpenMenu(admin, PenaltyType.Gag,
$"{CS2_SimpleAdmin._localizer?["sa_gag"] ?? "Gag"}: {player.PlayerName}", player, (_, _, reason) =>
{
if (player is { IsValid: true })
Gag(admin, player, duration, reason);
});
// var menu = AdminMenu.CreateMenu($"{CS2_SimpleAdmin._localizer?["sa_gag"] ?? "Gag"}: {player?.PlayerName}");
//
// foreach (var option in CS2_SimpleAdmin.Instance.Config.MenuConfigs.MuteReasons)
// {
// menu?.AddMenuOption(option, (_, _) =>
// {
// if (player is { IsValid: true })
// Gag(admin, player, duration, option);
// });
// }
//
// if (menu != null) AdminMenu.OpenMenu(admin, menu);
}
private static void Gag(CCSPlayerController admin, CCSPlayerController player, int duration, string reason)
{
if (player is not { IsValid: true }) return;
CS2_SimpleAdmin.Instance.Gag(admin, player, duration, reason);
}
internal static void MuteMenu(CCSPlayerController admin, CCSPlayerController player, int duration)
{
ReasonMenu.OpenMenu(admin, PenaltyType.Mute,
$"{CS2_SimpleAdmin._localizer?["sa_mute"] ?? "mute"}: {player.PlayerName}", player, (_, _, reason) =>
{
if (player is { IsValid: true })
Mute(admin, player, duration, reason);
});
// // TODO: Localize and make options in config?
// var menu = AdminMenu.CreateMenu($"{CS2_SimpleAdmin._localizer?["sa_mute"] ?? "Mute"}: {player?.PlayerName}");
//
// foreach (var option in CS2_SimpleAdmin.Instance.Config.MenuConfigs.MuteReasons)
// {
// menu?.AddMenuOption(option, (_, _) =>
// {
// if (player is { IsValid: true })
// Mute(admin, player, duration, option);
// });
// }
//
// if (menu != null) AdminMenu.OpenMenu(admin, menu);
}
private static void Mute(CCSPlayerController admin, CCSPlayerController player, int duration, string reason)
{
if (player is not { IsValid: true }) return;
CS2_SimpleAdmin.Instance.Mute(admin, player, duration, reason);
}
internal static void SilenceMenu(CCSPlayerController admin, CCSPlayerController player, int duration)
{
ReasonMenu.OpenMenu(admin, PenaltyType.Silence,
$"{CS2_SimpleAdmin._localizer?["sa_silence"] ?? "Silence"}: {player.PlayerName}", player, (_, _, reason) =>
{
if (player is { IsValid: true })
Silence(admin, player, duration, reason);
});
// // TODO: Localize and make options in config?
// var menu = AdminMenu.CreateMenu($"{CS2_SimpleAdmin._localizer?["sa_silence"] ?? "Silence"}: {player?.PlayerName}");
//
// foreach (var option in CS2_SimpleAdmin.Instance.Config.MenuConfigs.MuteReasons)
// {
// menu?.AddMenuOption(option, (_, _) =>
// {
// if (player is { IsValid: true })
// Silence(admin, player, duration, option);
// });
// }
//
// if (menu != null) AdminMenu.OpenMenu(admin, menu);
}
private static void Silence(CCSPlayerController admin, CCSPlayerController player, int duration, string reason)
{
if (player is not { IsValid: true }) return;
CS2_SimpleAdmin.Instance.Silence(admin, player, duration, reason);
}
private static void ForceTeamMenu(CCSPlayerController admin, CCSPlayerController player)
{
// TODO: Localize
var menu = AdminMenu.CreateMenu($"{CS2_SimpleAdmin._localizer?["sa_team_force"] ?? "Force Team"} {player.PlayerName}");
List<ChatMenuOptionData> options =
[
new(CS2_SimpleAdmin._localizer?["sa_team_ct"] ?? "CT", () => ForceTeam(admin, player, "ct", CsTeam.CounterTerrorist)),
new(CS2_SimpleAdmin._localizer?["sa_team_t"] ?? "T", () => ForceTeam(admin, player, "t", CsTeam.Terrorist)),
new(CS2_SimpleAdmin._localizer?["sa_team_swap"] ?? "Swap", () => ForceTeam(admin, player, "swap", CsTeam.Spectator)),
new(CS2_SimpleAdmin._localizer?["sa_team_spec"] ?? "Spec", () => ForceTeam(admin, player, "spec", CsTeam.Spectator)),
];
foreach (var menuOptionData in options)
{
var menuName = menuOptionData.Name;
menu?.AddMenuOption(menuName, (_, _) => { menuOptionData.Action.Invoke(); }, menuOptionData.Disabled);
}
if (menu != null) AdminMenu.OpenMenu(admin, menu);
}
private static void ForceTeam(CCSPlayerController admin, CCSPlayerController player, string teamName, CsTeam teamNum)
{
if (player is not { IsValid: true }) return;
CS2_SimpleAdmin.ChangeTeam(admin, player, teamName, teamNum, true);
}
}

View file

@ -1,83 +0,0 @@
using CounterStrikeSharp.API.Core;
using CounterStrikeSharp.API.Modules.Admin;
using CounterStrikeSharp.API.Modules.Entities;
namespace CS2_SimpleAdmin.Menus;
public static class ManageServerMenu
{
public static void OpenMenu(CCSPlayerController admin)
{
if (!admin.IsValid)
return;
var localizer = CS2_SimpleAdmin._localizer;
if (!AdminManager.PlayerHasPermissions(new SteamID(admin.SteamID), "@css/generic"))
{
admin.PrintToChat(localizer?["sa_prefix"] ??
"[SimpleAdmin] " +
(localizer?["sa_no_permission"] ?? "You do not have permissions to use this command")
);
return;
}
var menu = AdminMenu.CreateMenu(localizer?["sa_menu_server_manage"] ?? "Server Manage");
List<ChatMenuOptionData> options = [];
// permissions
var hasMap = AdminManager.CommandIsOverriden("css_map") ? AdminManager.PlayerHasPermissions(new SteamID(admin.SteamID), AdminManager.GetPermissionOverrides("css_map")) : AdminManager.PlayerHasPermissions(new SteamID(admin.SteamID), "@css/changemap");
var hasPlugins = AdminManager.CommandIsOverriden("css_pluginsmanager") ? AdminManager.PlayerHasPermissions(new SteamID(admin.SteamID), AdminManager.GetPermissionOverrides("css_pluginsmanager")) : AdminManager.PlayerHasPermissions(new SteamID(admin.SteamID), "@css/root");
//bool hasMap = AdminManager.PlayerHasPermissions(admin, "@css/changemap");
// options added in order
if (hasPlugins)
{
options.Add(new ChatMenuOptionData(localizer?["sa_menu_pluginsmanager_title"] ?? "Manage Plugins", () => admin.ExecuteClientCommandFromServer("css_pluginsmanager")));
}
if (hasMap)
{
options.Add(new ChatMenuOptionData(localizer?["sa_changemap"] ?? "Change Map", () => ChangeMapMenu(admin)));
}
options.Add(new ChatMenuOptionData(localizer?["sa_restart_game"] ?? "Restart Game", () => CS2_SimpleAdmin.RestartGame(admin)));
foreach (var menuOptionData in options)
{
var menuName = menuOptionData.Name;
menu?.AddMenuOption(menuName, (_, _) => { menuOptionData.Action.Invoke(); }, menuOptionData.Disabled);
}
if (menu != null) AdminMenu.OpenMenu(admin, menu);
}
private static void ChangeMapMenu(CCSPlayerController admin)
{
var menu = AdminMenu.CreateMenu(CS2_SimpleAdmin._localizer?["sa_changemap"] ?? "Change Map");
List<ChatMenuOptionData> options = [];
var maps = CS2_SimpleAdmin.Instance.Config.DefaultMaps;
options.AddRange(maps.Select(map => new ChatMenuOptionData(map, () => ExecuteChangeMap(admin, map, false))));
var wsMaps = CS2_SimpleAdmin.Instance.Config.WorkshopMaps;
options.AddRange(wsMaps.Select(map => new ChatMenuOptionData($"{map.Key} (WS)", () => ExecuteChangeMap(admin, map.Value?.ToString() ?? map.Key, true))));
foreach (var menuOptionData in options)
{
var menuName = menuOptionData.Name;
menu?.AddMenuOption(menuName, (_, _) => { menuOptionData.Action.Invoke(); }, menuOptionData.Disabled);
}
if (menu != null) AdminMenu.OpenMenu(admin, menu);
}
private static void ExecuteChangeMap(CCSPlayerController admin, string mapName, bool workshop)
{
if (workshop)
CS2_SimpleAdmin.Instance.ChangeWorkshopMap(admin, mapName);
else
CS2_SimpleAdmin.Instance.ChangeMap(admin, mapName);
}
}

View file

@ -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; }
}

View file

@ -2,6 +2,7 @@ using CounterStrikeSharp.API.Core;
using CounterStrikeSharp.API.Core.Translations;
using CounterStrikeSharp.API.Modules.Admin;
using CounterStrikeSharp.API.Modules.Entities;
using Microsoft.Extensions.Localization;
namespace CS2_SimpleAdmin.Menus;
@ -125,7 +126,11 @@ public class MenuManager
/// <param name="menuId">The menu to unregister.</param>
public void UnregisterMenu(string categoryId, string menuId)
{
if (!_menuCategories.TryGetValue(categoryId, out var category)) return;
if (!_menuCategories.TryGetValue(categoryId, out MenuCategory? category))
{
return;
}
category.MenuFactories.Remove(menuId);
_menuCategories[categoryId].MenuNames.Remove(menuId);
_menuCategories[categoryId].MenuPermissions.Remove(menuId);
@ -139,16 +144,21 @@ public class MenuManager
/// <returns>A MenuBuilder instance for the main menu.</returns>
public MenuBuilder CreateMainMenu(CCSPlayerController player)
{
var localizer = CS2_SimpleAdmin._localizer;
var mainMenu = new MenuBuilder("sa_title", player, localizer);
IStringLocalizer? localizer = CS2_SimpleAdmin._localizer;
MenuBuilder mainMenu = new MenuBuilder("sa_title", player, localizer);
foreach (var category in _menuCategories.Values)
foreach (MenuCategory category in _menuCategories.Values)
{
if (category.MenuFactories.Count <= 0) continue;
// Check category permissions
var steamId = new SteamID(player.SteamID);
if (!AdminManager.PlayerHasPermissions(steamId, category.Permission))
if (category.MenuFactories.Count <= 0)
{
continue;
}
// Check category permissions
SteamID steamId = new SteamID(player.SteamID);
if (!AdminManager.PlayerHasPermissions(steamId, category.Permission))
{
continue;
}
// Get localized category name for this player
// If category has a module localizer, use it; otherwise use main plugin localizer
@ -181,7 +191,7 @@ public class MenuManager
/// <returns>A MenuBuilder instance for the category menu.</returns>
private MenuBuilder CreateCategoryMenu(MenuCategory category, CCSPlayerController player)
{
var localizer = CS2_SimpleAdmin._localizer;
IStringLocalizer? localizer = CS2_SimpleAdmin._localizer;
// Get localized category name for this player
// If category has a module localizer, use it; otherwise use main plugin localizer
@ -198,18 +208,22 @@ public class MenuManager
}
}
var categoryMenu = new MenuBuilder(localizedCategoryName);
MenuBuilder categoryMenu = new MenuBuilder(localizedCategoryName);
foreach (var kvp in category.MenuFactories)
foreach (KeyValuePair<string, Func<CCSPlayerController, MenuBuilder>> kvp in category.MenuFactories)
{
var menuId = kvp.Key;
var menuFactory = kvp.Value;
var menuName = category.MenuNames.TryGetValue(menuId, out var name) ? name : menuId;
var permission = category.MenuPermissions.TryGetValue(menuId, out var perm) ? perm : null;
var commandName = category.MenuCommandNames.TryGetValue(menuId, out var cmd) ? cmd : null;
string menuId = kvp.Key;
Func<CCSPlayerController, MenuBuilder> menuFactory = kvp.Value;
if (!category.MenuNames.TryGetValue(menuId, out string? menuName))
{
menuName = menuId;
}
category.MenuPermissions.TryGetValue(menuId, out string? permission);
category.MenuCommandNames.TryGetValue(menuId, out string? commandName);
// Check permissions with command override support
var steamId = new SteamID(player.SteamID);
SteamID steamId = new SteamID(player.SteamID);
// If commandName is provided, check for permission overrides
if (!string.IsNullOrEmpty(commandName))
@ -219,7 +233,7 @@ public class MenuManager
// Check if command has overridden permissions
if (AdminManager.CommandIsOverriden(commandName))
{
var overriddenPermission = AdminManager.GetPermissionOverrides(commandName);
string[] overriddenPermission = AdminManager.GetPermissionOverrides(commandName);
hasPermission = AdminManager.PlayerHasPermissions(steamId, overriddenPermission);
}
else if (!string.IsNullOrEmpty(permission))
@ -234,13 +248,17 @@ public class MenuManager
}
if (!hasPermission)
{
continue;
}
}
// Fallback to standard permission check if no commandName provided
else if (!string.IsNullOrEmpty(permission))
{
if (!AdminManager.PlayerHasPermissions(steamId, permission))
{
continue;
}
}
// Get localized menu name for this player
@ -248,7 +266,7 @@ public class MenuManager
string localizedMenuName;
using (new WithTemporaryCulture(player.GetLanguage()))
{
if (category.MenuLocalizers.TryGetValue(menuId, out var menuLocalizer))
if (category.MenuLocalizers.TryGetValue(menuId, out IStringLocalizer? menuLocalizer))
{
// Menu has its own module localizer
localizedMenuName = menuLocalizer[menuName] ?? menuName;
@ -278,9 +296,9 @@ public class MenuManager
/// <param name="player">The player to open the menu for.</param>
public void OpenMainMenu(CCSPlayerController player)
{
var localizer = CS2_SimpleAdmin._localizer;
var steamId = new SteamID(player.SteamID);
IStringLocalizer? localizer = CS2_SimpleAdmin._localizer;
SteamID steamId = new SteamID(player.SteamID);
if (!AdminManager.PlayerHasPermissions(steamId, "@css/generic"))
{
player.PrintToChat(localizer?["sa_prefix"] ?? "[SimpleAdmin] " +
@ -303,17 +321,6 @@ public class MenuManager
// RegisterCategory("fun", "sa_menu_fun_commands", "@css/generic");
RegisterCategory("admin", "sa_menu_admins_manage", "@css/root");
}
/// <summary>
/// Public method for creating category menus (for API usage).
/// </summary>
/// <param name="category">The menu category to create.</param>
/// <param name="player">The player to create the menu for.</param>
/// <returns>A MenuBuilder instance for the category menu.</returns>
public MenuBuilder CreateCategoryMenuPublic(MenuCategory category, CCSPlayerController player)
{
return CreateCategoryMenu(category, player);
}
}
/// <summary>

View file

@ -1,56 +0,0 @@
using CounterStrikeSharp.API.Core;
using CounterStrikeSharp.API.Modules.Admin;
using System.Web;
namespace CS2_SimpleAdmin.Menus;
public static class PlayersMenu
{
public static void OpenRealPlayersMenu(CCSPlayerController admin, string menuName, Action<CCSPlayerController, CCSPlayerController> onSelectAction, Func<CCSPlayerController, bool>? enableFilter = null)
{
OpenMenu(admin, menuName, onSelectAction, p => !p.IsBot);
}
public static void OpenAdminPlayersMenu(CCSPlayerController admin, string menuName, Action<CCSPlayerController, CCSPlayerController> onSelectAction, Func<CCSPlayerController?, bool>? enableFilter = null)
{
OpenMenu(admin, menuName, onSelectAction, p => AdminManager.GetPlayerAdminData(p)?.Flags.Count > 0);
}
public static void OpenAliveMenu(CCSPlayerController admin, string menuName, Action<CCSPlayerController, CCSPlayerController> onSelectAction, Func<CCSPlayerController, bool>? enableFilter = null)
{
OpenMenu(admin, menuName, onSelectAction, p => p.PlayerPawn?.Value?.LifeState == (int)LifeState_t.LIFE_ALIVE);
}
public static void OpenDeadMenu(CCSPlayerController admin, string menuName, Action<CCSPlayerController?, CCSPlayerController> onSelectAction, Func<CCSPlayerController, bool>? enableFilter = null)
{
OpenMenu(admin, menuName, onSelectAction, p => p.PlayerPawn?.Value?.LifeState != (int)LifeState_t.LIFE_ALIVE);
}
public static void OpenMenu(CCSPlayerController admin, string menuName, Action<CCSPlayerController, CCSPlayerController> onSelectAction, Func<CCSPlayerController, bool>? enableFilter = null)
{
var menu = AdminMenu.CreateMenu(menuName);
var players = Helper.GetValidPlayersWithBots();
foreach (var player in players)
{
var playerName = player != null && player.PlayerName.Length > 26 ? player.PlayerName[..26] : player?.PlayerName;
var optionName = HttpUtility.HtmlEncode(playerName);
if (player != null && enableFilter != null && !enableFilter(player))
continue;
var enabled = admin.CanTarget(player);
var capturedPlayer = player; // Capture in local variable to avoid closure issues
if (optionName != null)
menu?.AddMenuOption(optionName, (controller, option) =>
{
if (capturedPlayer != null) onSelectAction.Invoke(admin, capturedPlayer);
},
!enabled);
}
if (menu != null) AdminMenu.OpenMenu(admin, menu);
}
}

View file

@ -1,52 +0,0 @@
using CounterStrikeSharp.API.Core;
using CS2_SimpleAdmin.Models;
using CS2_SimpleAdminApi;
namespace CS2_SimpleAdmin.Menus;
public static class ReasonMenu
{
public static void OpenMenu(CCSPlayerController admin, PenaltyType penaltyType, string menuName, CCSPlayerController player, Action<CCSPlayerController, CCSPlayerController, string> onSelectAction)
{
var menu = AdminMenu.CreateMenu(menuName);
var reasons = penaltyType switch
{
PenaltyType.Ban => CS2_SimpleAdmin.Instance.Config.MenuConfigs.BanReasons,
PenaltyType.Kick => CS2_SimpleAdmin.Instance.Config.MenuConfigs.KickReasons,
PenaltyType.Mute => CS2_SimpleAdmin.Instance.Config.MenuConfigs.MuteReasons,
PenaltyType.Warn => CS2_SimpleAdmin.Instance.Config.MenuConfigs.WarnReasons,
PenaltyType.Gag => CS2_SimpleAdmin.Instance.Config.MenuConfigs.MuteReasons,
PenaltyType.Silence => CS2_SimpleAdmin.Instance.Config.MenuConfigs.MuteReasons,
_ => CS2_SimpleAdmin.Instance.Config.MenuConfigs.BanReasons
};
foreach (var reason in reasons)
{
menu?.AddMenuOption(reason, (_, _) => onSelectAction(admin, player, reason));
}
if (menu != null) AdminMenu.OpenMenu(admin, menu);
}
public static void OpenMenu(CCSPlayerController admin, PenaltyType penaltyType, string menuName, DisconnectedPlayer player, Action<CCSPlayerController, DisconnectedPlayer, string> onSelectAction)
{
var menu = AdminMenu.CreateMenu(menuName);
var reasons = penaltyType switch
{
PenaltyType.Ban => CS2_SimpleAdmin.Instance.Config.MenuConfigs.BanReasons,
PenaltyType.Kick => CS2_SimpleAdmin.Instance.Config.MenuConfigs.KickReasons,
PenaltyType.Mute => CS2_SimpleAdmin.Instance.Config.MenuConfigs.MuteReasons,
PenaltyType.Warn => CS2_SimpleAdmin.Instance.Config.MenuConfigs.WarnReasons,
_ => CS2_SimpleAdmin.Instance.Config.MenuConfigs.BanReasons
};
foreach (var reason in reasons)
{
menu?.AddMenuOption(reason, (_, _) => onSelectAction(admin, player, reason));
}
if (menu != null) AdminMenu.OpenMenu(admin, menu);
}
}

View file

@ -0,0 +1,81 @@
using CounterStrikeSharp.API.Core.Capabilities;
using Microsoft.Extensions.Logging;
using PanoramaUiKit.Shared.Api;
using PanoramaUiKit.Shared.Banners;
using PanoramaUiKit.Shared.Common;
using PanoramaUiKit.Shared.Menus;
using PanoramaUiKit.Shared.Toasts;
using PanoramaUiKit.Shared.Votes;
namespace CS2_SimpleAdmin.Menus;
/// <summary>
/// Access to the Panorama UI Kit plugin and the layouts SimpleAdmin draws on.
/// </summary>
internal static class UiKit
{
private static readonly PluginCapability<IPanoramaUiKit> Capability = new(IPanoramaUiKit.CapabilityName);
internal static MenuLayout MenuLayout { get; private set; } = new() { Name = "uikit_menu" };
internal static VoteLayout VoteLayout { get; private set; } = new() { Name = "uikit_vote" };
internal static BannerLayout BannerLayout { get; private set; } = new() { Name = "uikit_banner" };
internal static ToastLayout ToastLayout { get; private set; } = new() { Name = "uikit_toast" };
/// <summary>
/// Resolved on every use so a hot reload of the kit is picked up.
/// </summary>
internal static IPanoramaUiKit? Instance
{
get
{
try
{
return Capability.Get();
}
catch (Exception)
{
return null;
}
}
}
internal static void Configure(MenuConfig config)
{
MenuLayout = new MenuLayout { Name = config.MenuLayout };
VoteLayout = new VoteLayout { Name = config.VoteLayout };
BannerLayout = new BannerLayout { Name = config.BannerLayout };
ToastLayout = new ToastLayout { Name = config.ToastLayout };
}
/// <summary>
/// Spawns the layouts up front: creating one on first use sends the client one big burst.
/// </summary>
internal static bool Preload(ILogger logger)
{
IPanoramaUiKit? kit = Instance;
if (kit == null)
{
logger.LogError("Panorama UI Kit not found: install PanoramaUiKit and shared/PanoramaUiKit.Shared.");
return false;
}
if (kit.Version != IPanoramaUiKit.ApiVersion)
{
logger.LogWarning("Panorama UI Kit API v{Running}, SimpleAdmin built against v{Built}.", kit.Version, IPanoramaUiKit.ApiVersion);
}
UiLayout[] layouts = [MenuLayout, VoteLayout, BannerLayout, ToastLayout];
foreach (UiLayout layout in layouts)
{
if (!kit.Preload(layout))
{
logger.LogError("Layout {Layout} was refused, see the Panorama UI Kit log.", layout);
}
}
return true;
}
}