Add panic bunker UI and automatic panic bunker (#20954)

This commit is contained in:
DrSmugleaf
2023-10-13 11:56:12 -07:00
committed by GitHub
parent e972ce7984
commit db4ad40430
20 changed files with 536 additions and 34 deletions

View File

@@ -5,13 +5,15 @@
xmlns:atmosTab="clr-namespace:Content.Client.Administration.UI.Tabs.AtmosTab" xmlns:atmosTab="clr-namespace:Content.Client.Administration.UI.Tabs.AtmosTab"
xmlns:tabs="clr-namespace:Content.Client.Administration.UI.Tabs" xmlns:tabs="clr-namespace:Content.Client.Administration.UI.Tabs"
xmlns:playerTab="clr-namespace:Content.Client.Administration.UI.Tabs.PlayerTab" 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"> <TabContainer Name="MasterTabContainer">
<adminTab:AdminTab /> <adminTab:AdminTab />
<adminbusTab:AdminbusTab /> <adminbusTab:AdminbusTab />
<atmosTab:AtmosTab /> <atmosTab:AtmosTab />
<tabs:RoundTab /> <tabs:RoundTab />
<tabs:ServerTab /> <tabs:ServerTab />
<panic:PanicBunkerTab Name="PanicBunkerControl" Access="Public" />
<playerTab:PlayerTab Name="PlayerTabControl" Access="Public" /> <playerTab:PlayerTab Name="PlayerTabControl" Access="Public" />
<objectsTab:ObjectsTab Name="ObjectsTabControl" Access="Public" /> <objectsTab:ObjectsTab Name="ObjectsTabControl" Access="Public" />
</TabContainer> </TabContainer>

View File

@@ -12,7 +12,7 @@ namespace Content.Client.Administration.UI
public AdminMenuWindow() public AdminMenuWindow()
{ {
MinSize = new Vector2(500, 250); MinSize = new Vector2(650, 250);
Title = Loc.GetString("admin-menu-title"); Title = Loc.GetString("admin-menu-title");
RobustXamlLoader.Load(this); RobustXamlLoader.Load(this);
MasterTabContainer.SetTabTitle(0, Loc.GetString("admin-menu-admin-tab")); 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(2, Loc.GetString("admin-menu-atmos-tab"));
MasterTabContainer.SetTabTitle(3, Loc.GetString("admin-menu-round-tab")); MasterTabContainer.SetTabTitle(3, Loc.GetString("admin-menu-round-tab"));
MasterTabContainer.SetTabTitle(4, Loc.GetString("admin-menu-server-tab")); MasterTabContainer.SetTabTitle(4, Loc.GetString("admin-menu-server-tab"));
MasterTabContainer.SetTabTitle(5, Loc.GetString("admin-menu-players-tab")); MasterTabContainer.SetTabTitle(5, Loc.GetString("admin-menu-panic-bunker-tab"));
MasterTabContainer.SetTabTitle(6, Loc.GetString("admin-menu-objects-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) protected override void Dispose(bool disposing)

View File

@@ -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>

View File

@@ -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);
}
}

View File

@@ -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>

View File

@@ -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();
}
}

View File

@@ -8,6 +8,5 @@
<cc:CommandButton Command="shutdown" Text="{Loc server-shutdown}" /> <cc:CommandButton Command="shutdown" Text="{Loc server-shutdown}" />
<cc:CommandButton Name="SetOocButton" Command="setooc" Text="{Loc server-ooc-toggle}" ToggleMode="True" /> <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="SetLoocButton" Command="setlooc" Text="{Loc server-looc-toggle}" ToggleMode="True" />
<cc:CommandButton Name="SetPanicbunkerButton" Command="panicbunker" Text="{Loc server-panicbunker-toggle}" ToggleMode="True" />
</GridContainer> </GridContainer>
</Control> </Control>

View File

