]> git.smokeofanarchy.ru Git - space-station-14.git/commitdiff
Add panic bunker UI and automatic panic bunker (#20954)
authorDrSmugleaf <DrSmugleaf@users.noreply.github.com>
Fri, 13 Oct 2023 18:56:12 +0000 (11:56 -0700)
committerGitHub <noreply@github.com>
Fri, 13 Oct 2023 18:56:12 +0000 (11:56 -0700)
20 files changed:
Content.Client/Administration/UI/AdminMenuWindow.xaml
Content.Client/Administration/UI/AdminMenuWindow.xaml.cs
Content.Client/Administration/UI/Tabs/PanicBunkerTab/PanicBunkerStatusWindow.xaml [new file with mode: 0644]
Content.Client/Administration/UI/Tabs/PanicBunkerTab/PanicBunkerStatusWindow.xaml.cs [new file with mode: 0644]
Content.Client/Administration/UI/Tabs/PanicBunkerTab/PanicBunkerTab.xaml [new file with mode: 0644]
Content.Client/Administration/UI/Tabs/PanicBunkerTab/PanicBunkerTab.xaml.cs [new file with mode: 0644]
Content.Client/Administration/UI/Tabs/ServerTab.xaml
Content.Client/Administration/UI/Tabs/ServerTab.xaml.cs
Content.Client/UserInterface/Systems/Admin/AdminUIController.cs
Content.Server/Administration/Commands/PanicBunkerCommand.cs
Content.Server/Administration/Systems/AdminSystem.cs
Content.Shared/Administration/Events/PanicBunkerChangedEvent.cs [new file with mode: 0644]
Content.Shared/CCVar/CCVars.cs
Resources/Changelog/Admin.yml
Resources/Locale/en-US/administration/commands/panicbunker.ftl
Resources/Locale/en-US/administration/ui/admin-menu-window.ftl
Resources/Locale/en-US/administration/ui/tabs/panicbunker-tab.ftl [new file with mode: 0644]
Resources/Locale/en-US/administration/ui/tabs/server-tab.ftl
Resources/Locale/en-US/generic.ftl
SpaceStation14.sln.DotSettings

index 49eb9c0de603755d6efa17e2bfe02d4cbc43be6d..311d67b826c7a2aad1711832d6917c95a257b322 100644 (file)
@@ -5,13 +5,15 @@
     xmlns:atmosTab="clr-namespace:Content.Client.Administration.UI.Tabs.AtmosTab"
     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:objectsTab="clr-namespace:Content.Client.Administration.UI.Tabs.ObjectsTab"
+    xmlns:panic="clr-namespace:Content.Client.Administration.UI.Tabs.PanicBunkerTab">
     <TabContainer Name="MasterTabContainer">
         <adminTab:AdminTab />
         <adminbusTab:AdminbusTab />
         <atmosTab:AtmosTab />
         <tabs:RoundTab />
         <tabs:ServerTab />
+        <panic:PanicBunkerTab Name="PanicBunkerControl" Access="Public" />
         <playerTab:PlayerTab Name="PlayerTabControl" Access="Public" />
         <objectsTab:ObjectsTab Name="ObjectsTabControl" Access="Public" />
     </TabContainer>
index d4dfcc2042e143b21d17081cbea60ca985fa8f61..c3ea67a3edb91d30162836bf1416e5cba7b7cabd 100644 (file)
@@ -12,7 +12,7 @@ namespace Content.Client.Administration.UI
 
         public AdminMenuWindow()
         {
-            MinSize = new Vector2(500, 250);
+            MinSize = new Vector2(650, 250);
             Title = Loc.GetString("admin-menu-title");
             RobustXamlLoader.Load(this);
             MasterTabContainer.SetTabTitle(0, Loc.GetString("admin-menu-admin-tab"));
@@ -20,8 +20,9 @@ namespace Content.Client.Administration.UI
             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-players-tab"));
-            MasterTabContainer.SetTabTitle(6, Loc.GetString("admin-menu-objects-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"));
         }
 
         protected override void Dispose(bool disposing)
diff --git a/Content.Client/Administration/UI/Tabs/PanicBunkerTab/PanicBunkerStatusWindow.xaml b/Content.Client/Administration/UI/Tabs/PanicBunkerTab/PanicBunkerStatusWindow.xaml
new file mode 100644 (file)
index 0000000..633bef0
--- /dev/null
@@ -0,0 +1,6 @@
+<controls:PanicBunkerStatusWindow
+    xmlns="https://spacestation14.io"
+    xmlns:controls="clr-namespace:Content.Client.Administration.UI.Tabs.PanicBunkerTab"
+    Title="{Loc admin-ui-panic-bunker-window-title}">
+    <Label Name="MessageLabel" Access="Public" Text="{Loc admin-ui-panic-bunker-is-enabled}" />
+</controls:PanicBunkerStatusWindow>
diff --git a/Content.Client/Administration/UI/Tabs/PanicBunkerTab/PanicBunkerStatusWindow.xaml.cs b/Content.Client/Administration/UI/Tabs/PanicBunkerTab/PanicBunkerStatusWindow.xaml.cs
new file mode 100644 (file)
index 0000000..ec16bf6
--- /dev/null
@@ -0,0 +1,14 @@
+using Robust.Client.AutoGenerated;
+using Robust.Client.UserInterface.CustomControls;
+using Robust.Client.UserInterface.XAML;
+
+namespace Content.Client.Administration.UI.Tabs.PanicBunkerTab;
+
+[GenerateTypedNameReferences]
+public sealed partial class PanicBunkerStatusWindow : DefaultWindow
+{
+    public PanicBunkerStatusWindow()
+    {
+        RobustXamlLoader.Load(this);
+    }
+}
diff --git a/Content.Client/Administration/UI/Tabs/PanicBunkerTab/PanicBunkerTab.xaml b/Content.Client/Administration/UI/Tabs/PanicBunkerTab/PanicBunkerTab.xaml
new file mode 100644 (file)
index 0000000..89827d0
--- /dev/null
@@ -0,0 +1,43 @@
+<controls:PanicBunkerTab
+    xmlns="https://spacestation14.io"
+    xmlns:controls="clr-namespace:Content.Client.Administration.UI.Tabs.PanicBunkerTab"
+    xmlns:cc="clr-namespace:Content.Client.Administration.UI.CustomControls"
+    Margin="4">
+    <BoxContainer Orientation="Vertical">
+        <cc:CommandButton Name="EnabledButton" Command="panicbunker" ToggleMode="True"
+                          Text="{Loc admin-ui-panic-bunker-disabled}"
+                          ToolTip="{Loc admin-ui-panic-bunker-tooltip}" />
+        <BoxContainer Orientation="Horizontal">
+            <cc:CommandButton Name="DisableAutomaticallyButton" HorizontalExpand="True"
+                              Command="panicbunker_disable_with_admins"
+                              ToggleMode="True"
+                              Text="{Loc admin-ui-panic-bunker-disable-automatically}"
+                              ToolTip="{Loc admin-ui-panic-bunker-disable-automatically-tooltip}" />
+            <cc:CommandButton Name="EnableAutomaticallyButton" HorizontalExpand="True"
+                              Command="panicbunker_enable_without_admins"
+                              ToggleMode="True"
+                              Text="{Loc admin-ui-panic-bunker-enable-automatically}"
+                              ToolTip="{Loc admin-ui-panic-bunker-enable-automatically-tooltip}" />
+            <cc:CommandButton Name="CountDeadminnedButton" HorizontalExpand="True"
+                              Command="panicbunker_count_deadminned_admins"
+                              ToggleMode="True"
+                              Text="{Loc admin-ui-panic-bunker-count-deadminned-admins}"
+                              ToolTip="{Loc admin-ui-panic-bunker-count-deadminned-admins-tooltip}" />
+        </BoxContainer>
+        <cc:CommandButton Name="ShowReasonButton" Command="panicbunker_show_reason"
+                          ToggleMode="True" Text="{Loc admin-ui-panic-bunker-show-reason}"
+                          ToolTip="{Loc admin-ui-panic-bunker-show-reason-tooltip}" />
+        <BoxContainer Orientation="Vertical" Margin="0 10 0 0">
+            <BoxContainer Orientation="Horizontal" Margin="2">
+                <Label Text="{Loc admin-ui-panic-bunker-min-account-age}" MinWidth="175" />
+                <LineEdit Name="MinAccountAge" MinWidth="50" Margin="0 0 5 0" />
+                <Label Text="{Loc generic-hours}" />
+            </BoxContainer>
+            <BoxContainer Orientation="Horizontal" Margin="2">
+                <Label Text="{Loc admin-ui-panic-bunker-min-overall-hours}" MinWidth="175" />
+                <LineEdit Name="MinOverallHours" MinWidth="50" Margin="0 0 5 0" />
+                <Label Text="{Loc generic-hours}" />
+            </BoxContainer>
+        </BoxContainer>
+    </BoxContainer>
+</controls:PanicBunkerTab>
diff --git a/Content.Client/Administration/UI/Tabs/PanicBunkerTab/PanicBunkerTab.xaml.cs b/Content.Client/Administration/UI/Tabs/PanicBunkerTab/PanicBunkerTab.xaml.cs
new file mode 100644 (file)
index 0000000..e9d3b95
--- /dev/null
@@ -0,0 +1,54 @@
+using Content.Shared.Administration.Events;
+using Robust.Client.AutoGenerated;
+using Robust.Client.UserInterface;
+using Robust.Client.UserInterface.XAML;
+using Robust.Shared.Console;
+
+namespace Content.Client.Administration.UI.Tabs.PanicBunkerTab;
+
+[GenerateTypedNameReferences]
+public sealed partial class PanicBunkerTab : Control
+{
+    [Dependency] private readonly IConsoleHost _console = default!;
+
+    public PanicBunkerTab()
+    {
+        RobustXamlLoader.Load(this);
+        IoCManager.InjectDependencies(this);
+
+        DisableAutomaticallyButton.ToolTip = Loc.GetString("admin-ui-panic-bunker-disable-automatically-tooltip");
+
+        MinAccountAge.OnTextEntered += args =>
+        {
+            if (string.IsNullOrWhiteSpace(args.Text) || !int.TryParse(args.Text, out var minutes))
+                return;
+
+            _console.ExecuteCommand($"panicbunker_min_account_age {minutes}");
+        };
+
+        MinOverallHours.OnTextEntered += args =>
+        {
+            if (string.IsNullOrWhiteSpace(args.Text) || !int.TryParse(args.Text, out var hours))
+                return;
+
+            _console.ExecuteCommand($"panicbunker_min_overall_hours {hours}");
+        };
+    }
+
+    public void UpdateStatus(PanicBunkerStatus status)
+    {
+        EnabledButton.Pressed = status.Enabled;
+        EnabledButton.Text = Loc.GetString(status.Enabled
+            ? "admin-ui-panic-bunker-enabled"
+            : "admin-ui-panic-bunker-disabled"
+        );
+        EnabledButton.ModulateSelfOverride = status.Enabled ? Color.Red : null;
+
+        DisableAutomaticallyButton.Pressed = status.DisableWithAdmins;
+        EnableAutomaticallyButton.Pressed = status.EnableWithoutAdmins;
+        CountDeadminnedButton.Pressed = status.CountDeadminnedAdmins;
+        ShowReasonButton.Pressed = status.ShowReason;
+        MinAccountAge.Text = status.MinAccountAgeHours.ToString();
+        MinOverallHours.Text = status.MinOverallHours.ToString();
+    }
+}
index 7e15bc27539a16eac7003508886addd68414f562..b9984058358c4b2bb664fc394db4afec815f23ca 100644 (file)
@@ -8,6 +8,5 @@
         <cc:CommandButton Command="shutdown" Text="{Loc server-shutdown}" />
         <cc:CommandButton Name="SetOocButton" Command="setooc" Text="{Loc server-ooc-toggle}" ToggleMode="True" />
         <cc:CommandButton Name="SetLoocButton" Command="setlooc" Text="{Loc server-looc-toggle}" ToggleMode="True" />
-        <cc:CommandButton Name="SetPanicbunkerButton" Command="panicbunker" Text="{Loc server-panicbunker-toggle}" ToggleMode="True" />
     </GridContainer>
 </Control>
index b83a3d1ec0301874b081fc5cf9656a47792b5f0e..24b92e42ce784d7b7a1f8682d1f3ca9b1e7dbdd2 100644 (file)
@@ -18,7 +18,6 @@ namespace Content.Client.Administration.UI.Tabs
 
             _config.OnValueChanged(CCVars.OocEnabled, OocEnabledChanged, true);
             _config.OnValueChanged(CCVars.LoocEnabled, LoocEnabledChanged, true);
-            _config.OnValueChanged(CCVars.PanicBunkerEnabled, BunkerEnabledChanged, true);
         }
 
         private void OocEnabledChanged(bool value)
