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,16 +1,21 @@
using CounterStrikeSharp.API.Core;
using System.Text;
using System.Text.RegularExpressions;
using CounterStrikeSharp.API.Core;
using CounterStrikeSharp.API.Core.Translations;
using CounterStrikeSharp.API.Modules.Admin;
using CounterStrikeSharp.API.Modules.Commands;
using CounterStrikeSharp.API.Modules.Memory;
using CounterStrikeSharp.API.Modules.Utils;
using System.Text;
using CounterStrikeSharp.API.Modules.Commands.Targeting;
using CounterStrikeSharp.API.Modules.Entities;
using CS2_SimpleAdmin.Menus;
using PanoramaUiKit.Shared.Api;
using PanoramaUiKit.Shared.Common;
namespace CS2_SimpleAdmin;
public partial class CS2_SimpleAdmin
{
private const float AnnouncementSeconds = 7f;
/// <summary>
/// Sends a chat message only to admins that have chat permission.
/// The message is encoded properly to handle UTF-8 characters.
@ -23,16 +28,18 @@ public partial class CS2_SimpleAdmin
{
Helper.LogCommand(caller, command);
var utf8BytesString = Encoding.UTF8.GetBytes(command.GetCommandString[command.GetCommandString.IndexOf(' ')..]);
var utf8String = Encoding.UTF8.GetString(utf8BytesString);
byte[] utf8BytesString = Encoding.UTF8.GetBytes(command.GetCommandString[command.GetCommandString.IndexOf(' ')..]);
string utf8String = Encoding.UTF8.GetString(utf8BytesString);
foreach (var player in Helper.GetValidPlayers()
foreach (CCSPlayerController? player in Helper.GetValidPlayers()
.Where(p => AdminManager.PlayerHasPermissions(new SteamID(p.SteamID), "@css/chat")))
{
if (_localizer != null)
{
player.PrintToChat(_localizer["sa_adminchat_template_admin",
caller == null ? _localizer?["sa_console"] ?? "Console" : caller.PlayerName,
Helper.GetCallerName(caller),
utf8String]);
}
}
}
@ -45,14 +52,17 @@ public partial class CS2_SimpleAdmin
[RequiresPermissions("@css/chat")]
public void OnAdminCustomSayCommand(CCSPlayerController? caller, CommandInfo command)
{
if (command.GetCommandString[command.GetCommandString.IndexOf(' ')..].Length == 0) return;
if (command.GetCommandString[command.GetCommandString.IndexOf(' ')..].Length == 0)
{
return;
}
var utf8BytesString = Encoding.UTF8.GetBytes(command.GetCommandString[command.GetCommandString.IndexOf(' ')..]);
var utf8String = Encoding.UTF8.GetString(utf8BytesString);
byte[] utf8BytesString = Encoding.UTF8.GetBytes(command.GetCommandString[command.GetCommandString.IndexOf(' ')..]);
string utf8String = Encoding.UTF8.GetString(utf8BytesString);
Helper.LogCommand(caller, command);
foreach (var player in Helper.GetValidPlayers())
foreach (CCSPlayerController player in Helper.GetValidPlayers())
{
player.PrintToChat(utf8String.ReplaceColorTags());
}
@ -67,14 +77,17 @@ public partial class CS2_SimpleAdmin
[RequiresPermissions("@css/chat")]
public void OnAdminSayCommand(CCSPlayerController? caller, CommandInfo command)
{
if (command.GetCommandString[command.GetCommandString.IndexOf(' ')..].Length == 0) return;
if (command.GetCommandString[command.GetCommandString.IndexOf(' ')..].Length == 0)
{
return;
}
var utf8BytesString = Encoding.UTF8.GetBytes(command.GetCommandString[command.GetCommandString.IndexOf(' ')..]);
var utf8String = Encoding.UTF8.GetString(utf8BytesString);
var callerName = caller?.PlayerName;
byte[] utf8BytesString = Encoding.UTF8.GetBytes(command.GetCommandString[command.GetCommandString.IndexOf(' ')..]);
string utf8String = Encoding.UTF8.GetString(utf8BytesString);
string? callerName = caller?.PlayerName;
Helper.LogCommand(caller, command);
foreach (var player in Helper.GetValidPlayers())
foreach (CCSPlayerController player in Helper.GetValidPlayers())
{
// The message always goes out (it is a broadcast, not an activity notice),
// but the admin's name follows ShowActivityType like every other activity message.
@ -93,19 +106,23 @@ public partial class CS2_SimpleAdmin
[RequiresPermissions("@css/chat")]
public void OnAdminPrivateSayCommand(CCSPlayerController? caller, CommandInfo command)
{
var callerName = caller == null ? _localizer?["sa_console"] ?? "Console" : caller.PlayerName;
string callerName = Helper.GetCallerName(caller);
var targets = GetTarget(command);
if (targets == null) return;
var playersToTarget = targets.Players.Where(player => player is { IsValid: true, IsHLTV: false }).ToList();
TargetResult? targets = GetTarget(command);
if (targets == null)
{
return;
}
List<CCSPlayerController> playersToTarget = targets.Players.Where(player => player is { IsValid: true, IsHLTV: false }).ToList();
//Helper.LogCommand(caller, command);
var range = command.GetArg(0).Length + command.GetArg(1).Length + 2;
var message = command.GetCommandString[range..];
int range = command.GetArg(0).Length + command.GetArg(1).Length + 2;
string message = command.GetCommandString[range..];
var utf8BytesString = Encoding.UTF8.GetBytes(message);
var utf8String = Encoding.UTF8.GetString(utf8BytesString);
byte[] utf8BytesString = Encoding.UTF8.GetBytes(message);
string utf8String = Encoding.UTF8.GetString(utf8BytesString);
playersToTarget.ForEach(player =>
{
@ -116,7 +133,7 @@ public partial class CS2_SimpleAdmin
}
/// <summary>
/// Broadcasts a center-screen message to all players.
/// Broadcasts a message to all players in a Panorama UI Kit banner.
/// </summary>
/// <param name="caller">The admin or console sending the message.</param>
/// <param name="command">The command input containing the message.</param>
@ -124,15 +141,15 @@ public partial class CS2_SimpleAdmin
[RequiresPermissions("@css/chat")]
public void OnAdminCenterSayCommand(CCSPlayerController? caller, CommandInfo command)
{
var utf8BytesString = Encoding.UTF8.GetBytes(command.GetCommandString[command.GetCommandString.IndexOf(' ')..]);
var utf8String = Encoding.UTF8.GetString(utf8BytesString);
byte[] utf8BytesString = Encoding.UTF8.GetBytes(command.GetCommandString[command.GetCommandString.IndexOf(' ')..]);
string utf8String = Encoding.UTF8.GetString(utf8BytesString);
Helper.LogCommand(caller, command);
Helper.PrintToCenterAll(utf8String.ReplaceColorTags());
UiKit.Instance?.Banner(UiKit.BannerLayout, StripColorTags(utf8String), UiStyle.Info, AnnouncementSeconds);
}
/// <summary>
/// Sends a HUD alert message to all players.
/// Sends a message to all players in a Panorama UI Kit toast, titled with the admin's name.
/// </summary>
/// <param name="caller">The admin or console sending the message.</param>
/// <param name="command">The command input containing the message.</param>
@ -140,14 +157,31 @@ public partial class CS2_SimpleAdmin
[RequiresPermissions("@css/chat")]
public void OnAdminHudSayCommand(CCSPlayerController? caller, CommandInfo command)
{
var utf8BytesString = Encoding.UTF8.GetBytes(command.GetCommandString[command.GetCommandString.IndexOf(' ')..]);
var utf8String = Encoding.UTF8.GetString(utf8BytesString);
byte[] utf8BytesString = Encoding.UTF8.GetBytes(command.GetCommandString[command.GetCommandString.IndexOf(' ')..]);
string utf8String = Encoding.UTF8.GetString(utf8BytesString);
Helper.LogCommand(caller, command);
VirtualFunctions.ClientPrintAll(
HudDestination.Alert,
utf8String.ReplaceColorTags(),
0, 0, 0, 0, 0);
IPanoramaUiKit? kit = UiKit.Instance;
if (kit == null)
{
return;
}
string message = StripColorTags(utf8String);
string? callerName = caller?.PlayerName;
foreach (CCSPlayerController player in Helper.GetValidPlayers())
{
kit.Toast(player, UiKit.ToastLayout, Helper.ResolveActivityName(player, callerName), message, UiStyle.Info, AnnouncementSeconds);
}
}
}
/// <summary>
/// Panorama does not render chat color tags such as {red}: drop them.
/// </summary>
private static string StripColorTags(string message)
{
return Regex.Replace(message, @"\{[A-Za-z]+\}", string.Empty).Trim();
}
}