@@ -18,7 +18,6 @@ namespace Content.Client.Administration.UI.Tabs
_config.OnValueChanged(CCVars.OocEnabled, OocEnabledChanged, true); _config.OnValueChanged(CCVars.OocEnabled, OocEnabledChanged, true);
_config.OnValueChanged(CCVars.LoocEnabled, LoocEnabledChanged, true); _config.OnValueChanged(CCVars.LoocEnabled, LoocEnabledChanged, true);
_config.OnValueChanged(CCVars.PanicBunkerEnabled, BunkerEnabledChanged, true);
} }
private void OocEnabledChanged(bool value) private void OocEnabledChanged(bool value)
@@ -31,11 +30,6 @@ namespace Content.Client.Administration.UI.Tabs
SetLoocButton.Pressed = value; SetLoocButton.Pressed = value;
} }
private void BunkerEnabledChanged(bool value)
{
SetPanicbunkerButton.Pressed = value;
}
protected override void Dispose(bool disposing) protected override void Dispose(bool disposing)
{ {
base.Dispose(disposing); base.Dispose(disposing);
@@ -44,7 +38,6 @@ namespace Content.Client.Administration.UI.Tabs
{ {
_config.UnsubValueChanged(CCVars.OocEnabled, OocEnabledChanged); _config.UnsubValueChanged(CCVars.OocEnabled, OocEnabledChanged);
_config.UnsubValueChanged(CCVars.LoocEnabled, LoocEnabledChanged); _config.UnsubValueChanged(CCVars.LoocEnabled, LoocEnabledChanged);
_config.UnsubValueChanged(CCVars.PanicBunkerEnabled, BunkerEnabledChanged);
} }
} }
} }

View File

@@ -2,11 +2,13 @@
using Content.Client.Administration.Systems; using Content.Client.Administration.Systems;
using Content.Client.Administration.UI; using Content.Client.Administration.UI;
using Content.Client.Administration.UI.Tabs.ObjectsTab; using Content.Client.Administration.UI.Tabs.ObjectsTab;
using Content.Client.Administration.UI.Tabs.PanicBunkerTab;
using Content.Client.Administration.UI.Tabs.PlayerTab; using Content.Client.Administration.UI.Tabs.PlayerTab;
using Content.Client.Gameplay; using Content.Client.Gameplay;
using Content.Client.Lobby; using Content.Client.Lobby;
using Content.Client.UserInterface.Controls; using Content.Client.UserInterface.Controls;
using Content.Client.Verbs.UI; using Content.Client.Verbs.UI;
using Content.Shared.Administration.Events;
using Content.Shared.Input; using Content.Shared.Input;
using JetBrains.Annotations; using JetBrains.Annotations;
using Robust.Client.Console; using Robust.Client.Console;
@@ -30,6 +32,25 @@ public sealed class AdminUIController : UIController, IOnStateEntered<GameplaySt
private AdminMenuWindow? _window; private AdminMenuWindow? _window;
private MenuButton? AdminButton => UIManager.GetActiveUIWidgetOrNull<MenuBar.Widgets.GameTopMenuBar>()?.AdminButton; 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) public void OnStateEntered(GameplayState state)
{ {
@@ -73,6 +94,9 @@ public sealed class AdminUIController : UIController, IOnStateEntered<GameplaySt
_window = UIManager.CreateWindow<AdminMenuWindow>(); _window = UIManager.CreateWindow<AdminMenuWindow>();
LayoutContainer.SetAnchorPreset(_window, LayoutContainer.LayoutPreset.Center); LayoutContainer.SetAnchorPreset(_window, LayoutContainer.LayoutPreset.Center);
if (_panicBunker != null)
_window.PanicBunkerControl.UpdateStatus(_panicBunker);
_window.PlayerTabControl.OnEntryPressed += PlayerTabEntryPressed; _window.PlayerTabControl.OnEntryPressed += PlayerTabEntryPressed;
_window.ObjectsTabControl.OnEntryPressed += ObjectsTabEntryPressed; _window.ObjectsTabControl.OnEntryPressed += ObjectsTabEntryPressed;
_window.OnOpen += OnWindowOpen; _window.OnOpen += OnWindowOpen;

View File

@@ -6,36 +6,187 @@ using Robust.Shared.Console;
namespace Content.Server.Administration.Commands; namespace Content.Server.Administration.Commands;
[AdminCommand(AdminFlags.Server)] [AdminCommand(AdminFlags.Server)]
public sealed class PanicBunkerCommand : IConsoleCommand public sealed class PanicBunkerCommand : LocalizedCommands
{ {
[Dependency] private readonly IConfigurationManager _cfg = default!; [Dependency] private readonly IConfigurationManager _cfg = default!;
public string Command => "panicbunker"; public override string Command => "panicbunker";
public string Description => "Enables or disables the panic bunker functionality.";
public string Help => "panicbunker"; public override void Execute(IConsoleShell shell, string argStr, string[] args)
public 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 null;
}
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) if (args.Length > 1)
{ {
shell.WriteError(Loc.GetString("shell-need-between-arguments",("lower", 0), ("upper", 1))); shell.WriteError(Loc.GetString("shell-need-between-arguments",("lower", 0), ("upper", 1)));
return; return;
} }
var enabled = _cfg.GetCVar(CCVars.PanicBunkerEnabled); if (!int.TryParse(args[0], out var hours))
if (args.Length == 0)
{ {
enabled = !enabled; shell.WriteError(Loc.GetString("shell-argument-must-be-number"));
}
if (args.Length == 1 && !bool.TryParse(args[0], out enabled))
{
shell.WriteError(Loc.GetString("shell-argument-must-be-boolean"));
return; return;
} }
_cfg.SetCVar(CCVars.PanicBunkerEnabled, enabled); _cfg.SetCVar(CCVars.PanicBunkerMinAccountAge, hours * 60);
shell.WriteLine(Loc.GetString("panicbunker-command-min-account-age-set", ("hours", hours)));
shell.WriteLine(Loc.GetString(enabled ? "panicbunker-command-enabled" : "panicbunker-command-disabled")); }
}
[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.PanicBunkerMinOverallHours, hours);
shell.WriteLine(Loc.GetString("panicbunker-command-overall-hours-age-set", ("hours", hours)));
} }
} }

