Skip to content

Commit

Permalink
Add balance command
Browse files Browse the repository at this point in the history
  • Loading branch information
MSWS committed Sep 8, 2024
1 parent b83dcc6 commit d8f22c0
Show file tree
Hide file tree
Showing 15 changed files with 286 additions and 31 deletions.
31 changes: 27 additions & 4 deletions lang/en.json
Original file line number Diff line number Diff line change
@@ -1,10 +1,33 @@
{
"prefix": "{red}GANGS {darkred}> {grey}",
"command.gang.not_in_gang": "%prefix%You are not in a gang. Type {gold}/gang create [name]{grey} to create one.",
"generic.player.not_found": "%prefix%Could not find a player using {darkred}{0}{grey}.",
"color.default": "{grey}",
"color.emph": "{white}",
"color.number": "{yellow}",
"color.special": "{lightblue}",
"color.command": "{blue}",
"color.currency": "{gold}",
"color.target": "{green}",
"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}.",
"command.balance.none": "%prefix%You have no %currency.player.plural%.",
"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.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!",
"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.",
"generic.no_permission.rank": "%prefix%{red}You must be {darkred}{0}{red} to use this command."
"generic.no_permission.rank": "%prefix%{red}You must be {darkred}{0}{red} to use this command.",
"generic.error": "%prefix%%color.error%An unknown error occured.",
"generic.error.info": "%prefix%%color.error%An error occured: {0}.",
"currency.player": "credit",
"currency.gang": "%currency.player%",
"currency.player.plural": "credits",
"currency.gang.plural": "%currency.player.plural%"
}
96 changes: 96 additions & 0 deletions src/CS2/Commands/BalanceCommand.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
using CounterStrikeSharp.API.Core;
using CounterStrikeSharp.API.Modules.Commands.Targeting;
using CounterStrikeSharp.API.Modules.Utils;
using GangsAPI;
using GangsAPI.Data;
using GangsAPI.Data.Command;
using GangsAPI.Services.Commands;
using GangsAPI.Services.Player;
using Microsoft.Extensions.Localization;
using Stats;

namespace Commands;

public class BalanceCommand(IPlayerStatManager playerMgr,
IStringLocalizer testLocalizer) : ICommand {
public string Name => "css_balance";

public string[] Usage => ["", "<player>", "<player> <amount>"];
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;
}

public async Task<CommandResult> Execute(PlayerWrapper? executor,
CommandInfoWrapper info) {
if (executor == null) return CommandResult.PLAYER_ONLY;

if (info.ArgCount == 1 || !executor.HasFlags("@css/ban")) {
var (success, balance) =
await playerMgr.GetForPlayer<int>(executor.Steam, id);

if (!success) {
info.ReplySync(localizer.Get(MSG.COMMAND_BALANCE_NONE));
return CommandResult.SUCCESS;
}

info.ReplySync(localizer.Get(
balance == 1 ? MSG.COMMAND_BALANCE : MSG.COMMAND_BALANCE_PLURAL,
balance));
return CommandResult.SUCCESS;
}

// 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 subject = result[0];

if (info.ArgCount == 2 || !executor.HasFlags("@css/root")) {
var (success, balance) =
await playerMgr.GetForPlayer<int>(subject.SteamID, id);

if (!success) {
info.ReplySync(localizer.Get(MSG.COMMAND_BALANCE_NONE));
return CommandResult.SUCCESS;
}

info.ReplySync(localizer.Get(
balance == 1 ?
MSG.COMMAND_BALANCE_OTHER :
MSG.COMMAND_BALANCE_OTHER_PLURAL, balance));
}


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);
if (!pass) {
info.ReplySync(localizer.Get(MSG.GENERIC_ERROR));
return CommandResult.ERROR;
}

info.ReplySync(localizer.Get(MSG.COMMAND_BALANCE_SET, subject.PlayerName,
amount));
return CommandResult.SUCCESS;
}
}
8 changes: 6 additions & 2 deletions src/CS2/Commands/CommandManager.cs
Original file line number Diff line number Diff line change
@@ -1,17 +1,20 @@
using CounterStrikeSharp.API;
using Commands.Gang;
using CounterStrikeSharp.API;
using CounterStrikeSharp.API.Core;
using CounterStrikeSharp.API.Modules.Commands;
using GangsAPI;
using GangsAPI.Data;
using GangsAPI.Data.Command;
using GangsAPI.Services.Commands;
using GangsAPI.Services.Gang;
using GangsAPI.Services.Player;
using Microsoft.Extensions.Localization;
using Mock;

