Skip to content

Commit a03964c

Browse files
committed
Add per-player menu localization and refactor menus
Introduces per-player localization for menu categories and items using translation keys and IStringLocalizer, allowing modules and the main plugin to display menu names in the player's language. Refactors menu registration and builder logic to use translation keys, updates API and documentation, and adds database provider upsert query abstraction for player IPs. Also updates version to 1.7.8-beta-4 and corrects a translation string typo.
1 parent b0d8696 commit a03964c

File tree

20 files changed

+761
-140
lines changed

20 files changed

+761
-140
lines changed

CS2-SimpleAdmin/Api/CS2_SimpleAdminApi.cs

Lines changed: 90 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
using CounterStrikeSharp.API.Core;
22
using CounterStrikeSharp.API.Core.Commands;
3+
using CounterStrikeSharp.API.Core.Translations;
34
using CounterStrikeSharp.API.Modules.Commands;
45
using CounterStrikeSharp.API.Modules.Commands.Targeting;
56
using CounterStrikeSharp.API.Modules.Entities;
@@ -205,6 +206,14 @@ public void RegisterMenuCategory(string categoryId, string categoryName, string
205206
Menus.MenuManager.Instance.RegisterCategory(categoryId, categoryName, permission);
206207
}
207208

209+
public void RegisterMenuCategory(string categoryId, string categoryNameKey, string permission, object moduleLocalizer)
210+
{
211+
if (moduleLocalizer is not IStringLocalizer localizer)
212+
throw new InvalidOperationException("moduleLocalizer must be an IStringLocalizer instance");
213+
214+
Menus.MenuManager.Instance.RegisterCategory(categoryId, categoryNameKey, permission, localizer);
215+
}
216+
208217
public void RegisterMenu(string categoryId, string menuId, string menuName,
209218
Func<CCSPlayerController, object> menuFactory, string? permission = null, string? commandName = null)
210219
{
@@ -263,6 +272,39 @@ MenuBuilder BuilderFactory(CCSPlayerController player)
263272
}
264273
}
265274

275+
public void RegisterMenu(string categoryId, string menuId, string menuNameKey,
276+
Func<CCSPlayerController, MenuContext, object> menuFactory, string? permission, string? commandName, object moduleLocalizer)
277+
{
278+
if (moduleLocalizer is not IStringLocalizer localizer)
279+
throw new InvalidOperationException("moduleLocalizer must be an IStringLocalizer instance");
280+
281+
Menus.MenuManager.Instance.RegisterMenu(categoryId, menuId, menuNameKey, BuilderFactory, permission, commandName, localizer);
282+
return;
283+
284+
MenuBuilder BuilderFactory(CCSPlayerController player)
285+
{
286+
var context = new MenuContext(categoryId, menuId, menuNameKey, permission, commandName);
287+
288+
if (menuFactory(player, context) is not MenuBuilder menuBuilder)
289+
throw new InvalidOperationException("Menu factory must return MenuBuilder");
290+
291+
// Dodaj automatyczną obsługę przycisku 'Wróć'
292+
menuBuilder.WithBackAction(p =>
293+
{
294+
if (Menus.MenuManager.Instance.GetMenuCategories().TryGetValue(categoryId, out var category))
295+
{
296+
Menus.MenuManager.Instance.CreateCategoryMenuPublic(category, p).OpenMenu(p);
297+
}
298+
else
299+
{
300+
Menus.MenuManager.Instance.OpenMainMenu(p);
301+
}
302+
});
303+
304+
return menuBuilder;
305+
}
306+
}
307+
266308

