From 8a8df45babc48f5e7f297cee7ed1b192100255aa Mon Sep 17 00:00:00 2001 From: Chief-Engineer <119664036+Chief-Engineer@users.noreply.github.com> Date: Thu, 11 Jul 2024 00:14:01 -0500 Subject: [PATCH] Fix baby jail (#29896) * Revert "Revert Baby Jail (#29891)" This reverts commit 24a2866747e6de37ab2c4395bee9ea44c9211c6f. * the fix --- .../Administration/UI/AdminMenuWindow.xaml | 4 +- .../Administration/UI/AdminMenuWindow.xaml.cs | 20 ++- .../BabyJailTab/BabyJailStatusWindow.xaml | 6 + .../BabyJailTab/BabyJailStatusWindow.xaml.cs | 21 +++ .../UI/Tabs/BabyJailTab/BabyJailTab.xaml | 26 ++++ .../UI/Tabs/BabyJailTab/BabyJailTab.xaml.cs | 75 ++++++++++ .../Systems/Admin/AdminUIController.cs | 22 +++ Content.Server.Database/Model.cs | 4 + .../Commands/BabyJailCommand.cs | 139 ++++++++++++++++++ .../Administration/Systems/AdminSystem.cs | 50 +++++++ .../Connection/ConnectionManager.cs | 66 +++++++++ .../GameTicking/GameTicker.StatusShell.cs | 6 + .../Events/BabyJailChangedEvent.cs | 22 +++ Content.Shared/CCVar/CCVars.cs | 42 ++++++ .../WizardsDen/wizardsDenGateway.toml | 6 + .../WizardsDen/wizardsDenLRPTide.toml | 4 + .../administration/commands/babyjail.ftl | 19 +++ .../administration/ui/admin-menu-window.ftl | 1 + .../administration/ui/tabs/babyjail-tab.ftl | 16 ++ .../Locale/en-US/connection-messages.ftl | 5 + 20 files changed, 545 insertions(+), 9 deletions(-) create mode 100644 Content.Client/Administration/UI/Tabs/BabyJailTab/BabyJailStatusWindow.xaml create mode 100644 Content.Client/Administration/UI/Tabs/BabyJailTab/BabyJailStatusWindow.xaml.cs create mode 100644 Content.Client/Administration/UI/Tabs/BabyJailTab/BabyJailTab.xaml create mode 100644 Content.Client/Administration/UI/Tabs/BabyJailTab/BabyJailTab.xaml.cs create mode 100644 Content.Server/Administration/Commands/BabyJailCommand.cs create mode 100644 Content.Shared/Administration/Events/BabyJailChangedEvent.cs create mode 100644 Resources/Locale/en-US/administration/commands/babyjail.ftl create mode 100644 Resources/Locale/en-US/administration/ui/tabs/babyjail-tab.ftl diff --git a/Content.Client/Administration/UI/AdminMenuWindow.xaml b/Content.Client/Administration/UI/AdminMenuWindow.xaml index 311d67b826c7a2..d3d3df02d93609 100644 --- a/Content.Client/Administration/UI/AdminMenuWindow.xaml +++ b/Content.Client/Administration/UI/AdminMenuWindow.xaml @@ -6,7 +6,8 @@ xmlns:tabs="clr-namespace:Content.Client.Administration.UI.Tabs" xmlns:playerTab="clr-namespace:Content.Client.Administration.UI.Tabs.PlayerTab" xmlns:objectsTab="clr-namespace:Content.Client.Administration.UI.Tabs.ObjectsTab" - xmlns:panic="clr-namespace:Content.Client.Administration.UI.Tabs.PanicBunkerTab"> + xmlns:panic="clr-namespace:Content.Client.Administration.UI.Tabs.PanicBunkerTab" + xmlns:baby="clr-namespace:Content.Client.Administration.UI.Tabs.BabyJailTab"> @@ -14,6 +15,7 @@ + diff --git a/Content.Client/Administration/UI/AdminMenuWindow.xaml.cs b/Content.Client/Administration/UI/AdminMenuWindow.xaml.cs index 51330a547ec5d2..d5c43e2a500e70 100644 --- a/Content.Client/Administration/UI/AdminMenuWindow.xaml.cs +++ b/Content.Client/Administration/UI/AdminMenuWindow.xaml.cs @@ -15,14 +15,18 @@ public AdminMenuWindow() MinSize = new Vector2(650, 250); Title = Loc.GetString("admin-menu-title"); RobustXamlLoader.Load(this); - MasterTabContainer.SetTabTitle(0, Loc.GetString("admin-menu-admin-tab")); - MasterTabContainer.SetTabTitle(1, Loc.GetString("admin-menu-adminbus-tab")); - MasterTabContainer.SetTabTitle(2, Loc.GetString("admin-menu-atmos-tab")); - MasterTabContainer.SetTabTitle(3, Loc.GetString("admin-menu-round-tab")); - MasterTabContainer.SetTabTitle(4, Loc.GetString("admin-menu-server-tab")); - MasterTabContainer.SetTabTitle(5, Loc.GetString("admin-menu-panic-bunker-tab")); - MasterTabContainer.SetTabTitle(6, Loc.GetString("admin-menu-players-tab")); - MasterTabContainer.SetTabTitle(7, Loc.GetString("admin-menu-objects-tab")); + MasterTabContainer.SetTabTitle((int) TabIndex.Admin, Loc.GetString("admin-menu-admin-tab")); + MasterTabContainer.SetTabTitle((int) TabIndex.Adminbus, Loc.GetString("admin-menu-adminbus-tab")); + MasterTabContainer.SetTabTitle((int) TabIndex.Atmos, Loc.GetString("admin-menu-atmos-tab")); + MasterTabContainer.SetTabTitle((int) TabIndex.Round, Loc.GetString("admin-menu-round-tab")); + MasterTabContainer.SetTabTitle((int) TabIndex.Server, Loc.GetString("admin-menu-server-tab")); + MasterTabContainer.SetTabTitle((int) TabIndex.PanicBunker, Loc.GetString("admin-menu-panic-bunker-tab")); + /* + * TODO: Remove baby jail code once a more mature gateway process is established. This code is only being issued as a stopgap to help with potential tiding in the immediate future. + */ + MasterTabContainer.SetTabTitle((int) TabIndex.BabyJail, Loc.GetString("admin-menu-baby-jail-tab")); + MasterTabContainer.SetTabTitle((int) TabIndex.Players, Loc.GetString("admin-menu-players-tab")); + MasterTabContainer.SetTabTitle((int) TabIndex.Objects, Loc.GetString("admin-menu-objects-tab")); MasterTabContainer.OnTabChanged += OnTabChanged; } diff --git a/Content.Client/Administration/UI/Tabs/BabyJailTab/BabyJailStatusWindow.xaml b/Content.Client/Administration/UI/Tabs/BabyJailTab/BabyJailStatusWindow.xaml new file mode 100644 index 00000000000000..b8034faf52abfb --- /dev/null +++ b/Content.Client/Administration/UI/Tabs/BabyJailTab/BabyJailStatusWindow.xaml @@ -0,0 +1,6 @@ + + + diff --git a/Content.Client/Administration/UI/Tabs/BabyJailTab/BabyJailStatusWindow.xaml.cs b/Content.Client/Administration/UI/Tabs/BabyJailTab/BabyJailStatusWindow.xaml.cs new file mode 100644 index 00000000000000..9e1d53818f2485 --- /dev/null +++ b/Content.Client/Administration/UI/Tabs/BabyJailTab/BabyJailStatusWindow.xaml.cs @@ -0,0 +1,21 @@ +using Content.Client.Message; +using Content.Client.UserInterface.Controls; +using Robust.Client.AutoGenerated; +using Robust.Client.UserInterface.CustomControls; +using Robust.Client.UserInterface.XAML; + +namespace Content.Client.Administration.UI.Tabs.BabyJailTab; + +/* + * TODO: Remove me once a more mature gateway process is established. This code is only being issued as a stopgap to help with potential tiding in the immediate future. + */ + +[GenerateTypedNameReferences] +public sealed partial class BabyJailStatusWindow : FancyWindow +{ + public BabyJailStatusWindow() + { + RobustXamlLoader.Load(this); + MessageLabel.SetMarkup(Loc.GetString("admin-ui-baby-jail-is-enabled")); + } +} diff --git a/Content.Client/Administration/UI/Tabs/BabyJailTab/BabyJailTab.xaml b/Content.Client/Administration/UI/Tabs/BabyJailTab/BabyJailTab.xaml new file mode 100644 index 00000000000000..dd770c2be53c1b --- /dev/null +++ b/Content.Client/Administration/UI/Tabs/BabyJailTab/BabyJailTab.xaml @@ -0,0 +1,26 @@ + + + + + + + + + + + + diff --git a/Content.Client/Administration/UI/Tabs/BabyJailTab/BabyJailTab.xaml.cs b/Content.Client/Administration/UI/Tabs/BabyJailTab/BabyJailTab.xaml.cs new file mode 100644 index 00000000000000..aa9d6ced9517ff --- /dev/null +++ b/Content.Client/Administration/UI/Tabs/BabyJailTab/BabyJailTab.xaml.cs @@ -0,0 +1,75 @@ +using Content.Shared.Administration.Events; +using Robust.Client.AutoGenerated; +using Robust.Client.UserInterface; +using Robust.Client.UserInterface.XAML; +using Robust.Shared.Console; + +/* + * TODO: Remove me once a more mature gateway process is established. This code is only being issued as a stopgap to help with potential tiding in the immediate future. + */ + +namespace Content.Client.Administration.UI.Tabs.BabyJailTab; + +[GenerateTypedNameReferences] +public sealed partial class BabyJailTab : Control +{ + [Dependency] private readonly IConsoleHost _console = default!; + + private string _maxAccountAge; + private string _maxOverallMinutes; + + public BabyJailTab() + { + RobustXamlLoader.Load(this); + IoCManager.InjectDependencies(this); + + MaxAccountAge.OnTextEntered += args => SendMaxAccountAge(args.Text); + MaxAccountAge.OnFocusExit += args => SendMaxAccountAge(args.Text); + _maxAccountAge = MaxAccountAge.Text; + + MaxOverallMinutes.OnTextEntered += args => SendMaxOverallMinutes(args.Text); + MaxOverallMinutes.OnFocusExit += args => SendMaxOverallMinutes(args.Text); + _maxOverallMinutes = MaxOverallMinutes.Text; + } + + private void SendMaxAccountAge(string text) + { + if (string.IsNullOrWhiteSpace(text) || + text == _maxAccountAge || + !int.TryParse(text, out var minutes)) + { + return; + } + + _console.ExecuteCommand($"babyjail_max_account_age {minutes}"); + } + + private void SendMaxOverallMinutes(string text) + { + if (string.IsNullOrWhiteSpace(text) || + text == _maxOverallMinutes || + !int.TryParse(text, out var minutes)) + { + return; + } + + _console.ExecuteCommand($"babyjail_max_overall_minutes {minutes}"); + } + + public void UpdateStatus(BabyJailStatus status) + { + EnabledButton.Pressed = status.Enabled; + EnabledButton.Text = Loc.GetString(status.Enabled + ? "admin-ui-baby-jail-enabled" + : "admin-ui-baby-jail-disabled" + ); + EnabledButton.ModulateSelfOverride = status.Enabled ? Color.Red : null; + ShowReasonButton.Pressed = status.ShowReason; + + MaxAccountAge.Text = status.MaxAccountAgeMinutes.ToString(); + _maxAccountAge = MaxAccountAge.Text; + + MaxOverallMinutes.Text = status.MaxOverallMinutes.ToString(); + _maxOverallMinutes = MaxOverallMinutes.Text; + } +} diff --git a/Content.Client/UserInterface/Systems/Admin/AdminUIController.cs b/Content.Client/UserInterface/Systems/Admin/AdminUIController.cs index 392a1a96de2e93..d36a91c3733283 100644 --- a/Content.Client/UserInterface/Systems/Admin/AdminUIController.cs +++ b/Content.Client/UserInterface/Systems/Admin/AdminUIController.cs @@ -3,6 +3,7 @@ using Content.Client.Administration.UI; using Content.Client.Administration.UI.Tabs.ObjectsTab; using Content.Client.Administration.UI.Tabs.PanicBunkerTab; +using Content.Client.Administration.UI.Tabs.BabyJailTab; using Content.Client.Administration.UI.Tabs.PlayerTab; using Content.Client.Gameplay; using Content.Client.Lobby; @@ -37,11 +38,13 @@ public sealed class AdminUIController : UIController, private AdminMenuWindow? _window; private MenuButton? AdminButton => UIManager.GetActiveUIWidgetOrNull()?.AdminButton; private PanicBunkerStatus? _panicBunker; + private BabyJailStatus? _babyJail; public override void Initialize() { base.Initialize(); SubscribeNetworkEvent(OnPanicBunkerUpdated); + SubscribeNetworkEvent(OnBabyJailUpdated); } private void OnPanicBunkerUpdated(PanicBunkerChangedEvent msg, EntitySessionEventArgs args) @@ -56,6 +59,18 @@ private void OnPanicBunkerUpdated(PanicBunkerChangedEvent msg, EntitySessionEven } } + private void OnBabyJailUpdated(BabyJailChangedEvent msg, EntitySessionEventArgs args) + { + var showDialog = _babyJail == null && msg.Status.Enabled; + _babyJail = msg.Status; + _window?.BabyJailControl.UpdateStatus(msg.Status); + + if (showDialog) + { + UIManager.CreateWindow().OpenCentered(); + } + } + public void OnStateEntered(GameplayState state) { EnsureWindow(); @@ -101,6 +116,13 @@ private void EnsureWindow() if (_panicBunker != null) _window.PanicBunkerControl.UpdateStatus(_panicBunker); + /* + * TODO: Remove baby jail code once a more mature gateway process is established. This code is only being issued as a stopgap to help with potential tiding in the immediate future. + */ + + if (_babyJail != null) + _window.BabyJailControl.UpdateStatus(_babyJail); + _window.PlayerTabControl.OnEntryKeyBindDown += PlayerTabEntryKeyBindDown; _window.ObjectsTabControl.OnEntryKeyBindDown += ObjectsTabEntryKeyBindDown; _window.OnOpen += OnWindowOpen; diff --git a/Content.Server.Database/Model.cs b/Content.Server.Database/Model.cs index bd5c4f5d7e8a34..dea8f9558abdd9 100644 --- a/Content.Server.Database/Model.cs +++ b/Content.Server.Database/Model.cs @@ -901,6 +901,10 @@ public enum ConnectionDenyReason : byte Whitelist = 1, Full = 2, Panic = 3, + /* + * TODO: Remove baby jail code once a more mature gateway process is established. This code is only being issued as a stopgap to help with potential tiding in the immediate future. + */ + BabyJail = 4, } public class ServerBanHit diff --git a/Content.Server/Administration/Commands/BabyJailCommand.cs b/Content.Server/Administration/Commands/BabyJailCommand.cs new file mode 100644 index 00000000000000..058b67ca528964 --- /dev/null +++ b/Content.Server/Administration/Commands/BabyJailCommand.cs @@ -0,0 +1,139 @@ +using Content.Shared.Administration; +using Content.Shared.CCVar; +using Robust.Shared.Configuration; +using Robust.Shared.Console; + +/* + * TODO: Remove baby jail code once a more mature gateway process is established. This code is only being issued as a stopgap to help with potential tiding in the immediate future. + */ + +namespace Content.Server.Administration.Commands; + +[AdminCommand(AdminFlags.Server)] +public sealed class BabyJailCommand : LocalizedCommands +{ + [Dependency] private readonly IConfigurationManager _cfg = default!; + + public override string Command => "babyjail"; + + public override void Execute(IConsoleShell shell, string argStr, string[] args) + { + var toggle = Toggle(CCVars.BabyJailEnabled, shell, args, _cfg); + if (toggle == null) + return; + + shell.WriteLine(Loc.GetString(toggle.Value ? "babyjail-command-enabled" : "babyjail-command-disabled")); + } + + public static bool? Toggle(CVarDef cvar, IConsoleShell shell, string[] args, IConfigurationManager config) + { + if (args.Length > 1) + { + shell.WriteError(Loc.GetString("shell-need-between-arguments",("lower", 0), ("upper", 1))); + return null; + } + + var enabled = config.GetCVar(cvar); + + switch (args.Length) + { + case 0: + enabled = !enabled; + break; + case 1 when !bool.TryParse(args[0], out enabled): + shell.WriteError(Loc.GetString("shell-argument-must-be-boolean")); + return null; + } + + config.SetCVar(cvar, enabled); + + return enabled; + } +} + + +[AdminCommand(AdminFlags.Server)] +public sealed class BabyJailShowReasonCommand : LocalizedCommands +{ + [Dependency] private readonly IConfigurationManager _cfg = default!; + + public override string Command => "babyjail_show_reason"; + + public override void Execute(IConsoleShell shell, string argStr, string[] args) + { + var toggle = BabyJailCommand.Toggle(CCVars.BabyJailShowReason, shell, args, _cfg); + if (toggle == null) + return; + + shell.WriteLine(Loc.GetString(toggle.Value + ? "babyjail-command-show-reason-enabled" + : "babyjail-command-show-reason-disabled" + )); + } +} + +[AdminCommand(AdminFlags.Server)] +public sealed class BabyJailMinAccountAgeCommand : LocalizedCommands +{ + [Dependency] private readonly IConfigurationManager _cfg = default!; + + public override string Command => "babyjail_max_account_age"; + + public override void Execute(IConsoleShell shell, string argStr, string[] args) + { + switch (args.Length) + { + case 0: + { + var current = _cfg.GetCVar(CCVars.BabyJailMaxAccountAge); + shell.WriteLine(Loc.GetString("babyjail-command-max-account-age-is", ("minutes", current))); + break; + } + case > 1: + shell.WriteError(Loc.GetString("shell-need-between-arguments",("lower", 0), ("upper", 1))); + return; + } + + if (!int.TryParse(args[0], out var minutes)) + { + shell.WriteError(Loc.GetString("shell-argument-must-be-number")); + return; + } + + _cfg.SetCVar(CCVars.BabyJailMaxAccountAge, minutes); + shell.WriteLine(Loc.GetString("babyjail-command-max-account-age-set", ("minutes", minutes))); + } +} + +[AdminCommand(AdminFlags.Server)] +public sealed class BabyJailMinOverallHoursCommand : LocalizedCommands +{ + [Dependency] private readonly IConfigurationManager _cfg = default!; + + public override string Command => "babyjail_max_overall_minutes"; + + public override void Execute(IConsoleShell shell, string argStr, string[] args) + { + switch (args.Length) + { + case 0: + { + var current = _cfg.GetCVar(CCVars.BabyJailMaxOverallMinutes); + shell.WriteLine(Loc.GetString("babyjail-command-max-overall-minutes-is", ("minutes", current))); + break; + } + case > 1: + shell.WriteError(Loc.GetString("shell-need-between-arguments",("lower", 0), ("upper", 1))); + return; + } + + if (!int.TryParse(args[0], out var hours)) + { + shell.WriteError(Loc.GetString("shell-argument-must-be-number")); + return; + } + + _cfg.SetCVar(CCVars.BabyJailMaxOverallMinutes, hours); + shell.WriteLine(Loc.GetString("babyjail-command-overall-minutes-set", ("hours", hours))); + } +} diff --git a/Content.Server/Administration/Systems/AdminSystem.cs b/Content.Server/Administration/Systems/AdminSystem.cs index 6a59aebfd02a04..16c079e4ba1d23 100644 --- a/Content.Server/Administration/Systems/AdminSystem.cs +++ b/Content.Server/Administration/Systems/AdminSystem.cs @@ -61,6 +61,7 @@ public sealed class AdminSystem : EntitySystem private readonly HashSet _roundActivePlayers = new(); public readonly PanicBunkerStatus PanicBunker = new(); + public readonly BabyJailStatus BabyJail = new(); public override void Initialize() { @@ -70,6 +71,7 @@ public override void Initialize() _adminManager.OnPermsChanged += OnAdminPermsChanged; _playTime.SessionPlayTimeUpdated += OnSessionPlayTimeUpdated; + // Panic Bunker Settings Subs.CVar(_config, CCVars.PanicBunkerEnabled, OnPanicBunkerChanged, true); Subs.CVar(_config, CCVars.PanicBunkerDisableWithAdmins, OnPanicBunkerDisableWithAdminsChanged, true); Subs.CVar(_config, CCVars.PanicBunkerEnableWithoutAdmins, OnPanicBunkerEnableWithoutAdminsChanged, true); @@ -78,6 +80,16 @@ public override void Initialize() Subs.CVar(_config, CCVars.PanicBunkerMinAccountAge, OnPanicBunkerMinAccountAgeChanged, true); Subs.CVar(_config, CCVars.PanicBunkerMinOverallMinutes, OnPanicBunkerMinOverallMinutesChanged, true); + /* + * TODO: Remove baby jail code once a more mature gateway process is established. This code is only being issued as a stopgap to help with potential tiding in the immediate future. + */ + + // Baby Jail Settings + Subs.CVar(_config, CCVars.BabyJailEnabled, OnBabyJailChanged, true); + Subs.CVar(_config, CCVars.BabyJailShowReason, OnBabyJailShowReasonChanged, true); + Subs.CVar(_config, CCVars.BabyJailMaxAccountAge, OnBabyJailMaxAccountAgeChanged, true); + Subs.CVar(_config, CCVars.BabyJailMaxOverallMinutes, OnBabyJailMaxOverallMinutesChanged, true); + SubscribeLocalEvent(OnIdentityChanged); SubscribeLocalEvent(OnPlayerAttached); SubscribeLocalEvent(OnPlayerDetached); @@ -250,6 +262,17 @@ private void OnPanicBunkerChanged(bool enabled) SendPanicBunkerStatusAll(); } + private void OnBabyJailChanged(bool enabled) + { + BabyJail.Enabled = enabled; + _chat.SendAdminAlert(Loc.GetString(enabled + ? "admin-ui-baby-jail-enabled-admin-alert" + : "admin-ui-baby-jail-disabled-admin-alert" + )); + + SendBabyJailStatusAll(); + } + private void OnPanicBunkerDisableWithAdminsChanged(bool enabled) { PanicBunker.DisableWithAdmins = enabled; @@ -274,18 +297,36 @@ private void OnPanicBunkerShowReasonChanged(bool enabled) SendPanicBunkerStatusAll(); } + private void OnBabyJailShowReasonChanged(bool enabled) + { + BabyJail.ShowReason = enabled; + SendBabyJailStatusAll(); + } + private void OnPanicBunkerMinAccountAgeChanged(int minutes) { PanicBunker.MinAccountAgeMinutes = minutes; SendPanicBunkerStatusAll(); } + private void OnBabyJailMaxAccountAgeChanged(int minutes) + { + BabyJail.MaxAccountAgeMinutes = minutes; + SendBabyJailStatusAll(); + } + private void OnPanicBunkerMinOverallMinutesChanged(int minutes) { PanicBunker.MinOverallMinutes = minutes; SendPanicBunkerStatusAll(); } + private void OnBabyJailMaxOverallMinutesChanged(int minutes) + { + BabyJail.MaxOverallMinutes = minutes; + SendBabyJailStatusAll(); + } + private void UpdatePanicBunker() { var admins = PanicBunker.CountDeadminnedAdmins @@ -327,6 +368,15 @@ private void SendPanicBunkerStatusAll() } } + private void SendBabyJailStatusAll() + { + var ev = new BabyJailChangedEvent(BabyJail); + foreach (var admin in _adminManager.AllAdmins) + { + RaiseNetworkEvent(ev, admin); + } + } + /// /// Erases a player from the round. /// This removes them and any trace of them from the round, deleting their diff --git a/Content.Server/Connection/ConnectionManager.cs b/Content.Server/Connection/ConnectionManager.cs index 42732ff1b1cdf3..cf7581aa4e654d 100644 --- a/Content.Server/Connection/ConnectionManager.cs +++ b/Content.Server/Connection/ConnectionManager.cs @@ -17,6 +17,9 @@ using Robust.Shared.Player; using Robust.Shared.Timing; +/* + * TODO: Remove baby jail code once a more mature gateway process is established. This code is only being issued as a stopgap to help with potential tiding in the immediate future. + */ namespace Content.Server.Connection { @@ -248,6 +251,14 @@ session.Status is SessionStatus.Connected or SessionStatus.InGame } } + if (_cfg.GetCVar(CCVars.BabyJailEnabled) && adminData == null) + { + var result = await IsInvalidConnectionDueToBabyJail(userId, e); + + if (result.IsInvalid) + return (ConnectionDenyReason.BabyJail, result.Reason, null); + } + var wasInGame = EntitySystem.TryGet(out var ticker) && ticker.PlayerGameStatuses.TryGetValue(userId, out var status) && status == PlayerGameStatus.JoinedGame; @@ -277,6 +288,61 @@ session.Status is SessionStatus.Connected or SessionStatus.InGame return null; } + private async Task<(bool IsInvalid, string Reason)> IsInvalidConnectionDueToBabyJail(NetUserId userId, NetConnectingArgs e) + { + // If you're whitelisted then bypass this whole thing + if (await _db.GetWhitelistStatusAsync(userId)) + return (false, ""); + + // Initial cvar retrieval + var showReason = _cfg.GetCVar(CCVars.BabyJailShowReason); + var reason = _cfg.GetCVar(CCVars.BabyJailCustomReason); + var maxAccountAgeMinutes = _cfg.GetCVar(CCVars.BabyJailMaxAccountAge); + var maxPlaytimeMinutes = _cfg.GetCVar(CCVars.BabyJailMaxOverallMinutes); + + // Wait some time to lookup data + var record = await _dbManager.GetPlayerRecordByUserId(userId); + + // No player record = new account or the DB is having a skill issue + if (record == null) + return (false, ""); + + var isAccountAgeInvalid = record.FirstSeenTime.CompareTo(DateTimeOffset.Now - TimeSpan.FromMinutes(maxAccountAgeMinutes)) <= 0; + if (isAccountAgeInvalid && showReason) + { + var locAccountReason = reason != string.Empty + ? reason + : Loc.GetString("baby-jail-account-denied-reason", + ("reason", + Loc.GetString( + "baby-jail-account-reason-account", + ("minutes", maxAccountAgeMinutes)))); + + return (true, locAccountReason); + } + + var overallTime = ( await _db.GetPlayTimes(e.UserId)).Find(p => p.Tracker == PlayTimeTrackingShared.TrackerOverall); + var isTotalPlaytimeInvalid = overallTime == null || overallTime.TimeSpent.TotalMinutes >= maxPlaytimeMinutes; + + if (isTotalPlaytimeInvalid && showReason) + { + var locPlaytimeReason = reason != string.Empty + ? reason + : Loc.GetString("baby-jail-account-denied-reason", + ("reason", + Loc.GetString( + "baby-jail-account-reason-overall", + ("minutes", maxPlaytimeMinutes)))); + + return (true, locPlaytimeReason); + } + + if (!showReason && isTotalPlaytimeInvalid || isAccountAgeInvalid) + return (true, Loc.GetString("baby-jail-account-denied")); + + return (false, ""); + } + private bool HasTemporaryBypass(NetUserId user) { return _temporaryBypasses.TryGetValue(user, out var time) && time > _gameTiming.RealTime; diff --git a/Content.Server/GameTicking/GameTicker.StatusShell.cs b/Content.Server/GameTicking/GameTicker.StatusShell.cs index fcf5b1c25cd7e6..67367b94b7f5ab 100644 --- a/Content.Server/GameTicking/GameTicker.StatusShell.cs +++ b/Content.Server/GameTicking/GameTicker.StatusShell.cs @@ -46,6 +46,12 @@ private void GetStatusResponse(JsonNode jObject) jObject["players"] = _playerManager.PlayerCount; jObject["soft_max_players"] = _cfg.GetCVar(CCVars.SoftMaxPlayers); jObject["panic_bunker"] = _cfg.GetCVar(CCVars.PanicBunkerEnabled); + + /* + * TODO: Remove baby jail code once a more mature gateway process is established. This code is only being issued as a stopgap to help with potential tiding in the immediate future. + */ + + jObject["baby_jail"] = _cfg.GetCVar(CCVars.BabyJailEnabled); jObject["run_level"] = (int) _runLevel; if (preset != null) jObject["preset"] = Loc.GetString(preset.ModeTitle); diff --git a/Content.Shared/Administration/Events/BabyJailChangedEvent.cs b/Content.Shared/Administration/Events/BabyJailChangedEvent.cs new file mode 100644 index 00000000000000..56d5ce51626572 --- /dev/null +++ b/Content.Shared/Administration/Events/BabyJailChangedEvent.cs @@ -0,0 +1,22 @@ +using Robust.Shared.Serialization; + +/* + * TODO: Remove baby jail code once a more mature gateway process is established. This code is only being issued as a stopgap to help with potential tiding in the immediate future. + */ + +namespace Content.Shared.Administration.Events; + +[Serializable, NetSerializable] +public sealed class BabyJailStatus +{ + public bool Enabled; + public bool ShowReason; + public int MaxAccountAgeMinutes; + public int MaxOverallMinutes; +} + +[Serializable, NetSerializable] +public sealed class BabyJailChangedEvent(BabyJailStatus status) : EntityEventArgs +{ + public BabyJailStatus Status = status; +} diff --git a/Content.Shared/CCVar/CCVars.cs b/Content.Shared/CCVar/CCVars.cs index 8c70631b945c67..a0e9157e922d9c 100644 --- a/Content.Shared/CCVar/CCVars.cs +++ b/Content.Shared/CCVar/CCVars.cs @@ -332,6 +332,48 @@ public static readonly CVarDef public static readonly CVarDef BypassBunkerWhitelist = CVarDef.Create("game.panic_bunker.whitelisted_can_bypass", true, CVar.SERVERONLY); + /* + * TODO: Remove baby jail code once a more mature gateway process is established. This code is only being issued as a stopgap to help with potential tiding in the immediate future. + */ + + /// + /// Whether the baby jail is currently enabled. + /// + public static readonly CVarDef BabyJailEnabled = + CVarDef.Create("game.baby_jail.enabled", false, CVar.NOTIFY | CVar.REPLICATED | CVar.SERVER); + + /// + /// Show reason of disconnect for user or not. + /// + public static readonly CVarDef BabyJailShowReason = + CVarDef.Create("game.baby_jail.show_reason", false, CVar.SERVERONLY); + + /// + /// Maximum age of the account (from server's PoV, so from first-seen date) in minutes that can access baby + /// jailed servers. + /// + public static readonly CVarDef BabyJailMaxAccountAge = + CVarDef.Create("game.baby_jail.max_account_age", 1440, CVar.SERVERONLY); + + /// + /// Maximum overall played time allowed to access baby jailed servers. + /// + public static readonly CVarDef BabyJailMaxOverallMinutes = + CVarDef.Create("game.baby_jail.max_overall_minutes", 120, CVar.SERVERONLY); + + /// + /// A custom message that will be used for connections denied due to the baby jail. + /// If not empty, then will overwrite + /// + public static readonly CVarDef BabyJailCustomReason = + CVarDef.Create("game.baby_jail.custom_reason", string.Empty, CVar.SERVERONLY); + + /// + /// Allow bypassing the baby jail if the user is whitelisted. + /// + public static readonly CVarDef BypassBabyJailWhitelist = + CVarDef.Create("game.baby_jail.whitelisted_can_bypass", true, CVar.SERVERONLY); + /// /// Make people bonk when trying to climb certain objects like tables. /// diff --git a/Resources/ConfigPresets/WizardsDen/wizardsDenGateway.toml b/Resources/ConfigPresets/WizardsDen/wizardsDenGateway.toml index 787321232609e1..b0f955bddec889 100644 --- a/Resources/ConfigPresets/WizardsDen/wizardsDenGateway.toml +++ b/Resources/ConfigPresets/WizardsDen/wizardsDenGateway.toml @@ -11,6 +11,12 @@ panic_bunker.enabled = false panic_bunker.disable_with_admins = false panic_bunker.enable_without_admins = false panic_bunker.custom_reason = "" +baby_jail.enabled = true +baby_jail.show_reason = true +baby_jail.max_account_age = 5256000 # 10 years. Disabling this check specifically isn't currently supported +baby_jail.max_overall_minutes = 3000 # 50 hours +baby_jail.custom_reason = "Sorry! Only new players can join the servers, try joining another one instead!" +baby_jail.whitelisted_can_bypass = true [hub] tags = "lang:en,region:am_n_e,rp:low" diff --git a/Resources/ConfigPresets/WizardsDen/wizardsDenLRPTide.toml b/Resources/ConfigPresets/WizardsDen/wizardsDenLRPTide.toml index d1cbfb9c905195..21abbf2e3f0702 100644 --- a/Resources/ConfigPresets/WizardsDen/wizardsDenLRPTide.toml +++ b/Resources/ConfigPresets/WizardsDen/wizardsDenLRPTide.toml @@ -8,6 +8,10 @@ soft_max_players = 50 hostname = "[EN] Wizard's Den Granite Flea [US East]" desc = "Official English Space Station 14 servers. Vanilla, roleplay ruleset." +panic_bunker.enabled = false +panic_bunker.disable_with_admins = false +panic_bunker.enable_without_admins = false +panic_bunker.custom_reason = "" [hub] tags = "lang:en,region:am_n_e,rp:low" diff --git a/Resources/Locale/en-US/administration/commands/babyjail.ftl b/Resources/Locale/en-US/administration/commands/babyjail.ftl new file mode 100644 index 00000000000000..5a9d949051755d --- /dev/null +++ b/Resources/Locale/en-US/administration/commands/babyjail.ftl @@ -0,0 +1,19 @@ +cmd-babyjail-desc = Toggles the baby jail, which enables stricter restrictions on who's allowed to join the server. +cmd-babyjail-help = Usage: babyjail +babyjail-command-enabled = Baby jail has been enabled. +babyjail-command-disabled = Baby jail has been disabled. + +cmd-babyjail_show_reason-desc = Toggles whether or not to show connecting clients the reason why the baby jail blocked them from joining. +cmd-babyjail_show_reason-help = Usage: babyjail_show_reason +babyjail-command-show-reason-enabled = The baby jail will now show a reason to users it blocks from connecting. +babyjail-command-show-reason-disabled = The baby jail will no longer show a reason to users it blocks from connecting. + +cmd-babyjail_max_account_age-desc = Gets or sets the maximum account age in minutes that an account can have to be allowed to connect with the baby jail enabled. +cmd-babyjail_max_account_age-help = Usage: babyjail_max_account_age +babyjail-command-max-account-age-is = The maximum account age for the baby jail is {$minutes} minutes. +babyjail-command-max-account-age-set = Set the maximum account age for the baby jail to {$minutes} minutes. + +cmd-babyjail_max_overall_minutes-desc = Gets or sets the maximum overall playtime in minutes that an account can have to be allowed to connect with the baby jail enabled. +cmd-babyjail_max_overall_minutes-help = Usage: babyjail_max_overall_minutes +babyjail-command-max-overall-minutes-is = The maximum overall playtime for the baby jail is {$minutes} minutes. +babyjail-command-max-overall-minutes-set = Set the maximum overall playtime for the baby jail to {$minutes} minutes. diff --git a/Resources/Locale/en-US/administration/ui/admin-menu-window.ftl b/Resources/Locale/en-US/administration/ui/admin-menu-window.ftl index c759e4c2cb16f2..03b2046a9e15ba 100644 --- a/Resources/Locale/en-US/administration/ui/admin-menu-window.ftl +++ b/Resources/Locale/en-US/administration/ui/admin-menu-window.ftl @@ -7,5 +7,6 @@ admin-menu-atmos-tab = Atmos admin-menu-round-tab = Round admin-menu-server-tab = Server admin-menu-panic-bunker-tab = Panic Bunker +admin-menu-baby-jail-tab = Baby Jail admin-menu-players-tab = Players admin-menu-objects-tab = Objects diff --git a/Resources/Locale/en-US/administration/ui/tabs/babyjail-tab.ftl b/Resources/Locale/en-US/administration/ui/tabs/babyjail-tab.ftl new file mode 100644 index 00000000000000..46dce54c1fc85d --- /dev/null +++ b/Resources/Locale/en-US/administration/ui/tabs/babyjail-tab.ftl @@ -0,0 +1,16 @@ +admin-ui-baby-jail-window-title = Baby Jail + +admin-ui-baby-jail-enabled = Baby Jail Enabled +admin-ui-baby-jail-disabled = Baby Jail Disabled +admin-ui-baby-jail-tooltip = The baby jail restricts players from joining if their account is too old or they do have too much overall playtime on this server. + +admin-ui-baby-jail-show-reason = Show Reason +admin-ui-baby-jail-show-reason-tooltip = Show the user why they were blocked from connecting by the baby jail. + +admin-ui-baby-jail-max-account-age = Max. Account Age +admin-ui-baby-jail-max-overall-minutes = Max. Overall Playtime + +admin-ui-baby-jail-is-enabled = [font size=20][bold]The baby jail is currently enabled.[/bold][/font] + +admin-ui-baby-jail-enabled-admin-alert = The baby jail has been enabled. +admin-ui-baby-jail-disabled-admin-alert = The baby jail has been disabled. diff --git a/Resources/Locale/en-US/connection-messages.ftl b/Resources/Locale/en-US/connection-messages.ftl index 65796b9c795f63..f1596d90152bf4 100644 --- a/Resources/Locale/en-US/connection-messages.ftl +++ b/Resources/Locale/en-US/connection-messages.ftl @@ -40,3 +40,8 @@ panic-bunker-account-denied-reason = This server is in panic bunker mode, often panic-bunker-account-reason-account = Your Space Station 14 account is too new. It must be older than {$minutes} minutes panic-bunker-account-reason-overall = Your overall playtime on the server must be greater than {$minutes} $minutes +baby-jail-account-denied = This server is a newbie server, intended for new players and those who want to help them. New connections by accounts that are too old or are not on a whitelist are not accepted. Check out some other servers and see everything Space Station 14 has to offer. Have fun! +baby-jail-account-denied-reason = This server is a newbie server, intended for new players and those who want to help them. New connections by accounts that are too old or are not on a whitelist are not accepted. Check out some other servers and see everything Space Station 14 has to offer. Have fun! Reason: "{$reason}" +baby-jail-account-reason-account = Your Space Station 14 account is too old. It must be younger than {$minutes} minutes +baby-jail-account-reason-overall = Your overall playtime on the server must be younger than {$minutes} $minutes +