View File

@@ -1,15 +1,18 @@
using System.Linq; using System.Linq;
using Content.Server.Administration.Managers; using Content.Server.Administration.Managers;
using Content.Server.Chat.Managers;
using Content.Server.IdentityManagement; using Content.Server.IdentityManagement;
using Content.Server.Mind; using Content.Server.Mind;
using Content.Shared.Administration; using Content.Shared.Administration;
using Content.Shared.Administration.Events; using Content.Shared.Administration.Events;
using Content.Shared.CCVar;
using Content.Shared.GameTicking; using Content.Shared.GameTicking;
using Content.Shared.IdentityManagement; using Content.Shared.IdentityManagement;
using Content.Shared.Roles; using Content.Shared.Roles;
using Content.Shared.Roles.Jobs; using Content.Shared.Roles.Jobs;
using Robust.Server.GameObjects; using Robust.Server.GameObjects;
using Robust.Server.Player; using Robust.Server.Player;
using Robust.Shared.Configuration;
using Robust.Shared.Enums; using Robust.Shared.Enums;
using Robust.Shared.Network; using Robust.Shared.Network;
using Robust.Shared.Player; using Robust.Shared.Player;
@@ -18,8 +21,10 @@ namespace Content.Server.Administration.Systems
{ {
public sealed class AdminSystem : EntitySystem public sealed class AdminSystem : EntitySystem
{ {
[Dependency] private readonly IPlayerManager _playerManager = default!;
[Dependency] private readonly IAdminManager _adminManager = 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 SharedJobSystem _jobs = default!;
[Dependency] private readonly MindSystem _minds = default!; [Dependency] private readonly MindSystem _minds = default!;
[Dependency] private readonly SharedRoleSystem _role = default!; [Dependency] private readonly SharedRoleSystem _role = default!;
@@ -32,6 +37,7 @@ namespace Content.Server.Administration.Systems
public IReadOnlySet<NetUserId> RoundActivePlayers => _roundActivePlayers; public IReadOnlySet<NetUserId> RoundActivePlayers => _roundActivePlayers;
private readonly HashSet<NetUserId> _roundActivePlayers = new(); private readonly HashSet<NetUserId> _roundActivePlayers = new();
private readonly PanicBunkerStatus _panicBunker = new();
public override void Initialize() public override void Initialize()
{ {
@@ -39,6 +45,15 @@ namespace Content.Server.Administration.Systems
_playerManager.PlayerStatusChanged += OnPlayerStatusChanged; _playerManager.PlayerStatusChanged += OnPlayerStatusChanged;
_adminManager.OnPermsChanged += OnAdminPermsChanged; _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<IdentityChangedEvent>(OnIdentityChanged);
SubscribeLocalEvent<PlayerAttachedEvent>(OnPlayerAttached); SubscribeLocalEvent<PlayerAttachedEvent>(OnPlayerAttached);
SubscribeLocalEvent<PlayerDetachedEvent>(OnPlayerDetached); SubscribeLocalEvent<PlayerDetachedEvent>(OnPlayerDetached);
@@ -114,7 +129,9 @@ namespace Content.Server.Administration.Systems
private void OnAdminPermsChanged(AdminPermsChangedEventArgs obj) private void OnAdminPermsChanged(AdminPermsChangedEventArgs obj)
{ {
if(!obj.IsAdmin) UpdatePanicBunker();
if (!obj.IsAdmin)
{ {
RaiseNetworkEvent(new FullPlayerListEvent(), obj.Player.ConnectedClient); RaiseNetworkEvent(new FullPlayerListEvent(), obj.Player.ConnectedClient);
return; 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. // If disconnected then the player won't have a connected entity to get character name from.
// The disconnected state gets sent by OnPlayerStatusChanged. // The disconnected state gets sent by OnPlayerStatusChanged.
if(ev.Player.Status == SessionStatus.Disconnected) return; if (ev.Player.Status == SessionStatus.Disconnected)
return;
UpdatePlayerList(ev.Player); UpdatePlayerList(ev.Player);
} }
private void OnPlayerAttached(PlayerAttachedEvent ev) private void OnPlayerAttached(PlayerAttachedEvent ev)
{ {
if(ev.Player.Status == SessionStatus.Disconnected) return; if (ev.Player.Status == SessionStatus.Disconnected)
return;
_roundActivePlayers.Add(ev.Player.UserId); _roundActivePlayers.Add(ev.Player.UserId);
UpdatePlayerList(ev.Player); UpdatePlayerList(ev.Player);
@@ -145,11 +164,20 @@ namespace Content.Server.Administration.Systems
base.Shutdown(); base.Shutdown();
_playerManager.PlayerStatusChanged -= OnPlayerStatusChanged; _playerManager.PlayerStatusChanged -= OnPlayerStatusChanged;
_adminManager.OnPermsChanged -= OnAdminPermsChanged; _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) private void OnPlayerStatusChanged(object? sender, SessionStatusEventArgs e)
{ {
UpdatePlayerList(e.Session); UpdatePlayerList(e.Session);
UpdatePanicBunker();
} }
private void SendFullPlayerList(IPlayerSession playerSession) 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, return new PlayerInfo(name, entityName, identityName, startingRole, antag, GetNetEntity(session?.AttachedEntity), data.UserId,
connected, _roundActivePlayers.Contains(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);
}
}
} }
} }

View File

@@ -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;
}
}

View File

@@ -248,6 +248,26 @@ namespace Content.Shared.CCVar
public static readonly CVarDef<bool> PanicBunkerEnabled = public static readonly CVarDef<bool> PanicBunkerEnabled =
CVarDef.Create("game.panic_bunker.enabled", false, CVar.NOTIFY | CVar.REPLICATED); 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> /// <summary>
/// Show reason of disconnect for user or not. /// Show reason of disconnect for user or not.
/// </summary> /// </summary>

View File

@@ -7,3 +7,10 @@ Entries:
- {message: 'Created the admin changelog.', type: Add} - {message: 'Created the admin changelog.', type: Add}
id: 1 id: 1
time: '2023-10-08T04:26:00.0000000+00:00' 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'

View 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-enabled = Panic bunker has been enabled.
panicbunker-command-disabled = Panic bunker has been disabled. 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.

View File

@@ -6,5 +6,6 @@ admin-menu-adminbus-tab = Adminbus
admin-menu-atmos-tab = Atmos admin-menu-atmos-tab = Atmos
admin-menu-round-tab = Round admin-menu-round-tab = Round
admin-menu-server-tab = Server admin-menu-server-tab = Server
admin-menu-panic-bunker-tab = Panic Bunker
admin-menu-players-tab = Players admin-menu-players-tab = Players
admin-menu-objects-tab = Objects admin-menu-objects-tab = Objects

View File

@@ -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.

View File

@@ -1,4 +1,3 @@
server-shutdown = Shutdown server-shutdown = Shutdown
server-ooc-toggle = Toggle OOC server-ooc-toggle = Toggle OOC
server-looc-toggle = Toggle LOOC server-looc-toggle = Toggle LOOC
server-panicbunker-toggle = Toggle Panic bunker

View File

@@ -8,3 +8,5 @@ generic-unknown = unknown
generic-unknown-title = Unknown generic-unknown-title = Unknown
generic-error = error generic-error = error
generic-invalid = invalid generic-invalid = invalid
generic-hours = hours

View 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/=Computus/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Constructible/@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/=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/=Dentification/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Diethylamine/@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> <s:Boolean x:Key="/Default/UserDictionary/Words/=Drainable/@EntryIndexedValue">True</s:Boolean>