@@ -31,11 +30,6 @@ namespace Content.Client.Administration.UI.Tabs
             SetLoocButton.Pressed = value;
         }
 
-        private void BunkerEnabledChanged(bool value)
-        {
-            SetPanicbunkerButton.Pressed = value;
-        }
-
         protected override void Dispose(bool disposing)
         {
             base.Dispose(disposing);
@@ -44,7 +38,6 @@ namespace Content.Client.Administration.UI.Tabs
             {
                 _config.UnsubValueChanged(CCVars.OocEnabled, OocEnabledChanged);
                 _config.UnsubValueChanged(CCVars.LoocEnabled, LoocEnabledChanged);
-                _config.UnsubValueChanged(CCVars.PanicBunkerEnabled, BunkerEnabledChanged);
             }
         }
     }
index 47b93fdb09a34be12ecad33b667bce5f0cb0f774..4a7a57e5272f2cc80ae8e7d802ba370b9b100ab5 100644 (file)
@@ -2,11 +2,13 @@
 using Content.Client.Administration.Systems;
 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.PlayerTab;
 using Content.Client.Gameplay;
 using Content.Client.Lobby;
 using Content.Client.UserInterface.Controls;
 using Content.Client.Verbs.UI;
+using Content.Shared.Administration.Events;
 using Content.Shared.Input;
 using JetBrains.Annotations;
 using Robust.Client.Console;
