diff --git a/.github/workflows/nightly.yml b/.github/workflows/nightly.yml index e15cf39c..636085c6 100644 --- a/.github/workflows/nightly.yml +++ b/.github/workflows/nightly.yml @@ -27,7 +27,7 @@ jobs: - uses: actions/upload-artifact@v4.0.0 with: - name: jailbreak-nightly-${{ github.run_id }} + name: jailbreak-nightly path: build # If build didn't put any artifacts in the build folder, consider it an error if-no-files-found: error diff --git a/Jailbreak.sln b/Jailbreak.sln index 7dfd86e9..9570efb8 100644 --- a/Jailbreak.sln +++ b/Jailbreak.sln @@ -16,6 +16,12 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Jailbreak.Generic", "src\Ja EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Jailbreak.Teams", "mod\Jailbreak.Teams\Jailbreak.Teams.csproj", "{28EE05E4-8FE3-4CC6-AA03-0C533EFBFBF2}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Jailbreak.Formatting", "public\Jailbreak.Formatting\Jailbreak.Formatting.csproj", "{446E0B6F-E4FE-45E6-BD9B-BD943698327A}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "lang", "lang", "{CDCDE44E-01D2-4B76-99DA-A57E1E956038}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Jailbreak.English", "lang\Jailbreak.English\Jailbreak.English.csproj", "{FC2D6F50-BCFF-41E6-A965-6C73CC01C3BF}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -42,6 +48,14 @@ Global {28EE05E4-8FE3-4CC6-AA03-0C533EFBFBF2}.Debug|Any CPU.Build.0 = Debug|Any CPU {28EE05E4-8FE3-4CC6-AA03-0C533EFBFBF2}.Release|Any CPU.ActiveCfg = Release|Any CPU {28EE05E4-8FE3-4CC6-AA03-0C533EFBFBF2}.Release|Any CPU.Build.0 = Release|Any CPU + {446E0B6F-E4FE-45E6-BD9B-BD943698327A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {446E0B6F-E4FE-45E6-BD9B-BD943698327A}.Debug|Any CPU.Build.0 = Debug|Any CPU + {446E0B6F-E4FE-45E6-BD9B-BD943698327A}.Release|Any CPU.ActiveCfg = Release|Any CPU + {446E0B6F-E4FE-45E6-BD9B-BD943698327A}.Release|Any CPU.Build.0 = Release|Any CPU + {FC2D6F50-BCFF-41E6-A965-6C73CC01C3BF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {FC2D6F50-BCFF-41E6-A965-6C73CC01C3BF}.Debug|Any CPU.Build.0 = Debug|Any CPU + {FC2D6F50-BCFF-41E6-A965-6C73CC01C3BF}.Release|Any CPU.ActiveCfg = Release|Any CPU + {FC2D6F50-BCFF-41E6-A965-6C73CC01C3BF}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(NestedProjects) = preSolution {9135CCC9-66C5-4A9C-AE3C-91475B5F0437} = {177DA48D-8306-4102-918D-992569878581} @@ -49,5 +63,7 @@ Global {E73417E7-D397-415B-B96F-BF43DAC511B8} = {36BA84C0-291C-4930-A7C6-97CDF8F7F0D7} {1D9CC1AC-4ABC-41A3-8CC7-6FB17E864C3F} = {177DA48D-8306-4102-918D-992569878581} {28EE05E4-8FE3-4CC6-AA03-0C533EFBFBF2} = {36BA84C0-291C-4930-A7C6-97CDF8F7F0D7} + {446E0B6F-E4FE-45E6-BD9B-BD943698327A} = {59311734-3648-43C2-B43C-385718B0D103} + {FC2D6F50-BCFF-41E6-A965-6C73CC01C3BF} = {CDCDE44E-01D2-4B76-99DA-A57E1E956038} EndGlobalSection EndGlobal diff --git a/lang/Jailbreak.English/Jailbreak.English.csproj b/lang/Jailbreak.English/Jailbreak.English.csproj new file mode 100644 index 00000000..883695e7 --- /dev/null +++ b/lang/Jailbreak.English/Jailbreak.English.csproj @@ -0,0 +1,13 @@ + + + + net7.0 + enable + enable + + + + + + + diff --git a/lang/Jailbreak.English/Teams/RatioNotifications.cs b/lang/Jailbreak.English/Teams/RatioNotifications.cs new file mode 100644 index 00000000..6ed87799 --- /dev/null +++ b/lang/Jailbreak.English/Teams/RatioNotifications.cs @@ -0,0 +1,46 @@ +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.Teams; + +public class RatioNotifications : IRatioNotifications, ILanguage +{ + public static FormatObject PREFIX = new HiddenFormatObject( $" {ChatColors.LightRed}[{ChatColors.Red}JB{ChatColors.LightRed}]" ) + { + // Hide in panorama and center text + Plain = false, + Panorama = false, + Chat = true, + }; + + public IView NOT_ENOUGH_GUARDS => new SimpleView(writer => + writer + .Line(PREFIX, "There's not enough guards in the queue!")); + + public IView JOIN_GUARD_QUEUE => new SimpleView(writer => + writer + .Line(PREFIX, "Type !guard to become a guard!")); + + public IView YOU_WERE_AUTOBALANCED_PRISONER => new SimpleView(writer => + writer + .Line(PREFIX, "You were autobalanced to the prisoner team!")); + + public IView ATTEMPT_TO_JOIN_FROM_TEAM_MENU => new SimpleView(writer => + writer + .Line(PREFIX, "You were swapped back to the prisoner team!") + .Line(PREFIX, "Please use !guard to join the guard team.")); + + public IView LEFT_GUARD => new SimpleView(writer => + writer + .Line(PREFIX, "You are no longer a guard.") + .Line(PREFIX, "Please use !guard if you want to re-join the guard team.")); + + public IView YOU_WERE_AUTOBALANCED_GUARD => new SimpleView(writer => + writer + .Line(PREFIX, "You are now a guard!")); +} diff --git a/lang/Jailbreak.English/Warden/WardenNotifications.cs b/lang/Jailbreak.English/Warden/WardenNotifications.cs new file mode 100644 index 00000000..332120b5 --- /dev/null +++ b/lang/Jailbreak.English/Warden/WardenNotifications.cs @@ -0,0 +1,67 @@ +using CounterStrikeSharp.API.Core; +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.Warden; + +public class WardenNotifications : IWardenNotifications, ILanguage +{ + public static FormatObject PREFIX = new HiddenFormatObject( $" {ChatColors.Lime}[{ChatColors.Green}WARDEN{ChatColors.Lime}]" ) + { + // Hide in panorama and center text + Plain = false, + Panorama = false, + Chat = true, + }; + + public IView PICKING_SHORTLY => new SimpleView(writer => + writer + .Line(PREFIX, "Picking a warden shortly") + .Line(PREFIX, "To enter the warden queue, type !warden in chat.")); + + public IView NO_WARDENS => new SimpleView(writer => + writer + .Line(PREFIX, "No wardens in queue! The next player to run !warden will become a warden.")); + + public IView WARDEN_LEFT => new SimpleView(writer => + writer.Line(PREFIX, "The warden has left the game!")); + + public IView WARDEN_DIED => new SimpleView(writer => + writer.Line(PREFIX, "The warden has died!")); + + public IView BECOME_NEXT_WARDEN => new SimpleView(writer => + writer.Line(PREFIX, "Type !warden to become the next warden")); + + public IView JOIN_RAFFLE => new SimpleView(writer => + writer.Line(PREFIX, "You've joined the warden raffle!")); + + public IView LEAVE_RAFFLE => new SimpleView(writer => + writer.Line(PREFIX, "You've left the warden raffle!")); + + public IView PASS_WARDEN(CCSPlayerController player) + { + return new SimpleView(writer => + writer.Line(PREFIX, player, "has resigned from being warden!")); + } + + public IView NEW_WARDEN(CCSPlayerController player) + { + return new SimpleView(writer => + writer.Line(PREFIX, player, "is now the warden!")); + } + + public IView CURRENT_WARDEN(CCSPlayerController? player) + { + if (player is not null) + return new SimpleView(writer => + writer.Line(PREFIX, "The current warden is", player)); + else + return new SimpleView(writer => + writer.Line(PREFIX, "There is currently no warden!")); + } +} diff --git a/mod/Jailbreak.Teams/Jailbreak.Teams.csproj b/mod/Jailbreak.Teams/Jailbreak.Teams.csproj index 29f7e134..7f2b8a0c 100644 --- a/mod/Jailbreak.Teams/Jailbreak.Teams.csproj +++ b/mod/Jailbreak.Teams/Jailbreak.Teams.csproj @@ -7,7 +7,8 @@ - + + - + diff --git a/mod/Jailbreak.Teams/Queue/QueueBehavior.cs b/mod/Jailbreak.Teams/Queue/QueueBehavior.cs index 6acdbeea..c5b55372 100644 --- a/mod/Jailbreak.Teams/Queue/QueueBehavior.cs +++ b/mod/Jailbreak.Teams/Queue/QueueBehavior.cs @@ -1,8 +1,11 @@ using CounterStrikeSharp.API; using CounterStrikeSharp.API.Core; using CounterStrikeSharp.API.Core.Attributes.Registration; +using CounterStrikeSharp.API.Modules.Commands; using CounterStrikeSharp.API.Modules.Utils; +using Jailbreak.Formatting.Extensions; +using Jailbreak.Formatting.Views; using Jailbreak.Public.Behaviors; using Jailbreak.Public.Extensions; using Jailbreak.Public.Generic; @@ -18,9 +21,12 @@ public class QueueBehavior : IGuardQueue, IPluginBehavior private readonly ILogger _logger; private readonly IPlayerState _state; - public QueueBehavior(IPlayerStateFactory factory, ILogger logger) + private IRatioNotifications _notifications; + + public QueueBehavior(IPlayerStateFactory factory, ILogger logger, IRatioNotifications notifications) { - _logger = logger; + _logger = logger; + _notifications = notifications; _counter = 0; _state = factory.Global(); } @@ -48,14 +54,12 @@ public bool TryExitQueue(CCSPlayerController player) public bool TryPop(int count) { - Server.PrintToChatAll($"[Jail] Autobalancing is adding {count} guards."); var queue = Queue.ToList(); if (queue.Count <= count) { - Server.PrintToChatAll("[Jail] Not enough guards are in the queue!"); - Server.PrintToChatAll("[Jail] Type !guard in chat to join the queue"); - ServerExtensions.PrintToCenterAll("Not enough players in guard queue!\nType !guard to become a guard."); + _notifications.NOT_ENOUGH_GUARDS.ToAllChat(); + _notifications.JOIN_GUARD_QUEUE.ToAllChat().ToAllCenter(); } _logger.LogInformation("[Queue] Pop requested {@Count} out of {@InQueue}", count, queue.Count); @@ -72,8 +76,6 @@ public bool TryPop(int count) public bool TryPush(int count) { - Server.PrintToChatAll($"[Jail] Autobalancing is removing {count} guards."); - var players = Utilities.GetPlayers() .Where(player => player.GetTeam() == CsTeam.CounterTerrorist) .Shuffle(Random.Shared) @@ -91,7 +93,7 @@ public bool TryPush(int count) TryEnterQueue(toSwap); - toSwap.PrintToCenter("You were autobalanced to the prisoner team!"); + _notifications.YOU_WERE_AUTOBALANCED_PRISONER.ToPlayerCenter(toSwap); } return true; @@ -102,7 +104,10 @@ public void ForceGuard(CCSPlayerController player) // Set IsGuard so they won't be swapped back. _state.Get(player).IsGuard = true; - player.PrintToCenter("You are now a guard!"); + _notifications.YOU_WERE_AUTOBALANCED_GUARD + .ToPlayerChat(player) + .ToPlayerCenter(player); + player.ChangeTeam(CsTeam.CounterTerrorist); } @@ -129,16 +134,72 @@ public HookResult OnPlayerTeam(EventPlayerTeam ev, GameEventInfo info) if (ev.Team == (int)CsTeam.CounterTerrorist && !state.IsGuard) { - player.SwitchTeam(CsTeam.Terrorist); - player.PrintToCenter("You were swapped to T!\nUse !guard to join the queue."); - return HookResult.Handled; } if (player.GetTeam() == CsTeam.Terrorist && state.IsGuard) - if (TryExitQueue(player)) - player.PrintToCenter("You were removed from the guard queue for switching to T.\nUse !guard to rejoin the queue!"); + { + if (this.TryExitQueue(player)) + _notifications.LEFT_GUARD + .ToPlayerCenter(player) + .ToPlayerChat(player); + } return HookResult.Continue; } + + private void HandleQueueRequest(CCSPlayerController player) + { + if (TryEnterQueue(player)) + _notifications.JOIN_GUARD_QUEUE + .ToPlayerCenter(player) + .ToPlayerChat(player); + else + player.PrintToCenter("An error occured adding you to the queue."); + + } + + private void HandleLeaveRequest(CCSPlayerController player) + { + if (TryExitQueue(player)) + _notifications.LEFT_GUARD + .ToPlayerCenter(player) + .ToPlayerChat(player); + else + player.PrintToCenter("An error occured removing you from the queue."); + } + + public int GetQueuePosition(CCSPlayerController player) + { + return Queue.ToList() + .FindIndex(controller => controller.Slot == player.Slot); + } + + [ConsoleCommand("css_guard", "Joins the guard queue")] + [ConsoleCommand("css_g", "Joins the guard queue")] + [CommandHelper(0, "", CommandUsage.CLIENT_ONLY)] + public void Command_Guard(CCSPlayerController? player, CommandInfo command) + { + if (player == null) + return; + HandleQueueRequest(player); + } + + [ConsoleCommand("css_leave", "Leaves the guard queue")] + [CommandHelper(0, "", CommandUsage.CLIENT_ONLY)] + public void Command_Leave(CCSPlayerController? player, CommandInfo command) + { + if (player == null) + return; + HandleLeaveRequest(player); + } + + + public IEnumerable Queue + => Utilities.GetPlayers() + .Select(player => (Player: player, State: _state.Get(player))) + .Where(tuple => tuple.State.InQueue) // Exclude not in queue + .Where(tuple => !tuple.State.IsGuard) // Exclude current guards + .OrderBy(tuple => tuple.State.Position) // Order by counter value when joined queue + .Select(tuple => tuple.Player); } \ No newline at end of file diff --git a/mod/Jailbreak.Warden/Commands/WardenCommandsBehavior.cs b/mod/Jailbreak.Warden/Commands/WardenCommandsBehavior.cs index 2967a5f2..b88f4b1b 100644 --- a/mod/Jailbreak.Warden/Commands/WardenCommandsBehavior.cs +++ b/mod/Jailbreak.Warden/Commands/WardenCommandsBehavior.cs @@ -3,6 +3,8 @@ using CounterStrikeSharp.API.Core.Attributes.Registration; using CounterStrikeSharp.API.Modules.Utils; +using Jailbreak.Formatting.Extensions; +using Jailbreak.Formatting.Views; using Jailbreak.Public.Behaviors; using Jailbreak.Public.Extensions; using Jailbreak.Public.Mod.Warden; @@ -11,13 +13,15 @@ namespace Jailbreak.Warden.Commands; public class WardenCommandsBehavior : IPluginBehavior { - private readonly IWardenSelectionService _queue; - private readonly IWardenService _warden; + private IWardenSelectionService _queue; + private IWardenService _warden; + private IWardenNotifications _notifications; - public WardenCommandsBehavior(IWardenSelectionService queue, IWardenService warden) + public WardenCommandsBehavior(IWardenSelectionService queue, IWardenService warden, IWardenNotifications notifications) { _queue = queue; _warden = warden; + _notifications = notifications; } public void Dispose() @@ -33,11 +37,11 @@ public HookResult HandleWarden(CCSPlayerController sender) { if (_queue.InQueue(sender)) if (_queue.TryEnter(sender)) - sender.PrintToChat("[Warden] You've joined the queue!"); + _notifications.JOIN_RAFFLE.ToPlayerChat(sender); if (!_queue.InQueue(sender)) if (_queue.TryExit(sender)) - sender.PrintToChat("[Warden] You've left the queue!"); + _notifications.LEAVE_RAFFLE.ToPlayerChat(sender); return HookResult.Handled; } @@ -46,11 +50,7 @@ public HookResult HandleWarden(CCSPlayerController sender) if (isCt && !_warden.HasWarden) _warden.TrySetWarden(sender); - // Respond to all other requests - if (_warden.HasWarden) - sender.PrintToChat($"[Warden] The current warden is {_warden.Warden.PlayerName}"); - else - sender.PrintToChat("[Warden] There is currently no warden!"); + _notifications.CURRENT_WARDEN(_warden.Warden).ToPlayerChat(sender); return HookResult.Handled; } @@ -63,7 +63,12 @@ public HookResult HandlePass(CCSPlayerController sender) if (isWarden) { // Handle warden pass - Server.PrintToChatAll("[Warden] The warden has passed!"); + _notifications.PASS_WARDEN(sender) + .ToAllChat() + .ToAllCenter(); + + _notifications.BECOME_NEXT_WARDEN.ToAllChat(); + if (!_warden.TryRemoveWarden()) Server.PrintToChatAll("[BUG] Couldn't remove warden :^("); diff --git a/mod/Jailbreak.Warden/Extensions/WardenFormatWriterExtensions.cs b/mod/Jailbreak.Warden/Extensions/WardenFormatWriterExtensions.cs new file mode 100644 index 00000000..2e6a4e31 --- /dev/null +++ b/mod/Jailbreak.Warden/Extensions/WardenFormatWriterExtensions.cs @@ -0,0 +1,6 @@ +namespace Jailbreak.Warden.Extensions; + +public class WardenFormatWriterExtensions +{ + +} \ No newline at end of file diff --git a/mod/Jailbreak.Warden/Global/WardenBehavior.cs b/mod/Jailbreak.Warden/Global/WardenBehavior.cs index 3034a719..9fc02573 100644 --- a/mod/Jailbreak.Warden/Global/WardenBehavior.cs +++ b/mod/Jailbreak.Warden/Global/WardenBehavior.cs @@ -6,6 +6,9 @@ using Jailbreak.Public.Behaviors; using Jailbreak.Public.Extensions; using Jailbreak.Public.Mod.Warden; +using Jailbreak.Formatting.Core; +using Jailbreak.Formatting.Extensions; +using Jailbreak.Formatting.Views; using Microsoft.Extensions.Logging; @@ -20,6 +23,17 @@ public WardenBehavior(ILogger logger) _logger = logger; } + + private IWardenNotifications _notifications; + + private bool _hasWarden; + private CCSPlayerController? _warden; + + public WardenBehavior(IWardenNotifications notifications) + { + _notifications = notifications; + } + /// /// Get the current warden, if there is one. /// @@ -42,9 +56,11 @@ public bool TrySetWarden(CCSPlayerController controller) HasWarden = true; Warden = controller; - Server.PrintToChatAll($"[Warden] {Warden.PlayerName.Sanitize()} is now the warden!"); - ServerExtensions.PrintToCenterAll($"{Warden.PlayerName.Sanitize()} is now the warden!"); - Warden.ClanName = "[WARDEN]"; + _notifications.NEW_WARDEN(_warden) + .ToAllChat() + .ToAllCenter(); + + _warden.ClanName = "[WARDEN]"; return true; } @@ -75,9 +91,11 @@ public HookResult OnDeath(EventPlayerDeath ev, GameEventInfo info) _logger.LogWarning("[Warden] BUG: Problem removing current warden :^("); // Warden died! - Server.PrintToChatAll("[Warden] The current warden has died!"); - Server.PrintToChatAll("[Warden] Type !warden to become the next warden"); - ServerExtensions.PrintToCenterAll("The warden has died!"); + _notifications.WARDEN_DIED + .ToAllChat() + .ToAllCenter(); + + _notifications.BECOME_NEXT_WARDEN.ToAllChat(); } return HookResult.Continue; @@ -102,10 +120,12 @@ public HookResult OnPlayerDisconnect(EventPlayerDisconnect ev, GameEventInfo inf if (!TryRemoveWarden()) _logger.LogWarning("[Warden] BUG: Problem removing current warden :^("); - // Warden died! - Server.PrintToChatAll("[Warden] The current warden has left the game!"); - Server.PrintToChatAll("[Warden] Type !warden to become the next warden"); - ServerExtensions.PrintToCenterAll("The warden has left!"); + + _notifications.WARDEN_LEFT + .ToAllChat() + .ToAllCenter(); + + _notifications.BECOME_NEXT_WARDEN.ToAllChat(); } return HookResult.Continue; diff --git a/mod/Jailbreak.Warden/Jailbreak.Warden.csproj b/mod/Jailbreak.Warden/Jailbreak.Warden.csproj index 29f7e134..e549f3ef 100644 --- a/mod/Jailbreak.Warden/Jailbreak.Warden.csproj +++ b/mod/Jailbreak.Warden/Jailbreak.Warden.csproj @@ -7,7 +7,8 @@ - + + diff --git a/mod/Jailbreak.Warden/Selection/WardenSelectionBehavior.cs b/mod/Jailbreak.Warden/Selection/WardenSelectionBehavior.cs index 3a2dbdf0..04d40921 100644 --- a/mod/Jailbreak.Warden/Selection/WardenSelectionBehavior.cs +++ b/mod/Jailbreak.Warden/Selection/WardenSelectionBehavior.cs @@ -1,4 +1,6 @@ -using System.Runtime.CompilerServices; +using System; +using System.Linq; +using System.Runtime.CompilerServices; using CounterStrikeSharp.API; using CounterStrikeSharp.API.Core; @@ -6,6 +8,8 @@ using CounterStrikeSharp.API.Modules.Timers; using CounterStrikeSharp.API.Modules.Utils; +using Jailbreak.Formatting.Extensions; +using Jailbreak.Formatting.Views; using Jailbreak.Public.Behaviors; using Jailbreak.Public.Extensions; using Jailbreak.Public.Generic; @@ -39,10 +43,13 @@ public class WardenSelectionBehavior : IPluginBehavior, IWardenSelectionService private readonly IWardenService _warden; - public WardenSelectionBehavior(IPlayerStateFactory factory, IWardenService warden, ILogger logger) + private IWardenNotifications _notifications; + + public WardenSelectionBehavior(IPlayerStateFactory factory, IWardenService warden, IWardenNotifications notifications, ILogger logger) { + _logger = logger; _warden = warden; - _logger = logger; + _notifications = notifications; _queue = factory.Round(); _favor = factory.Global(); @@ -88,8 +95,7 @@ public HookResult OnRoundStart(EventRoundStart ev, GameEventInfo info) // Enable the warden queue _queueInactive = false; - Server.PrintToChatAll("[Warden] Picking a warden shortly."); - Server.PrintToChatAll("[Warden] To enter the warden queue, type !WARDEN in chat."); + _notifications.PICKING_SHORTLY.ToAllChat(); // Start a timer to pick the warden in 7 seconds ScheduleChooseWarden(7.0f); @@ -118,7 +124,7 @@ protected void OnChooseWarden() if (eligible.Count == 0) { - Server.PrintToChatAll("[Warden] No Wardens in queue!"); + _notifications.NO_WARDENS.ToAllChat(); _queueInactive = true; return; diff --git a/public/Jailbreak.Formatting/Base/IView.cs b/public/Jailbreak.Formatting/Base/IView.cs new file mode 100644 index 00000000..9568bafe --- /dev/null +++ b/public/Jailbreak.Formatting/Base/IView.cs @@ -0,0 +1,10 @@ +using Jailbreak.Formatting.Core; + +namespace Jailbreak.Formatting.Base; + +public interface IView +{ + + void Render(FormatWriter writer); + +} diff --git a/public/Jailbreak.Formatting/Base/SimpleView.cs b/public/Jailbreak.Formatting/Base/SimpleView.cs new file mode 100644 index 00000000..6cf13644 --- /dev/null +++ b/public/Jailbreak.Formatting/Base/SimpleView.cs @@ -0,0 +1,30 @@ +using Jailbreak.Formatting.Core; + +namespace Jailbreak.Formatting.Base; + +public class SimpleView : IView +{ + + private Action _handler; + + public SimpleView(Action handler) + { + _handler = handler; + } + + public SimpleView(params string[] lines) + { + _handler = (writer) => + { + foreach (string line in lines) + { + writer.Line(line); + } + }; + } + + public void Render(FormatWriter writer) + { + _handler(writer); + } +} diff --git a/public/Jailbreak.Formatting/Core/FormatObject.cs b/public/Jailbreak.Formatting/Core/FormatObject.cs new file mode 100644 index 00000000..49f31096 --- /dev/null +++ b/public/Jailbreak.Formatting/Core/FormatObject.cs @@ -0,0 +1,39 @@ +using CounterStrikeSharp.API.Core; + +using Jailbreak.Formatting.Objects; +using Jailbreak.Public.Extensions; + +namespace Jailbreak.Formatting.Core; + +public abstract class FormatObject +{ + + /// + /// Output this format object compatible with CS2 chat formatting. + /// + /// + public virtual string ToChat() + => ToPlain(); + + /// + /// Output this format object in a panorama-compatible format. + /// + /// + public virtual string ToPanorama() + => ToPlain().Sanitize(); + + /// + /// Output plaintext + /// + /// + public abstract string ToPlain(); + + + public static implicit operator FormatObject(string value) + => new StringFormatObject(value); + + public static implicit operator FormatObject(CCSPlayerController value) + => new PlayerFormatObject(value); + + public static FormatObject FromObject(object value) => new StringFormatObject(value.ToString()); +} diff --git a/public/Jailbreak.Formatting/Core/FormatWriter.cs b/public/Jailbreak.Formatting/Core/FormatWriter.cs new file mode 100644 index 00000000..feccfc30 --- /dev/null +++ b/public/Jailbreak.Formatting/Core/FormatWriter.cs @@ -0,0 +1,28 @@ +namespace Jailbreak.Formatting.Core; + +public class FormatWriter +{ + + private List< FormatObject[] > _lines = new(); + + public IEnumerable Lines => _lines; + + public IEnumerable Chat + => Lines.Select(array => string.Join(' ', array.Select(obj => obj.ToChat()) )); + + + public IEnumerable Panorama + => Lines.Select(array => string.Join(' ', array.Select(obj => obj.ToPanorama()) )); + + public IEnumerable Plain + => Lines.Select(array => string.Join(' ', array.Select(obj => obj.ToPlain()) )); + + + public FormatWriter Line( params FormatObject[] args ) + { + _lines.Add( args ); + + return this; + } + +} diff --git a/public/Jailbreak.Formatting/Extensions/ViewExtensions.cs b/public/Jailbreak.Formatting/Extensions/ViewExtensions.cs new file mode 100644 index 00000000..981f483a --- /dev/null +++ b/public/Jailbreak.Formatting/Extensions/ViewExtensions.cs @@ -0,0 +1,85 @@ +using CounterStrikeSharp.API; +using CounterStrikeSharp.API.Core; + +using Jailbreak.Formatting.Base; +using Jailbreak.Formatting.Core; + +namespace Jailbreak.Formatting.Extensions; + +public static class ViewExtensions +{ + + public static FormatWriter ToWriter(this IView view) + { + var writer = new FormatWriter(); + + view.Render(writer); + + return writer; + } + + #region Individual + + public static IView ToPlayerConsole(this IView view, CCSPlayerController player) + { + var writer = view.ToWriter(); + + foreach (string writerLine in writer.Plain) + player.PrintToConsole(writerLine); + + return view; + } + + public static IView ToPlayerChat(this IView view, CCSPlayerController player) + { + var writer = view.ToWriter(); + + foreach (string writerLine in writer.Chat) + player.PrintToChat(writerLine); + + return view; + } + + public static IView ToPlayerCenter(this IView view, CCSPlayerController player) + { + var writer = view.ToWriter(); + var merged = string.Join('\n', writer.Plain); + + player.PrintToCenter(merged); + + return view; + } + + public static IView ToPlayerCenterHtml(this IView view, CCSPlayerController player) + { + var writer = view.ToWriter(); + var merged = string.Join('\n', writer.Panorama); + + player.PrintToCenterHtml(merged); + + return view; + } + + #endregion + + public static IView ToAllConsole(this IView view) + { + Utilities.GetPlayers().ForEach(player => view.ToPlayerConsole(player)); + + return view; + } + + public static IView ToAllChat(this IView view) + { + Utilities.GetPlayers().ForEach(player => view.ToPlayerChat(player)); + + return view; + } + + public static IView ToAllCenter(this IView view) + { + Utilities.GetPlayers().ForEach(player => view.ToPlayerCenter(player)); + + return view; + } +} diff --git a/public/Jailbreak.Formatting/Jailbreak.Formatting.csproj b/public/Jailbreak.Formatting/Jailbreak.Formatting.csproj new file mode 100644 index 00000000..dfa47427 --- /dev/null +++ b/public/Jailbreak.Formatting/Jailbreak.Formatting.csproj @@ -0,0 +1,13 @@ + + + + net7.0 + enable + enable + + + + + + + diff --git a/public/Jailbreak.Formatting/Languages/English.cs b/public/Jailbreak.Formatting/Languages/English.cs new file mode 100644 index 00000000..0fa55e13 --- /dev/null +++ b/public/Jailbreak.Formatting/Languages/English.cs @@ -0,0 +1,8 @@ +using Jailbreak.Formatting.Logistics; + +namespace Jailbreak.Formatting.Languages; + +public class English : IDialect +{ + +} diff --git a/public/Jailbreak.Formatting/Logistics/IDialect.cs b/public/Jailbreak.Formatting/Logistics/IDialect.cs new file mode 100644 index 00000000..a10560c4 --- /dev/null +++ b/public/Jailbreak.Formatting/Logistics/IDialect.cs @@ -0,0 +1,10 @@ +namespace Jailbreak.Formatting.Logistics; + +/// +/// A specific language, such as "English" or "French", +/// should inherit this interface. +/// +public interface IDialect +{ + +} diff --git a/public/Jailbreak.Formatting/Logistics/ILanguage.cs b/public/Jailbreak.Formatting/Logistics/ILanguage.cs new file mode 100644 index 00000000..a6483688 --- /dev/null +++ b/public/Jailbreak.Formatting/Logistics/ILanguage.cs @@ -0,0 +1,12 @@ +namespace Jailbreak.Formatting.Logistics; + +/// +/// Specifies that this class is written in a specific language +/// Eg, ILanguage<English> or ILanguage<French> +/// +/// +public interface ILanguage + where TDialect: IDialect +{ + +} diff --git a/public/Jailbreak.Formatting/Logistics/LanguageConfig.cs b/public/Jailbreak.Formatting/Logistics/LanguageConfig.cs new file mode 100644 index 00000000..47cc15be --- /dev/null +++ b/public/Jailbreak.Formatting/Logistics/LanguageConfig.cs @@ -0,0 +1,25 @@ +using Jailbreak.Formatting.Views; + +using Microsoft.Extensions.DependencyInjection; + +namespace Jailbreak.Formatting.Logistics; + +public class LanguageConfig + where TDialect: IDialect +{ + + private IServiceCollection _collection; + + public LanguageConfig(IServiceCollection collection) + { + _collection = collection; + } + + public void WithRatio() + where TRatio : class, ILanguage, IRatioNotifications + => _collection.AddSingleton(); + + public void WithWarden() + where TWarden : class, ILanguage, IWardenNotifications + => _collection.AddSingleton(); +} diff --git a/public/Jailbreak.Formatting/Logistics/RegisterLanguageExtensions.cs b/public/Jailbreak.Formatting/Logistics/RegisterLanguageExtensions.cs new file mode 100644 index 00000000..b2174095 --- /dev/null +++ b/public/Jailbreak.Formatting/Logistics/RegisterLanguageExtensions.cs @@ -0,0 +1,16 @@ +using Microsoft.Extensions.DependencyInjection; + +namespace Jailbreak.Formatting.Logistics; + +public static class RegisterLanguageExtensions +{ + public static void AddLanguage( + this IServiceCollection collection, + Action> factory) + where TDialect: IDialect + { + var config = new LanguageConfig(collection); + + factory(config); + } +} diff --git a/public/Jailbreak.Formatting/Objects/HiddenFormatObject.cs b/public/Jailbreak.Formatting/Objects/HiddenFormatObject.cs new file mode 100644 index 00000000..a9cac122 --- /dev/null +++ b/public/Jailbreak.Formatting/Objects/HiddenFormatObject.cs @@ -0,0 +1,40 @@ +using Jailbreak.Formatting.Core; + +namespace Jailbreak.Formatting.Objects; + +public class HiddenFormatObject : FormatObject +{ + + public FormatObject _value; + + public HiddenFormatObject(FormatObject value) + { + _value = value; + } + + public bool Plain { get; set; } = true; + + public bool Panorama { get; set; } = true; + + public bool Chat { get; set; } = true; + + public override string ToChat() + { + if (Chat) + return _value.ToChat(); + return String.Empty; + } + + public override string ToPanorama() + { + if (Panorama) + return _value.ToPanorama(); + return String.Empty; } + + public override string ToPlain() + { + if (Plain) + return _value.ToPlain(); + return String.Empty; + } +} diff --git a/public/Jailbreak.Formatting/Objects/PlayerFormatObject.cs b/public/Jailbreak.Formatting/Objects/PlayerFormatObject.cs new file mode 100644 index 00000000..3dadab23 --- /dev/null +++ b/public/Jailbreak.Formatting/Objects/PlayerFormatObject.cs @@ -0,0 +1,26 @@ +using CounterStrikeSharp.API.Core; +using CounterStrikeSharp.API.Modules.Utils; + +using Jailbreak.Formatting.Core; +using Jailbreak.Public.Extensions; + +namespace Jailbreak.Formatting.Objects; + +public class PlayerFormatObject : FormatObject +{ + private CCSPlayerController _player; + + public PlayerFormatObject(CCSPlayerController player) + { + _player = player; + } + + public override string ToChat() + => $"{ChatColors.Yellow}{_player.PlayerName}"; + + public override string ToPanorama() + => _player.PlayerName.Sanitize(); + + public override string ToPlain() + => _player.PlayerName; +} diff --git a/public/Jailbreak.Formatting/Objects/StringFormatObject.cs b/public/Jailbreak.Formatting/Objects/StringFormatObject.cs new file mode 100644 index 00000000..64900bba --- /dev/null +++ b/public/Jailbreak.Formatting/Objects/StringFormatObject.cs @@ -0,0 +1,28 @@ +using CounterStrikeSharp.API.Modules.Utils; + +using Jailbreak.Formatting.Core; + +namespace Jailbreak.Formatting.Objects; + +public class StringFormatObject : FormatObject +{ + private string _value; + private char _chatColor; + + public StringFormatObject(string value, char chatColor = '\x01') + { + _value = value; + _chatColor = chatColor; + } + + public string Value => _value; + + public override string ToChat() + => $"{_chatColor}{Value}"; + + public override string ToPanorama() + => Value; + + public override string ToPlain() + => Value; +} diff --git a/public/Jailbreak.Formatting/Views/ITeamsNotifications.cs b/public/Jailbreak.Formatting/Views/ITeamsNotifications.cs new file mode 100644 index 00000000..15e2ce80 --- /dev/null +++ b/public/Jailbreak.Formatting/Views/ITeamsNotifications.cs @@ -0,0 +1,19 @@ +using Jailbreak.Formatting.Base; + +namespace Jailbreak.Formatting.Views; + +public interface IRatioNotifications +{ + public IView NOT_ENOUGH_GUARDS { get; } + + public IView JOIN_GUARD_QUEUE { get; } + + public IView YOU_WERE_AUTOBALANCED_PRISONER { get; } + + public IView YOU_WERE_AUTOBALANCED_GUARD { get; } + + public IView ATTEMPT_TO_JOIN_FROM_TEAM_MENU { get; } + + public IView LEFT_GUARD { get; } + +} diff --git a/public/Jailbreak.Formatting/Views/IWardenNotifications.cs b/public/Jailbreak.Formatting/Views/IWardenNotifications.cs new file mode 100644 index 00000000..189b41be --- /dev/null +++ b/public/Jailbreak.Formatting/Views/IWardenNotifications.cs @@ -0,0 +1,38 @@ +using CounterStrikeSharp.API.Core; + +using Jailbreak.Formatting.Base; + +namespace Jailbreak.Formatting.Views; + +public interface IWardenNotifications +{ + public IView PICKING_SHORTLY { get; } + public IView NO_WARDENS { get; } + public IView WARDEN_LEFT { get; } + public IView WARDEN_DIED { get; } + public IView BECOME_NEXT_WARDEN { get; } + public IView JOIN_RAFFLE { get; } + public IView LEAVE_RAFFLE { get; } + + /// + /// Create a view for when the specified player passes warden + /// + /// + /// + public IView PASS_WARDEN(CCSPlayerController player); + + /// + /// Create a view for when this player becomes a new warden + /// + /// + /// + public IView NEW_WARDEN(CCSPlayerController player); + + /// + /// Format a response to a request about the current warden. + /// When player is null, instead respond stating that there is no warden. + /// + /// + /// + public IView CURRENT_WARDEN(CCSPlayerController? player); +} diff --git a/src/Jailbreak.Generic/GenericServiceExtension.cs b/src/Jailbreak.Generic/GenericServiceExtension.cs index 850207e3..c55984ff 100644 --- a/src/Jailbreak.Generic/GenericServiceExtension.cs +++ b/src/Jailbreak.Generic/GenericServiceExtension.cs @@ -1,4 +1,6 @@ -using Jailbreak.Generic.PlayerState; +using CounterStrikeSharp.API.Core; + +using Jailbreak.Generic.PlayerState; using Jailbreak.Generic.PlayerState.Behaviors; using Jailbreak.Public.Extensions; using Jailbreak.Public.Generic; diff --git a/src/Jailbreak.Generic/PlayerState/Behaviors/RoundStateTracker.cs b/src/Jailbreak.Generic/PlayerState/Behaviors/RoundStateTracker.cs index 1c4aa376..66566489 100644 --- a/src/Jailbreak.Generic/PlayerState/Behaviors/RoundStateTracker.cs +++ b/src/Jailbreak.Generic/PlayerState/Behaviors/RoundStateTracker.cs @@ -3,6 +3,7 @@ using Jailbreak.Public.Behaviors; + namespace Jailbreak.Generic.PlayerState.Behaviors; public class RoundStateTracker : BaseStateTracker, IPluginBehavior diff --git a/src/Jailbreak/Jailbreak.csproj b/src/Jailbreak/Jailbreak.csproj index 50d6651b..0a0c71f4 100644 --- a/src/Jailbreak/Jailbreak.csproj +++ b/src/Jailbreak/Jailbreak.csproj @@ -32,10 +32,11 @@ - - - - + + + + + diff --git a/src/Jailbreak/JailbreakServiceCollection.cs b/src/Jailbreak/JailbreakServiceCollection.cs index 7bd7b26a..d5504c14 100644 --- a/src/Jailbreak/JailbreakServiceCollection.cs +++ b/src/Jailbreak/JailbreakServiceCollection.cs @@ -1,6 +1,10 @@ using CounterStrikeSharp.API.Core; using Jailbreak.Config; +using Jailbreak.English.Teams; +using Jailbreak.English.Warden; +using Jailbreak.Formatting.Languages; +using Jailbreak.Formatting.Logistics; using Jailbreak.Generic; using Jailbreak.Public.Configuration; using Jailbreak.Teams; @@ -25,5 +29,12 @@ public void ConfigureServices(IServiceCollection serviceCollection) serviceCollection.AddJailbreakGeneric(); serviceCollection.AddJailbreakWarden(); serviceCollection.AddJailbreakTeams(); + + // Add in english localization + serviceCollection.AddLanguage(config => + { + config.WithRatio(); + config.WithWarden(); + }); } } \ No newline at end of file