diff --git a/lang/en.json b/lang/en.json index 8749a37..82c135f 100644 --- a/lang/en.json +++ b/lang/en.json @@ -6,7 +6,7 @@ "color.command": "{blue}", "color.currency": "{gold}", "color.target": "{green}", - "prefix": "{red}GANGS {darkred}>%color.default% ", + "prefix": " {red}GANGS {darkred}> %color.default%", "command.gang.not_in_gang": "%prefix%You are not in a gang. Type %color.blue%/gang create [name]%color.default% to create one.", "command.balance": "%prefix%You have %color.currency%{0} %currency.player%{grey}.", "command.balance.plural": "%prefix%You have %color.currency%{0} %currency.player.plural%{grey}.", @@ -14,12 +14,12 @@ "command.balance.other": "%prefix%%color.target%{0}%color.default% has %color.currency%{1} %currency.player%%color.default%.", "command.balance.other.plural": "%prefix%%color.target%{0}%color.default% has %color.currency%{1} %currency.player.plural%%color.default%.", "command.balance.other.none": "%prefix%%color.target%{0}%color.default% has no %currency.player.plural%.", - "command.balance.set": "%prefix%Set %color.target%{0}%color.default%'s %color.currency%%currency.player.plural% to %color.currency%{1} %color.default%.", + "command.balance.set": "%prefix%Set %color.target%{0}%color.default%'s %color.currency%%currency.player.plural% %color.default%to %color.currency%{1} %color.default%.", "command.usage": "%prefix%Usage: %color.command%{0}", - "command.invalid_parameter": "%prefix%Invalid parameter %color.emph%\"{0}\"%color.default%, expected %color.special%{1}%color.default%.", - "generic.player.not_found": "%prefix%Could not find a player using {darkred}\"{0}\"{grey}.", - "generic.player.found_multiple": "%prefix%Found multiple players using {darkred}\"{0}\"{grey}.", - "generic.soontm": "%prefix%{grey}SoonTM!", + "command.invalid_parameter": "%prefix%Invalid parameter \"%color.emph%{0}%color.default%\", expected %color.special%{1}%color.default%.", + "generic.player.not_found": "%prefix%Could not find a player using \"{darkred}{0}{grey}\".", + "generic.player.found_multiple": "%prefix%Found multiple players using \"{darkred}{0}{grey}\".", + "generic.soontm": "%prefix%SoonTM!", "generic.player.only": "%prefix%{red}Only players can use this.", "generic.no_permission": "%prefix%{red}You do not have permission to use this command.", "generic.no_permission.node": "%prefix%{red}You are missing the {darkred}{0}{red} permission.", diff --git a/src/CS2/Commands/BalanceCommand.cs b/src/CS2/Commands/BalanceCommand.cs index d9c8cd3..1e335e9 100644 --- a/src/CS2/Commands/BalanceCommand.cs +++ b/src/CS2/Commands/BalanceCommand.cs @@ -1,4 +1,5 @@ -using CounterStrikeSharp.API.Core; +using CounterStrikeSharp.API; +using CounterStrikeSharp.API.Core; using CounterStrikeSharp.API.Modules.Commands.Targeting; using CounterStrikeSharp.API.Modules.Utils; using GangsAPI; @@ -12,18 +13,13 @@ namespace Commands; public class BalanceCommand(IPlayerStatManager playerMgr, - IStringLocalizer testLocalizer) : ICommand { + IStringLocalizer localizer) : ICommand { public string Name => "css_balance"; public string[] Usage => ["", "", " "]; public string[] Aliases => ["css_balance", "css_credit", "css_credits"]; - private string id = new BalanceStat().StatId; - private IStringLocalizer localizer = testLocalizer; - - public void Start(BasePlugin? plugin, bool hotReload) { - if (plugin != null) localizer = plugin.Localizer; - } + private readonly string id = new BalanceStat().StatId; public async Task Execute(PlayerWrapper? executor, CommandInfoWrapper info) { @@ -44,53 +40,62 @@ public async Task Execute(PlayerWrapper? executor, return CommandResult.SUCCESS; } + if (info.ArgCount > 3) return CommandResult.PRINT_USAGE; + // TODO: Add Unit Test Support // Would require a mock of some type of Server state // for Utilities to wrap around. - var target = new Target(info[1]); - var result = target.GetTarget(null).Players; - if (result.Count != 1) { - info.ReplySync(localizer.Get( - result.Count > 1 ? - MSG.GENERIC_PLAYER_FOUND_MULTIPLE : - MSG.GENERIC_PLAYER_NOT_FOUND, info[1])); - return CommandResult.INVALID_ARGS; - } + var result = CommandResult.ERROR; + PlayerWrapper? subject = null; + await Server.NextFrameAsync(() => { + var target = new Target(info[1]); + var targetResult = target.GetTarget(null).Players; + if (targetResult.Count != 1) { + info.ReplySync(localizer.Get( + targetResult.Count > 1 ? + MSG.GENERIC_PLAYER_FOUND_MULTIPLE : + MSG.GENERIC_PLAYER_NOT_FOUND, info[1])); + result = CommandResult.INVALID_ARGS; + return; + } + + subject = new PlayerWrapper(targetResult[0]); + }); - var subject = result[0]; + if (subject == null) return result; if (info.ArgCount == 2 || !executor.HasFlags("@css/root")) { var (success, balance) = - await playerMgr.GetForPlayer(subject.SteamID, id); + await playerMgr.GetForPlayer(subject.Steam, id); if (!success) { - info.ReplySync(localizer.Get(MSG.COMMAND_BALANCE_NONE)); + info.ReplySync(localizer.Get(MSG.COMMAND_BALANCE_OTHER_NONE, + subject.Name ?? subject.Steam.ToString())); return CommandResult.SUCCESS; } info.ReplySync(localizer.Get( balance == 1 ? MSG.COMMAND_BALANCE_OTHER : - MSG.COMMAND_BALANCE_OTHER_PLURAL, balance)); + MSG.COMMAND_BALANCE_OTHER_PLURAL, + subject.Name ?? subject.Steam.ToString(), balance)); + return CommandResult.SUCCESS; } - - if (info.ArgCount != 3) return CommandResult.PRINT_USAGE; - if (!int.TryParse(info[2], out var amount)) { info.ReplySync(localizer.Get(MSG.COMMAND_INVALID_PARAM, info[2], "an integer")); return CommandResult.INVALID_ARGS; } - var pass = await playerMgr.SetForPlayer(subject.SteamID, id, amount); + var pass = await playerMgr.SetForPlayer(subject.Steam, id, amount); if (!pass) { info.ReplySync(localizer.Get(MSG.GENERIC_ERROR)); return CommandResult.ERROR; } - info.ReplySync(localizer.Get(MSG.COMMAND_BALANCE_SET, subject.PlayerName, - amount)); + info.ReplySync(localizer.Get(MSG.COMMAND_BALANCE_SET, + subject.Name ?? subject.Steam.ToString(), amount)); return CommandResult.SUCCESS; } } \ No newline at end of file diff --git a/src/CS2/Commands/CommandManager.cs b/src/CS2/Commands/CommandManager.cs index bc12148..7ead6a1 100644 --- a/src/CS2/Commands/CommandManager.cs +++ b/src/CS2/Commands/CommandManager.cs @@ -14,8 +14,8 @@ namespace Commands; public class CommandManager(IGangManager gangMgr, - IPlayerStatManager playerStatMgr, IStringLocalizer locale) - : MockCommandManager(locale), IPluginBehavior { + IPlayerStatManager playerStatMgr, IStringLocalizer testLocale) + : MockCommandManager(testLocale), IPluginBehavior { private BasePlugin? plugin; private bool hotReload; @@ -23,6 +23,8 @@ public void Start(BasePlugin? basePlugin, bool hotReload) { plugin = basePlugin; this.hotReload = hotReload; + if (basePlugin != null) Locale = basePlugin.Localizer; + RegisterCommand(new GangCommand(gangMgr, Locale)); RegisterCommand(new BalanceCommand(playerStatMgr, Locale)); } @@ -44,7 +46,7 @@ private void Server.NextFrameAsync(async () => { var result = await ProcessCommand(wrapper, wrappedInfo); if (result == CommandResult.PLAYER_ONLY) - executor?.PrintToChat(Locale.Get(MSG.GENERIC_PLAYER_ONLY)); + wrappedInfo.ReplySync(Locale.Get(MSG.GENERIC_PLAYER_ONLY)); }); } } \ No newline at end of file diff --git a/src/CS2/Gangs/PluginStringLocalizer.cs b/src/CS2/Gangs/PluginStringLocalizer.cs index 38f2e13..870a456 100644 --- a/src/CS2/Gangs/PluginStringLocalizer.cs +++ b/src/CS2/Gangs/PluginStringLocalizer.cs @@ -27,7 +27,10 @@ private LocalizedString GetString(string name) { // Check if the key exists try { var key = match.Groups[0].Value; - value = value.Replace(key, localizer[key[1..^1]].Value); + value = value.Replace(key, + key == "%prefix%" ? + this[key[1..^1]].Value : + this[key[1..^1]].Value.Trim()); } catch (NullReferenceException) { } return new LocalizedString(name, value); diff --git a/src/GangsAPI/Data/PlayerWrapper.cs b/src/GangsAPI/Data/PlayerWrapper.cs index ca8e064..a44aefa 100644 --- a/src/GangsAPI/Data/PlayerWrapper.cs +++ b/src/GangsAPI/Data/PlayerWrapper.cs @@ -3,6 +3,7 @@ using CounterStrikeSharp.API; using CounterStrikeSharp.API.Core; using CounterStrikeSharp.API.Modules.Admin; +using CounterStrikeSharp.API.Modules.Entities; namespace GangsAPI.Data; @@ -72,6 +73,9 @@ public PlayerWrapper WithFlags(params string[] flags) { public bool HasFlags(params string[] flags) { if (Data == null) return false; + if (Player != null) + return AdminManager.PlayerHasPermissions(new SteamID(Steam), flags); + foreach (var flag in flags) { if (!flag.StartsWith(USER_CHAR)) throw new ArgumentException( diff --git a/src/GangsImpl/Mock/MockCommandManager.cs b/src/GangsImpl/Mock/MockCommandManager.cs index 67dadce..a8bfc7a 100644 --- a/src/GangsImpl/Mock/MockCommandManager.cs +++ b/src/GangsImpl/Mock/MockCommandManager.cs @@ -8,15 +8,15 @@ namespace Mock; public class MockCommandManager(IStringLocalizer locale) : ICommandManager { - private readonly Dictionary commands = new(); - protected readonly IStringLocalizer Locale = locale; + protected readonly Dictionary Commands = new(); + protected IStringLocalizer Locale = locale; public virtual bool RegisterCommand(ICommand command) { - return command.Aliases.All(alias => commands.TryAdd(alias, command)); + return command.Aliases.All(alias => Commands.TryAdd(alias, command)); } public bool UnregisterCommand(ICommand command) { - return command.Aliases.All(alias => commands.Remove(alias)); + return command.Aliases.All(alias => Commands.Remove(alias)); } public async Task ProcessCommand(PlayerWrapper? executor, @@ -31,19 +31,18 @@ public async Task ProcessCommand(PlayerWrapper? executor, return await ProcessCommand(executor, info); } - public async Task ProcessCommand(PlayerWrapper? executor, - CommandInfoWrapper sourceInfo) { + public virtual async Task ProcessCommand( + PlayerWrapper? executor, CommandInfoWrapper sourceInfo) { if (sourceInfo.ArgCount == 0) return CommandResult.ERROR; var result = CommandResult.ERROR; - if (!commands.TryGetValue(sourceInfo[0], out var command)) { + if (!Commands.TryGetValue(sourceInfo[0], out var command)) { sourceInfo.ReplySync("Unknown command: " + sourceInfo[0]); return CommandResult.UNKNOWN_COMMAND; } if (!command.CanExecute(executor)) return CommandResult.NO_PERMISSION; - await Task.Run(async () => { result = await command.Execute(executor, sourceInfo); }); @@ -55,7 +54,7 @@ await Task.Run(async () => { case CommandResult.PRINT_USAGE: { foreach (var use in command.Usage) sourceInfo.ReplySync(Locale.Get(MSG.COMMAND_USAGE, - $"{command.Name} {use}")); + $"{sourceInfo[0]} {use}")); break; } } diff --git a/src/GangsTest/TestLocale/FormatTests.cs b/src/GangsTest/TestLocale/FormatTests.cs index 37103aa..79e1e20 100644 --- a/src/GangsTest/TestLocale/FormatTests.cs +++ b/src/GangsTest/TestLocale/FormatTests.cs @@ -1,4 +1,5 @@ using System.Text.RegularExpressions; +using CounterStrikeSharp.API.Modules.Utils; using GangsAPI; using Microsoft.Extensions.Localization; diff --git a/src/GangsTest/TestLocale/StringLocalizer.cs b/src/GangsTest/TestLocale/StringLocalizer.cs index 5d7702c..ff2f6ed 100644 --- a/src/GangsTest/TestLocale/StringLocalizer.cs +++ b/src/GangsTest/TestLocale/StringLocalizer.cs @@ -38,7 +38,10 @@ private LocalizedString GetString(string name) { // Check if the key exists try { var key = match.Groups[0].Value; - value = value.Replace(key, this[key[1..^1]].Value); + value = value.Replace(key, + key == "%prefix%" ? + this[key[1..^1]].Value : + this[key[1..^1]].Value.Trim()); } catch (NullReferenceException) { } return new LocalizedString(name, value);