diff --git a/Jailbreak.sln b/Jailbreak.sln index 4e9a7f23..6098dfce 100644 --- a/Jailbreak.sln +++ b/Jailbreak.sln @@ -26,6 +26,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Jailbreak.Rebel", "mod\Jail EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Jailbreak.Logs", "mod\Jailbreak.Logs\Jailbreak.Logs.csproj", "{CE6EC648-E7F9-4CE7-B28F-8C7995830F35}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Jailbreak.Debug", "mod\Jailbreak.Debug\Jailbreak.Debug.csproj", "{4F10E2B5-E8BB-4253-9BE6-9187575ADB13}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -68,6 +70,10 @@ Global {CE6EC648-E7F9-4CE7-B28F-8C7995830F35}.Debug|Any CPU.Build.0 = Debug|Any CPU {CE6EC648-E7F9-4CE7-B28F-8C7995830F35}.Release|Any CPU.ActiveCfg = Release|Any CPU {CE6EC648-E7F9-4CE7-B28F-8C7995830F35}.Release|Any CPU.Build.0 = Release|Any CPU + {4F10E2B5-E8BB-4253-9BE6-9187575ADB13}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {4F10E2B5-E8BB-4253-9BE6-9187575ADB13}.Debug|Any CPU.Build.0 = Debug|Any CPU + {4F10E2B5-E8BB-4253-9BE6-9187575ADB13}.Release|Any CPU.ActiveCfg = Release|Any CPU + {4F10E2B5-E8BB-4253-9BE6-9187575ADB13}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(NestedProjects) = preSolution {9135CCC9-66C5-4A9C-AE3C-91475B5F0437} = {177DA48D-8306-4102-918D-992569878581} @@ -79,5 +85,6 @@ Global {FC2D6F50-BCFF-41E6-A965-6C73CC01C3BF} = {CDCDE44E-01D2-4B76-99DA-A57E1E956038} {CB2391A1-6CDD-496F-B8D6-674FD6268038} = {36BA84C0-291C-4930-A7C6-97CDF8F7F0D7} {CE6EC648-E7F9-4CE7-B28F-8C7995830F35} = {36BA84C0-291C-4930-A7C6-97CDF8F7F0D7} + {4F10E2B5-E8BB-4253-9BE6-9187575ADB13} = {36BA84C0-291C-4930-A7C6-97CDF8F7F0D7} EndGlobalSection EndGlobal diff --git a/lang/Jailbreak.English/Generic/GenericCommandNotifications.cs b/lang/Jailbreak.English/Generic/GenericCommandNotifications.cs new file mode 100644 index 00000000..f246b231 --- /dev/null +++ b/lang/Jailbreak.English/Generic/GenericCommandNotifications.cs @@ -0,0 +1,34 @@ +using CounterStrikeSharp.API.Modules.Utils; +using Jailbreak.Formatting.Base; +using Jailbreak.Formatting.Core; +using Jailbreak.Formatting.Logistics; +using Jailbreak.Formatting.Objects; +using Jailbreak.Formatting.Views; + +namespace Jailbreak.English.Generic; + +public class GenericCommandNotifications : IGenericCommandNotifications, ILanguage +{ + public static FormatObject PREFIX = + new HiddenFormatObject($" {ChatColors.Darkred}[{ChatColors.LightRed}JB{ChatColors.Darkred}]") + { + // Hide in panorama and center text + Plain = false, + Panorama = false, + Chat = true, + }; + + public IView PlayerNotFound(string query) + { + return new SimpleView(writer => + writer + .Line(PREFIX, $"Player '{query}' not found!")); + } + + public IView PlayerFoundMultiple(string query) + { + return new SimpleView(writer => + writer + .Line(PREFIX, $"Multiple players found for '{query}'!")); + } +} \ No newline at end of file diff --git a/mod/Jailbreak.Debug/DebugCommand.cs b/mod/Jailbreak.Debug/DebugCommand.cs new file mode 100644 index 00000000..32532b9a --- /dev/null +++ b/mod/Jailbreak.Debug/DebugCommand.cs @@ -0,0 +1,46 @@ +using CounterStrikeSharp.API.Core; +using CounterStrikeSharp.API.Modules.Admin; +using CounterStrikeSharp.API.Modules.Commands; +using Jailbreak.Debug.Subcommands; +using Jailbreak.Formatting.Views; +using Jailbreak.Public.Behaviors; + +namespace Jailbreak.Debug; + +// css_debug [subcommand] [args] -> subcommand [args] +public class DebugCommand : IPluginBehavior +{ + private readonly Dictionary commands = new(); + + public DebugCommand(IServiceProvider serviceProvider) + { + commands.Add("markrebel", new MarkRebel(serviceProvider)); + } + + [RequiresPermissions("@css/root")] + public void Command_Debug(CCSPlayerController? executor, CommandInfo info) + { + if (executor == null) + { + return; + } + + if (info.ArgCount == 1) + { + foreach (var command in commands) + { + info.ReplyToCommand(command.Key); + } + + return; + } + + if (!commands.TryGetValue(info.GetArg(1), out var subcommand)) + { + info.ReplyToCommand("Invalid subcommand"); + return; + } + + subcommand.OnCommand(executor, new WrappedInfo(info)); + } +} \ No newline at end of file diff --git a/mod/Jailbreak.Debug/DebugServiceExtension.cs b/mod/Jailbreak.Debug/DebugServiceExtension.cs new file mode 100644 index 00000000..5f1ed04e --- /dev/null +++ b/mod/Jailbreak.Debug/DebugServiceExtension.cs @@ -0,0 +1,12 @@ +using Jailbreak.Public.Extensions; +using Microsoft.Extensions.DependencyInjection; + +namespace Jailbreak.Debug; + +public static class DebugServiceExtension +{ + public static void AddJailbreakDebug(this IServiceCollection services) + { + services.AddPluginBehavior(); + } +} \ No newline at end of file diff --git a/mod/Jailbreak.Debug/Jailbreak.Debug.csproj b/mod/Jailbreak.Debug/Jailbreak.Debug.csproj new file mode 100644 index 00000000..e549f3ef --- /dev/null +++ b/mod/Jailbreak.Debug/Jailbreak.Debug.csproj @@ -0,0 +1,14 @@ + + + + net7.0 + enable + enable + + + + + + + + diff --git a/mod/Jailbreak.Debug/Subcommands/AbstractCommand.cs b/mod/Jailbreak.Debug/Subcommands/AbstractCommand.cs new file mode 100644 index 00000000..010ec189 --- /dev/null +++ b/mod/Jailbreak.Debug/Subcommands/AbstractCommand.cs @@ -0,0 +1,145 @@ +using CounterStrikeSharp.API.Core; +using CounterStrikeSharp.API.Modules.Admin; +using CounterStrikeSharp.API.Modules.Commands; +using CounterStrikeSharp.API.Modules.Commands.Targeting; +using Jailbreak.Formatting.Extensions; +using Jailbreak.Formatting.Views; +using Microsoft.Extensions.DependencyInjection; + +namespace Jailbreak.Debug.Subcommands; + +public abstract class AbstractCommand +{ + protected IServiceProvider services; + private IGenericCommandNotifications lang; + + protected AbstractCommand(IServiceProvider services) + { + this.services = services; + lang = services.GetRequiredService(); + } + + public abstract void OnCommand(CCSPlayerController? executor, WrappedInfo info); + + protected TargetResult? GetTarget(WrappedInfo command, int argIndex = 1, + Func? predicate = null) + { + return GetTarget(command.info, argIndex + 1, predicate); + } + + protected TargetResult? GetVulnerableTarget(WrappedInfo command, int argIndex = 1, + Func? predicate = null) + { + return GetVulnerableTarget(command.info, argIndex + 1, predicate); + } + + protected TargetResult? GetTarget(CommandInfo command, int argIndex = 1, + Func? predicate = null) + { + var matches = command.GetArgTargetResult(argIndex); + + matches.Players = matches.Players.Where(player => + player is { IsValid: true, Connected: PlayerConnectedState.PlayerConnected }).ToList(); + if (predicate != null) + matches.Players = matches.Players.Where(predicate).ToList(); + + if (!matches.Any()) + { + if (command.CallingPlayer != null) + lang.PlayerNotFound(command.GetArg(argIndex)).ToPlayerChat(command.CallingPlayer); + return null; + } + + if (matches.Count() > 1 && command.GetArg(argIndex).StartsWith('@')) + return matches; + + if (matches.Count() == 1 || !command.GetArg(argIndex).StartsWith('@')) + return matches; + + if (command.CallingPlayer != null) + lang.PlayerFoundMultiple(command.GetArg(argIndex)).ToPlayerChat(command.CallingPlayer); + return null; + } + + internal TargetResult? GetVulnerableTarget(CommandInfo command, int argIndex = 1, + Func? predicate = null) + { + return GetTarget(command, argIndex, + (p) => command.CallingPlayer == null || + command.CallingPlayer.CanTarget(p) && (predicate == null || predicate(p))); + } + + internal TargetResult? GetSingleTarget(CommandInfo command, int argIndex = 1) + { + var matches = command.GetArgTargetResult(argIndex); + + if (!matches.Any()) + { + if (command.CallingPlayer != null) + lang.PlayerNotFound(command.GetArg(argIndex)).ToPlayerChat(command.CallingPlayer); + return null; + } + + if (matches.Count() > 1) + { + if (command.CallingPlayer != null) + lang.PlayerFoundMultiple(command.GetArg(argIndex)).ToPlayerChat(command.CallingPlayer); + return null; + } + + return matches; + } + + internal string GetTargetLabel(CommandInfo info, int argIndex = 1) + { + switch (info.GetArg(argIndex)) + { + case "@all": + return "all players"; + case "@bots": + return "all bots"; + case "@humans": + return "all humans"; + case "@alive": + return "alive players"; + case "@dead": + return "dead players"; + case "@!me": + return "all except self"; + case "@me": + return info.CallingPlayer == null ? "Console" : info.CallingPlayer.PlayerName; + case "@ct": + return "all CTs"; + case "@t": + return "all Ts"; + case "@spec": + return "all spectators"; + default: + var player = info.GetArgTargetResult(argIndex).FirstOrDefault(); + if (player != null) + return player.PlayerName; + return "unknown"; + } + } + + + internal string GetTargetLabels(CommandInfo info, int argIndex = 1) + { + string label = GetTargetLabel(info, argIndex); + if (label.ToLower().EndsWith("s")) + return label + "'"; + return label + "'s"; + } +} + +public static class CommandExtensions + +{ + internal static bool CanTarget(this CCSPlayerController controller, CCSPlayerController target) + { + if (!target.IsValid) return false; + if (target.Connected != PlayerConnectedState.PlayerConnected) return false; + if (target.IsBot || target.IsHLTV) return true; + return AdminManager.CanPlayerTarget(controller, target); + } +} \ No newline at end of file diff --git a/mod/Jailbreak.Debug/Subcommands/MarkRebel.cs b/mod/Jailbreak.Debug/Subcommands/MarkRebel.cs new file mode 100644 index 00000000..7e735a43 --- /dev/null +++ b/mod/Jailbreak.Debug/Subcommands/MarkRebel.cs @@ -0,0 +1,45 @@ +using CounterStrikeSharp.API; +using CounterStrikeSharp.API.Core; +using CounterStrikeSharp.API.Modules.Commands; +using Jailbreak.Formatting.Views; +using Jailbreak.Public.Mod.Rebel; +using Microsoft.Extensions.DependencyInjection; + +namespace Jailbreak.Debug.Subcommands; + +// css_markrebel [player] +public class MarkRebel : AbstractCommand +{ + public MarkRebel(IServiceProvider services) : base(services) + { + } + + public override void OnCommand(CCSPlayerController? executor, WrappedInfo info) + { + if (info.ArgCount == 1) + { + info.ReplyToCommand("Specify target?"); + return; + } + + var target = GetVulnerableTarget(info); + if (target == null) + return; + + var duration = 120; + if(info.ArgCount == 3) + { + if (!int.TryParse(info.GetArg(2), out duration)) + { + info.ReplyToCommand("Invalid duration"); + return; + } + } + + foreach (var player in target.Players) + { + services.GetRequiredService().MarkRebel(player, duration); + } + info.ReplyToCommand($"Marked {target.Players.Count()} players as rebels for {duration} seconds"); + } +} \ No newline at end of file diff --git a/mod/Jailbreak.Debug/Subcommands/WrappedInfo.cs b/mod/Jailbreak.Debug/Subcommands/WrappedInfo.cs new file mode 100644 index 00000000..f64af2de --- /dev/null +++ b/mod/Jailbreak.Debug/Subcommands/WrappedInfo.cs @@ -0,0 +1,29 @@ +using CounterStrikeSharp.API.Core; +using CounterStrikeSharp.API.Modules.Commands; + +namespace Jailbreak.Debug.Subcommands; + +public class WrappedInfo +{ + public readonly CommandInfo info; + + public WrappedInfo(CommandInfo info) + { + this.info = info; + } + + public CCSPlayerController? CallingPlayer => info.CallingPlayer; + + public IntPtr Handle => info.Handle; + + public int ArgCount => info.ArgCount - 1; + + public string ArgString => info.ArgString[(info.ArgString.IndexOf(' ') + 1)..]; + + public string GetCommandString => info.GetCommandString[(info.GetCommandString.IndexOf(' ') + 1)..]; + + public string ArgByIndex(int index) => info.ArgByIndex(index + 1); + public string GetArg(int index) => info.GetArg(index + 1); + + public void ReplyToCommand(string message, bool console = false) => info.ReplyToCommand(message, console); +} \ No newline at end of file diff --git a/mod/Jailbreak.Logs/LogsServiceExtension.cs b/mod/Jailbreak.Logs/LogsServiceExtension.cs index 815ad70d..4c626273 100644 --- a/mod/Jailbreak.Logs/LogsServiceExtension.cs +++ b/mod/Jailbreak.Logs/LogsServiceExtension.cs @@ -6,7 +6,7 @@ namespace Jailbreak.Logs; public static class LogsServiceExtension { - public static void AddLogsService(this IServiceCollection services) + public static void AddJailbreakLogs(this IServiceCollection services) { services.AddPluginBehavior(); diff --git a/mod/Jailbreak.Rebel/RebelManager.cs b/mod/Jailbreak.Rebel/RebelManager.cs index 9fadd81f..e971b2c5 100644 --- a/mod/Jailbreak.Rebel/RebelManager.cs +++ b/mod/Jailbreak.Rebel/RebelManager.cs @@ -96,7 +96,7 @@ public long GetRebelTimeLeft(CCSPlayerController player) return 0; } - public bool MarkRebel(CCSPlayerController player, long time) + public bool MarkRebel(CCSPlayerController player, long time = 120) { if (!rebelTimes.ContainsKey(player)) { diff --git a/public/Jailbreak.Formatting/Logistics/LanguageConfig.cs b/public/Jailbreak.Formatting/Logistics/LanguageConfig.cs index bc07c36a..3848bfc8 100644 --- a/public/Jailbreak.Formatting/Logistics/LanguageConfig.cs +++ b/public/Jailbreak.Formatting/Logistics/LanguageConfig.cs @@ -15,6 +15,10 @@ public LanguageConfig(IServiceCollection collection) _collection = collection; } + public void WithGenericCommand() + where TGenericCommand : class, ILanguage, IGenericCommandNotifications + => _collection.AddSingleton(); + public void WithRatio() where TRatio : class, ILanguage, IRatioNotifications => _collection.AddSingleton(); diff --git a/public/Jailbreak.Formatting/Views/IGenericCommandNotifications.cs b/public/Jailbreak.Formatting/Views/IGenericCommandNotifications.cs new file mode 100644 index 00000000..e7250481 --- /dev/null +++ b/public/Jailbreak.Formatting/Views/IGenericCommandNotifications.cs @@ -0,0 +1,9 @@ +using Jailbreak.Formatting.Base; + +namespace Jailbreak.Formatting.Views; + +public interface IGenericCommandNotifications +{ + public IView PlayerNotFound(string query); + public IView PlayerFoundMultiple(string query); +} \ No newline at end of file diff --git a/public/Jailbreak.Public/Mod/Rebel/IRebelService.cs b/public/Jailbreak.Public/Mod/Rebel/IRebelService.cs index 87363d8c..61be0744 100644 --- a/public/Jailbreak.Public/Mod/Rebel/IRebelService.cs +++ b/public/Jailbreak.Public/Mod/Rebel/IRebelService.cs @@ -13,7 +13,7 @@ bool IsRebel(CCSPlayerController player) long GetRebelTimeLeft(CCSPlayerController player); - bool MarkRebel(CCSPlayerController player, long time); + bool MarkRebel(CCSPlayerController player, long time = 120); void UnmarkRebel(CCSPlayerController player); } \ No newline at end of file diff --git a/src/Jailbreak/Jailbreak.csproj b/src/Jailbreak/Jailbreak.csproj index c4f3890a..2a615055 100644 --- a/src/Jailbreak/Jailbreak.csproj +++ b/src/Jailbreak/Jailbreak.csproj @@ -33,6 +33,7 @@ + diff --git a/src/Jailbreak/JailbreakServiceCollection.cs b/src/Jailbreak/JailbreakServiceCollection.cs index 99a8ef80..d1046809 100644 --- a/src/Jailbreak/JailbreakServiceCollection.cs +++ b/src/Jailbreak/JailbreakServiceCollection.cs @@ -3,6 +3,8 @@ using CounterStrikeSharp.API.Core; using Jailbreak.Config; +using Jailbreak.Debug; +using Jailbreak.English.Generic; using Jailbreak.English.Rebel; using Jailbreak.English.Teams; using Jailbreak.English.Warden; @@ -33,14 +35,16 @@ public void ConfigureServices(IServiceCollection serviceCollection) serviceCollection.AddTransient(); serviceCollection.AddJailbreakGeneric(); - serviceCollection.AddLogsService(); + serviceCollection.AddJailbreakLogs(); serviceCollection.AddJailbreakWarden(); serviceCollection.AddJailbreakTeams(); serviceCollection.AddJailbreakRebel(); + serviceCollection.AddJailbreakDebug(); // Add in english localization serviceCollection.AddLanguage(config => { + config.WithGenericCommand(); config.WithRatio(); config.WithWarden(); config.WithRebel();