@@ -30,6 +32,25 @@ public sealed class AdminUIController : UIController, IOnStateEntered<GameplaySt
 
     private AdminMenuWindow? _window;
     private MenuButton? AdminButton => UIManager.GetActiveUIWidgetOrNull<MenuBar.Widgets.GameTopMenuBar>()?.AdminButton;
+    private PanicBunkerStatus? _panicBunker;
+
+    public override void Initialize()
+    {
+        base.Initialize();
+        SubscribeNetworkEvent<PanicBunkerChangedEvent>(OnPanicBunkerUpdated);
+    }
+
+    private void OnPanicBunkerUpdated(PanicBunkerChangedEvent msg, EntitySessionEventArgs args)
+    {
+        var showDialog = _panicBunker == null && msg.Status.Enabled;
+        _panicBunker = msg.Status;
+        _window?.PanicBunkerControl.UpdateStatus(msg.Status);
+
+        if (showDialog)
+        {
+            UIManager.CreateWindow<PanicBunkerStatusWindow>().OpenCentered();
+        }
+    }
 
     public void OnStateEntered(GameplayState state)
     {
@@ -73,6 +94,9 @@ public sealed class AdminUIController : UIController, IOnStateEntered<GameplaySt
         _window = UIManager.CreateWindow<AdminMenuWindow>();
         LayoutContainer.SetAnchorPreset(_window, LayoutContainer.LayoutPreset.Center);
 
+        if (_panicBunker != null)
+            _window.PanicBunkerControl.UpdateStatus(_panicBunker);
+
         _window.PlayerTabControl.OnEntryPressed += PlayerTabEntryPressed;
         _window.ObjectsTabControl.OnEntryPressed += ObjectsTabEntryPressed;
         _window.OnOpen += OnWindowOpen;
index 0273ac313d688a75d3cc6fd2e7de483306234e45..de3f3cbaea2b6b5f483f8fa379b45a5e071ba798 100644 (file)
@@ -6,36 +6,187 @@ using Robust.Shared.Console;
 namespace Content.Server.Administration.Commands;
 
 [AdminCommand(AdminFlags.Server)]
-public sealed class PanicBunkerCommand : IConsoleCommand
+public sealed class PanicBunkerCommand : LocalizedCommands
 {
     [Dependency] private readonly IConfigurationManager _cfg = default!;
 
-    public string Command => "panicbunker";
-    public string Description => "Enables or disables the panic bunker functionality.";
-    public string Help => "panicbunker";
-    public void Execute(IConsoleShell shell, string argStr, string[] args)
+    public override string Command => "panicbunker";
+
+    public override void Execute(IConsoleShell shell, string argStr, string[] args)
+    {
+        var toggle = Toggle(CCVars.PanicBunkerEnabled, shell, args, _cfg);
+        if (toggle == null)
+            return;
+
+        shell.WriteLine(Loc.GetString(toggle.Value ? "panicbunker-command-enabled" : "panicbunker-command-disabled"));
+    }
+
+    public static bool? Toggle(CVarDef<bool> cvar, IConsoleShell shell, string[] args, IConfigurationManager config)
     {
         if (args.Length > 1)
         {
             shell.WriteError(Loc.GetString("shell-need-between-arguments",("lower", 0), ("upper", 1)));
-            return;
+            return null;
         }
 
-        var enabled = _cfg.GetCVar(CCVars.PanicBunkerEnabled);
-        
+        var enabled = config.GetCVar(cvar);
+
         if (args.Length == 0)
         {
             enabled = !enabled;
         }
-        
+
         if (args.Length == 1 && !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 PanicBunkerDisableWithAdminsCommand : LocalizedCommands
+{
+    [Dependency] private readonly IConfigurationManager _cfg = default!;
+
+    public override string Command => "panicbunker_disable_with_admins";
+
+    public override void Execute(IConsoleShell shell, string argStr, string[] args)
+    {
+        var toggle = PanicBunkerCommand.Toggle(CCVars.PanicBunkerDisableWithAdmins, shell, args, _cfg);
+        if (toggle == null)
+            return;
+
+        shell.WriteLine(Loc.GetString(toggle.Value
+            ? "panicbunker-command-disable-with-admins-enabled"
+            : "panicbunker-command-disable-with-admins-disabled"
+        ));
+    }
+}
+
+[AdminCommand(AdminFlags.Server)]
+public sealed class PanicBunkerEnableWithoutAdminsCommand : LocalizedCommands
+{
+    [Dependency] private readonly IConfigurationManager _cfg = default!;
+
+    public override string Command => "panicbunker_enable_without_admins";
+
+    public override void Execute(IConsoleShell shell, string argStr, string[] args)
+    {
+        var toggle = PanicBunkerCommand.Toggle(CCVars.PanicBunkerEnableWithoutAdmins, shell, args, _cfg);
+        if (toggle == null)
+            return;
+
+        shell.WriteLine(Loc.GetString(toggle.Value
+            ? "panicbunker-command-enable-without-admins-enabled"
+            : "panicbunker-command-enable-without-admins-disabled"
+        ));
+    }
+}
+
+[AdminCommand(AdminFlags.Server)]
+public sealed class PanicBunkerCountDeadminnedCommand : LocalizedCommands
+{
+    [Dependency] private readonly IConfigurationManager _cfg = default!;
+
+    public override string Command => "panicbunker_count_deadminned_admins";
+
+    public override void Execute(IConsoleShell shell, string argStr, string[] args)
+    {
+        var toggle = PanicBunkerCommand.Toggle(CCVars.PanicBunkerCountDeadminnedAdmins, shell, args, _cfg);
+        if (toggle == null)
+            return;
+
+        shell.WriteLine(Loc.GetString(toggle.Value
+            ? "panicbunker-command-count-deadminned-admins-enabled"
+            : "panicbunker-command-count-deadminned-admins-disabled"
+        ));
+    }
+}
+
+[AdminCommand(AdminFlags.Server)]
+public sealed class PanicBunkerShowReasonCommand : LocalizedCommands
+{
+    [Dependency] private readonly IConfigurationManager _cfg = default!;
+
+    public override string Command => "panicbunker_show_reason";
+
+    public override void Execute(IConsoleShell shell, string argStr, string[] args)
+    {
+        var toggle = PanicBunkerCommand.Toggle(CCVars.PanicBunkerShowReason, shell, args, _cfg);
+        if (toggle == null)
+            return;
+
+        shell.WriteLine(Loc.GetString(toggle.Value
+            ? "panicbunker-command-show-reason-enabled"
+            : "panicbunker-command-show-reason-disabled"
+        ));
+    }
+}
+
+[AdminCommand(AdminFlags.Server)]
+public sealed class PanicBunkerMinAccountAgeCommand : LocalizedCommands
+{
+    [Dependency] private readonly IConfigurationManager _cfg = default!;
+
+    public override string Command => "panicbunker_min_account_age";
+
+    public override void Execute(IConsoleShell shell, string argStr, string[] args)
+    {
+        if (args.Length == 0)
+        {
+            var current = _cfg.GetCVar(CCVars.PanicBunkerMinAccountAge);
+            shell.WriteLine(Loc.GetString("panicbunker-command-min-account-age-is", ("hours", current / 60)));
+        }
+
+        if (args.Length > 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.PanicBunkerMinAccountAge, hours * 60);
+        shell.WriteLine(Loc.GetString("panicbunker-command-min-account-age-set", ("hours", hours)));
+    }
+}
+
+[AdminCommand(AdminFlags.Server)]
+public sealed class PanicBunkerMinOverallHoursCommand : LocalizedCommands
+{
+    [Dependency] private readonly IConfigurationManager _cfg = default!;
+
+    public override string Command => "panicbunker_min_overall_hours";
+
+    public override void Execute(IConsoleShell shell, string argStr, string[] args)
+    {
+        if (args.Length == 0)
+        {
+            var current = _cfg.GetCVar(CCVars.PanicBunkerMinOverallHours);
+            shell.WriteLine(Loc.GetString("panicbunker-command-min-overall-hours-is", ("minutes", current)));
+        }
+
+        if (args.Length > 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.PanicBunkerEnabled, enabled);
-        
-        shell.WriteLine(Loc.GetString(enabled ? "panicbunker-command-enabled" : "panicbunker-command-disabled"));
+        _cfg.SetCVar(CCVars.PanicBunkerMinOverallHours, hours);
+        shell.WriteLine(Loc.GetString("panicbunker-command-overall-hours-age-set", ("hours", hours)));
     }
 }
index d54a7a2092a63085567ad4aa15ed8e9dc1e86d92..8851680aea6336252d312f0a15d8b8aae5f48e7b 100644 (file)
@@ -1,15 +1,18 @@
 using System.Linq;
 using Content.Server.Administration.Managers;
+using Content.Server.Chat.Managers;
 using Content.Server.IdentityManagement;
 using Content.Server.Mind;
 using Content.Shared.Administration;
 using Content.Shared.Administration.Events;
+using Content.Shared.CCVar;
 using Content.Shared.GameTicking;
 using Content.Shared.IdentityManagement;
 using Content.Shared.Roles;
 using Content.Shared.Roles.Jobs;
 using Robust.Server.GameObjects;
 using Robust.Server.Player;
+using Robust.Shared.Configuration;
 using Robust.Shared.Enums;
 using Robust.Shared.Network;
 using Robust.Shared.Player;
@@ -18,8 +21,10 @@ namespace Content.Server.Administration.Systems
 {
     public sealed class AdminSystem : EntitySystem
     {
-        [Dependency] private readonly IPlayerManager _playerManager = default!;
         [Dependency] private readonly IAdminManager _adminManager = default!;
+        [Dependency] private readonly IChatManager _chat = default!;
+        [Dependency] private readonly IConfigurationManager _config = default!;
+        [Dependency] private readonly IPlayerManager _playerManager = default!;
         [Dependency] private readonly SharedJobSystem _jobs = default!;
         [Dependency] private readonly MindSystem _minds = default!;
         [Dependency] private readonly SharedRoleSystem _role = default!;
@@ -32,6 +37,7 @@ namespace Content.Server.Administration.Systems
         public IReadOnlySet<NetUserId> RoundActivePlayers => _roundActivePlayers;
 
         private readonly HashSet<NetUserId> _roundActivePlayers = new();
+        private readonly PanicBunkerStatus _panicBunker = new();
 
         public override void Initialize()
         {
@@ -39,6 +45,15 @@ namespace Content.Server.Administration.Systems
 
             _playerManager.PlayerStatusChanged += OnPlayerStatusChanged;
             _adminManager.OnPermsChanged += OnAdminPermsChanged;
+
+            _config.OnValueChanged(CCVars.PanicBunkerEnabled, OnPanicBunkerChanged, true);
+            _config.OnValueChanged(CCVars.PanicBunkerDisableWithAdmins, OnPanicBunkerDisableWithAdminsChanged, true);
+            _config.OnValueChanged(CCVars.PanicBunkerEnableWithoutAdmins, OnPanicBunkerEnableWithoutAdminsChanged, true);
+            _config.OnValueChanged(CCVars.PanicBunkerCountDeadminnedAdmins, OnPanicBunkerCountDeadminnedAdminsChanged, true);
+            _config.OnValueChanged(CCVars.PanicBunkerShowReason, OnShowReasonChanged, true);
+            _config.OnValueChanged(CCVars.PanicBunkerMinAccountAge, OnPanicBunkerMinAccountAgeChanged, true);
+            _config.OnValueChanged(CCVars.PanicBunkerMinOverallHours, OnPanicBunkerMinOverallHoursChanged, true);
+
             SubscribeLocalEvent<IdentityChangedEvent>(OnIdentityChanged);
             SubscribeLocalEvent<PlayerAttachedEvent>(OnPlayerAttached);
             SubscribeLocalEvent<PlayerDetachedEvent>(OnPlayerDetached);
@@ -114,7 +129,9 @@ namespace Content.Server.Administration.Systems
 
         private void OnAdminPermsChanged(AdminPermsChangedEventArgs obj)
         {
-            if(!obj.IsAdmin)
+            UpdatePanicBunker();
+
+            if (!obj.IsAdmin)
             {
                 RaiseNetworkEvent(new FullPlayerListEvent(), obj.Player.ConnectedClient);
                 return;
@@ -127,14 +144,16 @@ namespace Content.Server.Administration.Systems
         {
             // If disconnected then the player won't have a connected entity to get character name from.
             // The disconnected state gets sent by OnPlayerStatusChanged.
-            if(ev.Player.Status == SessionStatus.Disconnected) return;
+            if (ev.Player.Status == SessionStatus.Disconnected)
+                return;
 
             UpdatePlayerList(ev.Player);
         }
 
         private void OnPlayerAttached(PlayerAttachedEvent ev)
         {
-            if(ev.Player.Status == SessionStatus.Disconnected) return;
+            if (ev.Player.Status == SessionStatus.Disconnected)
+                return;
 
             _roundActivePlayers.Add(ev.Player.UserId);
             UpdatePlayerList(ev.Player);
@@ -145,11 +164,20 @@ namespace Content.Server.Administration.Systems
             base.Shutdown();
             _playerManager.PlayerStatusChanged -= OnPlayerStatusChanged;
             _adminManager.OnPermsChanged -= OnAdminPermsChanged;
+
+            _config.UnsubValueChanged(CCVars.PanicBunkerEnabled, OnPanicBunkerChanged);
+            _config.UnsubValueChanged(CCVars.PanicBunkerDisableWithAdmins, OnPanicBunkerDisableWithAdminsChanged);
+            _config.UnsubValueChanged(CCVars.PanicBunkerEnableWithoutAdmins, OnPanicBunkerEnableWithoutAdminsChanged);
+            _config.UnsubValueChanged(CCVars.PanicBunkerCountDeadminnedAdmins, OnPanicBunkerCountDeadminnedAdminsChanged);
+            _config.UnsubValueChanged(CCVars.PanicBunkerShowReason, OnShowReasonChanged);
+            _config.UnsubValueChanged(CCVars.PanicBunkerMinAccountAge, OnPanicBunkerMinAccountAgeChanged);
+            _config.UnsubValueChanged(CCVars.PanicBunkerMinOverallHours, OnPanicBunkerMinOverallHoursChanged);
         }
 
         private void OnPlayerStatusChanged(object? sender, SessionStatusEventArgs e)
         {
             UpdatePlayerList(e.Session);
+            UpdatePanicBunker();
         }
 
         private void SendFullPlayerList(IPlayerSession playerSession)
@@ -186,5 +214,80 @@ namespace Content.Server.Administration.Systems
             return new PlayerInfo(name, entityName, identityName, startingRole, antag, GetNetEntity(session?.AttachedEntity), data.UserId,
                 connected, _roundActivePlayers.Contains(data.UserId));
         }
+
+        private void OnPanicBunkerChanged(bool enabled)
+        {
+            _panicBunker.Enabled = enabled;
+            _chat.SendAdminAlert(Loc.GetString(enabled
+                ? "admin-ui-panic-bunker-enabled-admin-alert"
+                : "admin-ui-panic-bunker-disabled-admin-alert"
+            ));
+
+            SendPanicBunkerStatusAll();
+        }
+
+        private void OnPanicBunkerDisableWithAdminsChanged(bool enabled)
+        {
+            _panicBunker.DisableWithAdmins = enabled;
+            UpdatePanicBunker();
+        }
+
+        private void OnPanicBunkerEnableWithoutAdminsChanged(bool enabled)
+        {
+            _panicBunker.EnableWithoutAdmins = enabled;
+            UpdatePanicBunker();
+        }
+
+        private void OnPanicBunkerCountDeadminnedAdminsChanged(bool enabled)
+        {
+            _panicBunker.CountDeadminnedAdmins = enabled;
+            UpdatePanicBunker();
+        }
+
+        private void OnShowReasonChanged(bool enabled)
+        {
+            _panicBunker.ShowReason = enabled;
+            SendPanicBunkerStatusAll();
+        }
+
+        private void OnPanicBunkerMinAccountAgeChanged(int minutes)
+        {
+            _panicBunker.MinAccountAgeHours = minutes / 60;
+            SendPanicBunkerStatusAll();
+        }
+
+        private void OnPanicBunkerMinOverallHoursChanged(int hours)
+        {
+            _panicBunker.MinOverallHours = hours;
+            SendPanicBunkerStatusAll();
+        }
+
+        private void UpdatePanicBunker()
+        {
+            var admins = _panicBunker.CountDeadminnedAdmins
+                ? _adminManager.AllAdmins
+                : _adminManager.ActiveAdmins;
+            var hasAdmins = admins.Any();
+
+            if (hasAdmins && _panicBunker.DisableWithAdmins)
+            {
+                _config.SetCVar(CCVars.PanicBunkerEnabled, false);
+            }
+            else if (!hasAdmins && _panicBunker.EnableWithoutAdmins)
+            {
+                _config.SetCVar(CCVars.PanicBunkerEnabled, true);
+            }
+
+            SendPanicBunkerStatusAll();
+        }
+
+        private void SendPanicBunkerStatusAll()
+        {
+            var ev = new PanicBunkerChangedEvent(_panicBunker);
+            foreach (var admin in _adminManager.AllAdmins)
+            {
+                RaiseNetworkEvent(ev, admin);
+            }
+        }
     }
 }
diff --git a/Content.Shared/Administration/Events/PanicBunkerChangedEvent.cs b/Content.Shared/Administration/Events/PanicBunkerChangedEvent.cs
new file mode 100644 (file)
index 0000000..f809b67
--- /dev/null
@@ -0,0 +1,26 @@
+using Robust.Shared.Serialization;
+
+namespace Content.Shared.Administration.Events;
+
+[Serializable, NetSerializable]
+public sealed class PanicBunkerStatus
+{
+    public bool Enabled;
+    public bool DisableWithAdmins;
+    public bool EnableWithoutAdmins;
+    public bool CountDeadminnedAdmins;
+    public bool ShowReason;
+    public int MinAccountAgeHours;
+    public int MinOverallHours;
+}
+
+[Serializable, NetSerializable]
+public sealed class PanicBunkerChangedEvent : EntityEventArgs
+{
+    public PanicBunkerStatus Status;
+
+    public PanicBunkerChangedEvent(PanicBunkerStatus status)
+    {
+        Status = status;
+    }
+}
index ccc8b6d51dc6a4dc8db3b1c8f9562cc7c7601867..0cf374fe4dea801bd3cf094f51055d6730225276 100644 (file)
@@ -248,6 +248,26 @@ namespace Content.Shared.CCVar
         public static readonly CVarDef<bool> PanicBunkerEnabled =
             CVarDef.Create("game.panic_bunker.enabled", false, CVar.NOTIFY | CVar.REPLICATED);
 
+        /// <summary>
+        /// Whether or not the panic bunker will disable when an admin comes online.
+        /// </summary>
+        public static readonly CVarDef<bool> PanicBunkerDisableWithAdmins =
+            CVarDef.Create("game.panic_bunker.disable_with_admins", false, CVar.SERVERONLY);
+
+        /// <summary>
+        /// Whether or not the panic bunker will enable when no admins are online.
+        /// </summary>
+        public static readonly CVarDef<bool> PanicBunkerEnableWithoutAdmins =
+            CVarDef.Create("game.panic_bunker.enable_without_admins", false, CVar.SERVERONLY);
+
+        /// <summary>
+        /// Whether or not the panic bunker will count deadminned admins for
+        /// <see cref="PanicBunkerDisableWithAdmins"/> and
+        /// <see cref="PanicBunkerEnableWithoutAdmins"/>
+        /// </summary>
+        public static readonly CVarDef<bool> PanicBunkerCountDeadminnedAdmins =
+            CVarDef.Create("game.panic_bunker.count_deadminned_admins", false, CVar.SERVERONLY);
+
         /// <summary>
         /// Show reason of disconnect for user or not.
         /// </summary>
index 81bc934176c7efc9839b1714d066a4344d2af667..aafb784ddc1ca9ee0b45723d9fb21d6ca8387b3c 100644 (file)
@@ -7,3 +7,10 @@ Entries:
   - {message: 'Created the admin changelog.', type: Add}
   id: 1
   time: '2023-10-08T04:26:00.0000000+00:00'
+- author: DrSmugleaf
+  changes:
+  - {message: 'Added a new panic bunker UI in the F7 admin panel.', type: Add}
+  - {message: 'Added being able to toggle the panic bunker automatically depending on
+      if admins are online or not.', type: Add}
+  id: 2
+  time: '2023-10-12T22:46:00.0000000+00:00'
index 46896500b8e8f48ab084b04e044478cdcc815e3f..c16748c9926a91cc07b9cf595732d44247119283 100644 (file)
@@ -1,2 +1,34 @@
+cmd-panicbunker-desc = Toggles the panic bunker, which enables stricter restrictions on who's allowed to join the server.
+cmd-panicbunker-help = Usage: panicbunker
 panicbunker-command-enabled = Panic bunker has been enabled.
 panicbunker-command-disabled = Panic bunker has been disabled.
+
+cmd-panicbunker_disable_with_admins-desc = Toggles whether or not the panic bunker will disable when an admin connects.
+cmd-panicbunker_disable_with_admins-help = Usage: panicbunker_disable_with_admins
+panicbunker-command-disable-with-admins-enabled = The panic bunker will automatically disable with admins online.
+panicbunker-command-disable-with-admins-disabled = The panic bunker will not automatically disable with admins online.
+
+cmd-panicbunker_enable_without_admins-desc = Toggles whether or not the panic bunker will enable when the last admin disconnects.
+cmd-panicbunker_enable_without_admins-help = Usage: panicbunker_enable_without_admins
+panicbunker-command-enable-without-admins-enabled = The panic bunker will automatically enable without admins online.
+panicbunker-command-enable-without-admins-disabled = The panic bunker will not automatically enable without admins online.
+
+cmd-panicbunker_count_deadminned_admins-desc = Toggles whether or not to count deadminned admins when automatically enabling and disabling the panic bunker.
+cmd-panicbunker_count_deadminned_admins-help = Usage: panicbunker_count_deadminned_admins
+panicbunker-command-count-deadminned-admins-enabled = The panic bunker will count deadminned admins when made to automatically enable and disable.
+panicbunker-command-count-deadminned-admins-disabled = The panic bunker will not count deadminned admins when made to automatically enable and disable.
+
+cmd-panicbunker_show_reason-desc = Toggles whether or not to show connecting clients the reason why the panic bunker blocked them from joining.
+cmd-panicbunker_show_reason-help = Usage: panicbunker_show_reason
+panicbunker-command-show-reason-enabled = The panic bunker will now show a reason to users it blocks from connecting.
+panicbunker-command-show-reason-disabled = The panic bunker will no longer show a reason to users it blocks from connecting.
+
+cmd-panicbunker_min_account_age-desc = Gets or sets the minimum account age in hours that an account must have to be allowed to connect with the panic bunker enabled.
+cmd-panicbunker_min_account_age-help = Usage: panicbunker_min_account_age <hours>
+panicbunker-command-min-account-age-is = The minimum account age for the panic bunker is {$hours} hours.
+panicbunker-command-min-account-age-set = Set the minimum account age for the panic bunker to {$hours} hours.
+
+cmd-panicbunker_min_overall_hours-desc = Gets or sets the minimum overall playtime in hours that an account must have to be allowed to connect with the panic bunker enabled.
+cmd-panicbunker_min_overall_hours-help = Usage: panicbunker_min_overall_hours <hours>
+panicbunker-command-min-overall-hours-is = The minimum overall playtime for the panic bunker is {$hours} hours.
+panicbunker-command-min-overall-hours-set = Set the minimum overall playtime for the panic bunker to {$hours} hours.
index ce256a2cd532a8eb1d14fe66af17c0c44983869d..c759e4c2cb16f2b3b857f1a4e8eb259e8667886f 100644 (file)
@@ -6,5 +6,6 @@ admin-menu-adminbus-tab = Adminbus
 admin-menu-atmos-tab = Atmos
 admin-menu-round-tab = Round
 admin-menu-server-tab = Server
+admin-menu-panic-bunker-tab = Panic Bunker
 admin-menu-players-tab = Players
 admin-menu-objects-tab = Objects
diff --git a/Resources/Locale/en-US/administration/ui/tabs/panicbunker-tab.ftl b/Resources/Locale/en-US/administration/ui/tabs/panicbunker-tab.ftl
new file mode 100644 (file)
index 0000000..730d0c2
--- /dev/null
@@ -0,0 +1,24 @@
+admin-ui-panic-bunker-window-title = Panic Bunker
+
+admin-ui-panic-bunker-enabled = Panic Bunker Enabled
+admin-ui-panic-bunker-disabled = Panic Bunker Disabled
+admin-ui-panic-bunker-tooltip = The panic bunker restricts players from joining if their account is too new or they do not have enough overall playtime on this server.
+
+admin-ui-panic-bunker-disable-automatically = Disable Automatically
+admin-ui-panic-bunker-disable-automatically-tooltip = Disables the panic bunker automatically when an admin connects.
+admin-ui-panic-bunker-enable-automatically = Enable Automatically
+admin-ui-panic-bunker-enable-automatically-tooltip = Enables the panic bunker automatically when no admins are online.
+
+admin-ui-panic-bunker-count-deadminned-admins = Count Deadmins
+admin-ui-panic-bunker-count-deadminned-admins-tooltip = Count deadminned admins when automatically enabling and disabling the panic bunker.
+
+admin-ui-panic-bunker-show-reason = Show Reason
+admin-ui-panic-bunker-show-reason-tooltip = Show the user why they were blocked from connecting by the panic bunker.
+
+admin-ui-panic-bunker-min-account-age = Min. Account Age
+admin-ui-panic-bunker-min-overall-hours = Min. Overall Playtime
+
+admin-ui-panic-bunker-is-enabled = The panic bunker is currently enabled.
+
+admin-ui-panic-bunker-enabled-admin-alert = The panic bunker has been enabled.
+admin-ui-panic-bunker-disabled-admin-alert = The panic bunker has been disabled.
index 713af85fa5bc983eceea7774e14cc356635e46fb..7a41cbe2c751d793636e62bb178153974558fd73 100644 (file)
@@ -1,4 +1,3 @@
 server-shutdown = Shutdown
 server-ooc-toggle = Toggle OOC
 server-looc-toggle = Toggle LOOC
-server-panicbunker-toggle = Toggle Panic bunker
index 0ecfefdd1cbb2965ab44268b90131d651b6fd5e1..7b3e0d3684ef8eaf388f6bc58a056039cd774f3e 100644 (file)
@@ -8,3 +8,5 @@ generic-unknown = unknown
 generic-unknown-title = Unknown
 generic-error = error
 generic-invalid = invalid
+
+generic-hours = hours
index 1d141ba58a467b87b5240f20809e4e9d9d6a409e..57f0e3c4db6acb5dc036837a2c82b61ea8fc932d 100644 (file)
@@ -584,6 +584,7 @@ public sealed partial class $CLASS$ : Shared$CLASS$ {
        <s:Boolean x:Key="/Default/UserDictionary/Words/=Computus/@EntryIndexedValue">True</s:Boolean>
        <s:Boolean x:Key="/Default/UserDictionary/Words/=Constructible/@EntryIndexedValue">True</s:Boolean>
        <s:Boolean x:Key="/Default/UserDictionary/Words/=Cooldowns/@EntryIndexedValue">True</s:Boolean>
+       <s:Boolean x:Key="/Default/UserDictionary/Words/=Deadminned/@EntryIndexedValue">True</s:Boolean>
        <s:Boolean x:Key="/Default/UserDictionary/Words/=Dentification/@EntryIndexedValue">True</s:Boolean>
        <s:Boolean x:Key="/Default/UserDictionary/Words/=Diethylamine/@EntryIndexedValue">True</s:Boolean>
        <s:Boolean x:Key="/Default/UserDictionary/Words/=Drainable/@EntryIndexedValue">True</s:Boolean>