267309
public void UnregisterMenu(string categoryId, string menuId)
268310
{
@@ -289,7 +331,30 @@ public object CreateMenuWithBack(string title, string categoryId, CCSPlayerContr
289331

290332
public object CreateMenuWithBack(MenuContext context, CCSPlayerController player)
291333
{
292-
return CreateMenuWithBack(context.MenuTitle, context.CategoryId, player);
334+
// Get translated title if module has localizer
335+
string title = context.MenuTitle;
336+
337+
if (Menus.MenuManager.Instance.GetMenuCategories().TryGetValue(context.CategoryId, out var category))
338+
{
339+
// Check if this specific menu has a localizer
340+
if (category.MenuLocalizers.TryGetValue(context.MenuId, out var menuLocalizer))
341+
{
342+
using (new WithTemporaryCulture(player.GetLanguage()))
343+
{
344+
title = menuLocalizer[context.MenuTitle] ?? context.MenuTitle;
345+
}
346+
}
347+
// Fallback to category localizer
348+
else if (category.ModuleLocalizer != null)
349+
{
350+
using (new WithTemporaryCulture(player.GetLanguage()))
351+
{
352+
title = category.ModuleLocalizer[context.MenuTitle] ?? context.MenuTitle;
353+
}
354+
}
355+
}
356+
357+
return CreateMenuWithBack(title, context.CategoryId, player);
293358
}
294359

295360
public List<CCSPlayerController> GetValidPlayers()
@@ -321,7 +386,30 @@ public object CreateMenuWithPlayers(string title, string categoryId, CCSPlayerCo
321386
public object CreateMenuWithPlayers(MenuContext context, CCSPlayerController admin,
322387
Func<CCSPlayerController, bool> filter, Action<CCSPlayerController, CCSPlayerController> onSelect)
323388
{
324-
return CreateMenuWithPlayers(context.MenuTitle, context.CategoryId, admin, filter, onSelect);
389+
// Get translated title if module has localizer
390+
string title = context.MenuTitle;
391+
392+
if (Menus.MenuManager.Instance.GetMenuCategories().TryGetValue(context.CategoryId, out var category))
393+
{
394+
// Check if this specific menu has a localizer
395+
if (category.MenuLocalizers.TryGetValue(context.MenuId, out var menuLocalizer))
396+
{
397+
using (new WithTemporaryCulture(admin.GetLanguage()))
398+
{
399+
title = menuLocalizer[context.MenuTitle] ?? context.MenuTitle;
400+
}
401+
}
402+
// Fallback to category localizer
403+
else if (category.ModuleLocalizer != null)
404+
{
405+
using (new WithTemporaryCulture(admin.GetLanguage()))
406+
{
407+
title = category.ModuleLocalizer[context.MenuTitle] ?? context.MenuTitle;
408+
}
409+
}
410+
}
411+
412+
return CreateMenuWithPlayers(title, context.CategoryId, admin, filter, onSelect);
325413
}
326414

327415
public void AddMenuOption(object menu, string name, Action<CCSPlayerController> action, bool disabled = false,

CS2-SimpleAdmin/CS2-SimpleAdmin.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ public partial class CS2_SimpleAdmin : BasePlugin, IPluginConfig<CS2_SimpleAdmin
2222
public override string ModuleName => "CS2-SimpleAdmin" + (Helper.IsDebugBuild ? " (DEBUG)" : " (RELEASE)");
2323
public override string ModuleDescription => "Simple admin plugin for Counter-Strike 2 :)";
2424
public override string ModuleAuthor => "daffyy & Dliix66";
25-
public override string ModuleVersion => "1.7.8-beta-3";
25+
public override string ModuleVersion => "1.7.8-beta-4";
2626

2727
public override void Load(bool hotReload)
2828
{

CS2-SimpleAdmin/Database/IDatabaseProvider.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,9 @@ public interface IDatabaseProvider
1212
string GetBanSelectQuery(bool multiServer);
1313
string GetIpHistoryQuery();
1414
string GetBanUpdateQuery(bool multiServer);
15+
16+
// PlayerManager
17+
string GetUpsertPlayerIpQuery();
1518

1619
// PermissionManager
1720
string GetAdminsQuery();
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
CREATE TABLE IF NOT EXISTS `sa_players_ips` (
22
`steamid` INTEGER NOT NULL,
3-
`address` INTEGER NOT NULL
3+
`address` INTEGER NOT NULL,
44
`used_at` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
55
PRIMARY KEY (`steamid`, `address`)
66
);

CS2-SimpleAdmin/Database/MysqlDatabaseProvider.cs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,17 @@ public string GetIpHistoryQuery()
8686
return "SELECT steamid, name, address, used_at FROM sa_players_ips ORDER BY used_at DESC";
8787
}
8888

89+
public string GetUpsertPlayerIpQuery()
90+
{
91+
return """
92+
INSERT INTO `sa_players_ips` (steamid, name, address, used_at)
93+
VALUES (@SteamID, @playerName, @IPAddress, CURRENT_TIMESTAMP)
94+
ON DUPLICATE KEY UPDATE
95+
used_at = CURRENT_TIMESTAMP,
96+
name = @playerName;
97+
""";
98+
}
99+
89100
public string GetBanUpdateQuery(bool multiServer)
90101
{
91102
return multiServer ? """

CS2-SimpleAdmin/Database/SqliteDatabaseProvider.cs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,17 @@ ORDER BY updated_at DESC
8383
public string GetIpHistoryQuery() =>
8484
"SELECT steamid, name, address, used_at FROM sa_players_ips ORDER BY used_at DESC";
8585

86+
public string GetUpsertPlayerIpQuery()
87+
{
88+
return """
89+
INSERT INTO sa_players_ips (steamid, name, address, used_at)
90+
VALUES (@SteamID, @playerName, @IPAddress, CURRENT_TIMESTAMP)
91+
ON CONFLICT(steamid, address) DO UPDATE SET
92+
used_at = CURRENT_TIMESTAMP,
93+
name = @playerName;
94+
""";
95+
}
96+
8697
public string GetBanUpdateQuery(bool multiServer) =>
8798
multiServer
8899
? """

CS2-SimpleAdmin/Helper.cs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -426,7 +426,7 @@ private static void SendDiscordLogMessage(CCSPlayerController? caller, CommandIn
426426

427427
var communityUrl = caller != null ? "<" + new SteamID(caller.SteamID).ToCommunityUrl() + ">" : "<https://steamcommunity.com/profiles/0>";
428428
var callerName = caller != null ? caller.PlayerName : CS2_SimpleAdmin._localizer?["sa_console"] ?? "Console";
429-
_ = CS2_SimpleAdmin.DiscordWebhookClientLog.SendMessageAsync(Helper.GenerateMessageDiscord(localizer["sa_discord_log_command", $"[{callerName}]({communityUrl})", command.GetCommandString]));
429+
_ = CS2_SimpleAdmin.DiscordWebhookClientLog.SendMessageAsync(GenerateMessageDiscord(localizer["sa_discord_log_command", $"[{callerName}]({communityUrl})", command.GetCommandString]));
430430
}
431431

432432
private static void SendDiscordLogMessage(CCSPlayerController? caller, string command, IStringLocalizer? localizer)
@@ -1026,7 +1026,9 @@ public static class Time
10261026
{
10271027
public static DateTime ActualDateTime()
10281028
{
1029-
return DateTime.UtcNow;
1029+
if (CS2_SimpleAdmin.Instance.Config.DatabaseConfig.DatabaseType.ToLower().Equals("sqlite"))
1030+
return DateTime.UtcNow;
1031+
10301032
string timezoneId = CS2_SimpleAdmin.Instance.Config.Timezone;
10311033
DateTime utcNow = DateTime.UtcNow;
10321034

CS2-SimpleAdmin/Managers/PlayerManager.cs

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -99,14 +99,8 @@ await Server.NextWorldUpdateAsync(() =>
9999
var steamId64 = CS2_SimpleAdmin.PlayersInfo[steamId].SteamId.SteamId64;
100100
var ipUint = IpHelper.IpToUint(ipAddress);
101101

102-
// MySQL: INSERT ... ON DUPLICATE KEY UPDATE pattern
103-
const string upsertQuery = """
104-
INSERT INTO `sa_players_ips` (steamid, name, address, used_at)
105-
VALUES (@SteamID, @playerName, @IPAddress, CURRENT_TIMESTAMP)
106-
ON DUPLICATE KEY UPDATE
107-
used_at = CURRENT_TIMESTAMP,
108-
name = @playerName;
109-
""";
102+
// Use database-specific UPSERT query (handles MySQL vs SQLite syntax differences)
103+
var upsertQuery = CS2_SimpleAdmin.DatabaseProvider.GetUpsertPlayerIpQuery();
110104

111105
await connection.ExecuteAsync(upsertQuery, new
112106
{

0 commit comments

Comments
 (0)