namespace Commands;

public class CommandManager(IGangManager gangMgr, IStringLocalizer locale)
public class CommandManager(IGangManager gangMgr,
IPlayerStatManager playerStatMgr, IStringLocalizer locale)
: MockCommandManager(locale), IPluginBehavior {
private BasePlugin? plugin;
private bool hotReload;
Expand All @@ -21,6 +24,7 @@ public void Start(BasePlugin? basePlugin, bool hotReload) {
this.hotReload = hotReload;

RegisterCommand(new GangCommand(gangMgr, Locale));
RegisterCommand(new BalanceCommand(playerStatMgr, Locale));
}

public override bool RegisterCommand(ICommand command) {
Expand Down
1 change: 1 addition & 0 deletions src/CS2/Commands/Commands.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
<ItemGroup>
<ProjectReference Include="..\..\GangsAPI\GangsAPI.csproj" />
<ProjectReference Include="..\..\GangsImpl\Mock\Mock.csproj" />
<ProjectReference Include="..\..\GangsImpl\Stats\Stats.csproj" />
</ItemGroup>

</Project>
2 changes: 1 addition & 1 deletion src/CS2/Commands/GangCommand.cs
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ public async Task<CommandResult> Execute(PlayerWrapper? executor,
var gang = await gangMgr.GetGang(executor.Steam);

if (gang == null) {
info.ReplySync(myLocale[NOT_IN_GANG.Key()]);
info.ReplySync(myLocale[COMMAND_GANG_NOTINGANG.Key()]);
return CommandResult.SUCCESS;
}

Expand Down
1 change: 1 addition & 0 deletions src/GangsAPI/Data/Command/CommandResult.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ public enum CommandResult {
/// no sufficient arguments
/// </summary>
INVALID_ARGS,
PRINT_USAGE,

/// <summary>
/// The executor of the command did not have
Expand Down
76 changes: 64 additions & 12 deletions src/GangsAPI/MSG.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,33 +3,85 @@
namespace GangsAPI;

public enum MSG {
NOT_IN_GANG,
COMMAND_GANG_NOTINGANG,
COMMAND_BALANCE_NONE,
COMMAND_BALANCE,
COMMAND_BALANCE_PLURAL,
COMMAND_BALANCE_OTHER_NONE,
COMMAND_BALANCE_OTHER,
COMMAND_BALANCE_OTHER_PLURAL,
COMMAND_BALANCE_SET,
COMMAND_USAGE,
COMMAND_INVALID_PARAM,
PREFIX,
GENERIC_PLAYER_NOT_FOUND,
GENERIC_PLAYER_FOUND_MULTIPLE,
SOONTM,
GENERIC_PLAYER_ONLY,
GENERIC_NOPERM,
GENERIC_NOPERM_NODE,
GENERIC_NOPERM_RANK
}
GENERIC_NOPERM_RANK,
GENERIC_ERROR,
GENERIC_ERROR_INFO,
PLAYER_CURRENCY,
PLAYER_CURRENCY_PLURAL,
GANG_CURRENCY,
GANG_CURRENCY_PLURAL,
COLOR_DEFAULT,
COLOR_EMPHASIS,
COLOR_NUMBERL,
COLOR_SPECIAL,
COLOR_COMMAND,
COLOR_CURRENCY,
COLOR_TARGET, }

public static class LocaleExtensions {
public static string Key(this MSG msg) {
return msg switch {
MSG.NOT_IN_GANG => "command.gang.not_in_gang",
MSG.PREFIX => "prefix",
MSG.GENERIC_PLAYER_NOT_FOUND => "generic.player.not_found",
MSG.SOONTM => "generic.soontm",
MSG.GENERIC_PLAYER_ONLY => "generic.player.only",
MSG.GENERIC_NOPERM => "generic.no_permission",
MSG.GENERIC_NOPERM_NODE => "generic.no_permission.node",
MSG.GENERIC_NOPERM_RANK => "generic.no_permission.rank",
MSG.COMMAND_GANG_NOTINGANG => "command.gang.not_in_gang",
MSG.COMMAND_BALANCE_NONE => "command.balance.none",
MSG.COMMAND_BALANCE => "command.balance",
MSG.COMMAND_BALANCE_OTHER => "command.balance.other",
MSG.COMMAND_BALANCE_OTHER_PLURAL => "command.balance.other.plural",
MSG.COMMAND_BALANCE_OTHER_NONE => "command.balance.other.none",
MSG.COMMAND_BALANCE_PLURAL => "command.balance.plural",
MSG.COMMAND_BALANCE_SET => "command.balance.set",
MSG.COMMAND_USAGE => "command.usage",
MSG.COMMAND_INVALID_PARAM => "command.invalid_parameter",
MSG.PREFIX => "prefix",
MSG.GENERIC_PLAYER_NOT_FOUND => "generic.player.not_found",
MSG.SOONTM => "generic.soontm",
MSG.GENERIC_PLAYER_ONLY => "generic.player.only",
MSG.GENERIC_NOPERM => "generic.no_permission",
MSG.GENERIC_NOPERM_NODE => "generic.no_permission.node",
MSG.GENERIC_NOPERM_RANK => "generic.no_permission.rank",
MSG.GENERIC_PLAYER_FOUND_MULTIPLE => "generic.player.found_multiple",
MSG.GENERIC_ERROR => "generic.error",
MSG.GENERIC_ERROR_INFO => "generic.error.info",
MSG.PLAYER_CURRENCY => "currency.player",
MSG.PLAYER_CURRENCY_PLURAL => "currency.player.plural",
MSG.GANG_CURRENCY => "currency.gang",
MSG.GANG_CURRENCY_PLURAL => "currency.gang.plural",
MSG.COLOR_DEFAULT => "color.default",
MSG.COLOR_EMPHASIS => "color.emph",
MSG.COLOR_NUMBERL => "color.number",
MSG.COLOR_SPECIAL => "color.special",
MSG.COLOR_COMMAND => "color.command",
MSG.COLOR_CURRENCY => "color.currency",
MSG.COLOR_TARGET => "color.target",


_ => throw new ArgumentOutOfRangeException(nameof(msg), msg, null)
};
}

public static string Get(this IStringLocalizer localizer, MSG msg,
params object[] args) {
return localizer[msg.Key(), args].Value;
try { return localizer[msg.Key(), args].Value; } catch (FormatException e) {
throw new FormatException(
$"There was an error formatting {msg.Key()} ({localizer[msg.Key()]})",
e);
return msg.Key();

Check warning on line 84 in src/GangsAPI/MSG.cs

View workflow job for this annotation

GitHub Actions / build

Unreachable code detected

Check warning on line 84 in src/GangsAPI/MSG.cs

View workflow job for this annotation

GitHub Actions / build

Unreachable code detected

Check warning on line 84 in src/GangsAPI/MSG.cs

View workflow job for this annotation

GitHub Actions / build (6.0.x)

Unreachable code detected

Check warning on line 84 in src/GangsAPI/MSG.cs

View workflow job for this annotation

GitHub Actions / build (6.0.x)

Unreachable code detected

Check warning on line 84 in src/GangsAPI/MSG.cs

View workflow job for this annotation

GitHub Actions / test (8.0.x)

Unreachable code detected

Check warning on line 84 in src/GangsAPI/MSG.cs

View workflow job for this annotation

GitHub Actions / test (8.0.x)

Unreachable code detected

Check warning on line 84 in src/GangsAPI/MSG.cs

View workflow job for this annotation

GitHub Actions / build (7.0.x)

Unreachable code detected

Check warning on line 84 in src/GangsAPI/MSG.cs

View workflow job for this annotation

GitHub Actions / build (7.0.x)

Unreachable code detected

Check warning on line 84 in src/GangsAPI/MSG.cs

View workflow job for this annotation

GitHub Actions / test (9.0.x)

Unreachable code detected

Check warning on line 84 in src/GangsAPI/MSG.cs

View workflow job for this annotation

GitHub Actions / test (9.0.x)

Unreachable code detected

Check warning on line 84 in src/GangsAPI/MSG.cs

View workflow job for this annotation

GitHub Actions / build (8.0.x)

Unreachable code detected

Check warning on line 84 in src/GangsAPI/MSG.cs

View workflow job for this annotation

GitHub Actions / build (8.0.x)

Unreachable code detected

Check warning on line 84 in src/GangsAPI/MSG.cs

View workflow job for this annotation

GitHub Actions / build (9.0.x)

Unreachable code detected

Check warning on line 84 in src/GangsAPI/MSG.cs

View workflow job for this annotation

GitHub Actions / build (9.0.x)

Unreachable code detected
}
}
}
8 changes: 7 additions & 1 deletion src/GangsAPI/Services/Commands/ICommand.cs
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
using GangsAPI.Data;
using GangsAPI.Data.Command;
using Microsoft.Extensions.Localization;

namespace GangsAPI.Services.Commands;

public interface ICommand : IPluginBehavior {
string Name { get; }

string? Description => null;
string Usage => "";
string[] Usage => [];
string[] RequiredFlags => [];
string[] RequiredGroups => [];
string[] Aliases => [Name];
Expand All @@ -21,4 +22,9 @@ bool CanExecute(PlayerWrapper? executor) {
}

Task<CommandResult> Execute(PlayerWrapper? executor, CommandInfoWrapper info);

// void PrintUsage(IStringLocalizer localizer, PlayerWrapper? executor) {
// foreach (var use in Usage)
// localizer.Get(MSG.COMMAND_USAGE, $"{Name} {use}");
// }
}
13 changes: 11 additions & 2 deletions src/GangsImpl/Mock/MockCommandManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -48,8 +48,17 @@ await Task.Run(async () => {
result = await command.Execute(executor, sourceInfo);
});

if (result == CommandResult.PLAYER_ONLY)
sourceInfo.ReplySync(Locale.Get(MSG.GENERIC_PLAYER_ONLY));
switch (result) {
case CommandResult.PLAYER_ONLY:
sourceInfo.ReplySync(Locale.Get(MSG.GENERIC_PLAYER_ONLY));
break;
case CommandResult.PRINT_USAGE: {
foreach (var use in command.Usage)
sourceInfo.ReplySync(Locale.Get(MSG.COMMAND_USAGE,
$"{command.Name} {use}"));
break;
}
}

return result;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
using Commands;
using GangsAPI;
using GangsAPI.Data.Command;
using GangsAPI.Services.Commands;
using GangsAPI.Services.Player;
using GangsTest.TestLocale;
using Microsoft.Extensions.Localization;
using Stats;

namespace GangsTest.API.Services.Commands.Command.Concrete;

public class BalanceTests(ICommandManager commands, IPlayerStatManager statMgr,
IStringLocalizer locale) : TestParent(commands,
new BalanceCommand(statMgr, StringLocalizer.Instance)) {
private static readonly string STAT_ID = new BalanceStat().StatId;

[Fact]
public async Task None() {
Assert.Equal("css_balance", Command.Name);
Assert.Equal(CommandResult.SUCCESS,
await Commands.ProcessCommand(TestPlayer, Command.Name));
Assert.Contains(locale.Get(MSG.COMMAND_BALANCE_NONE),
TestPlayer.ConsoleOutput);
}

[Fact]
public async Task One() {
await statMgr.SetForPlayer(TestPlayer.Steam, STAT_ID, 1);
Assert.Equal(CommandResult.SUCCESS,
await Commands.ProcessCommand(TestPlayer, Command.Name));
Assert.Contains(locale.Get(MSG.COMMAND_BALANCE, 1),
TestPlayer.ConsoleOutput);
}

[Theory]
[InlineData(2)]
[InlineData(5)]
[InlineData(10000)]
[InlineData(-1)]
[InlineData(-1000)]
public async Task Multiple(int bal) {
await statMgr.SetForPlayer(TestPlayer.Steam, STAT_ID, bal);
Assert.Equal(CommandResult.SUCCESS,
await Commands.ProcessCommand(TestPlayer, Command.Name));
Assert.Contains(locale.Get(MSG.COMMAND_BALANCE_PLURAL, bal),
TestPlayer.ConsoleOutput);
}
}
Loading

0 comments on commit d8f22c0

Please sign in to comment.