job whitelists panel !!! (#1678)
* make JobPrototype.Whitelisted respect blanket whitelist, make jobs use it * add jobwhitelists command and ui * add job whitelist button to player panel --------- Co-authored-by: deltanedas <@deltanedas:kde.org>
This commit is contained in:
parent
a3bef2b30f
commit
7fd2541aee
|
|
@ -31,6 +31,7 @@
|
|||
<Button Name="BanButton" Text="{Loc player-panel-ban}" Disabled="True"/>
|
||||
<controls:ConfirmButton Name="RejuvenateButton" Text="{Loc player-panel-rejuvenate}" Disabled="True"/>
|
||||
</GridContainer>
|
||||
<Button Name="JobWhitelistsButton" Text="{Loc player-panel-job-whitelists}" SetWidth="136" SetHeight="27" Disabled="True"/> <!-- DeltaV: Job whitelists -->
|
||||
</BoxContainer>
|
||||
</BoxContainer>
|
||||
</ui:FancyWindow>
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@ public sealed partial class PlayerPanel : FancyWindow
|
|||
public event Action? OnLogs;
|
||||
public event Action? OnDelete;
|
||||
public event Action? OnRejuvenate;
|
||||
public event Action<NetUserId?>? OnOpenJobWhitelists; // DeltaV
|
||||
|
||||
public NetUserId? TargetPlayer;
|
||||
public string? TargetUsername;
|
||||
|
|
@ -52,6 +53,8 @@ public sealed partial class PlayerPanel : FancyWindow
|
|||
LogsButton.OnPressed += _ => OnLogs?.Invoke();
|
||||
DeleteButton.OnPressed += _ => OnDelete?.Invoke();
|
||||
RejuvenateButton.OnPressed += _ => OnRejuvenate?.Invoke();
|
||||
|
||||
JobWhitelistsButton.OnPressed += _ => OnOpenJobWhitelists?.Invoke(TargetPlayer); // DeltaV: Job whitelists
|
||||
}
|
||||
|
||||
public void SetUsername(string player)
|
||||
|
|
@ -128,5 +131,6 @@ public sealed partial class PlayerPanel : FancyWindow
|
|||
LogsButton.Disabled = !_adminManager.CanCommand("adminlogs");
|
||||
RejuvenateButton.Disabled = !_adminManager.HasFlag(AdminFlags.Debug);
|
||||
DeleteButton.Disabled = !_adminManager.HasFlag(AdminFlags.Debug);
|
||||
JobWhitelistsButton.Disabled = !_adminManager.HasFlag(AdminFlags.Whitelist); // DeltaV
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -38,6 +38,7 @@ public sealed class PlayerPanelEui : BaseEui
|
|||
PlayerPanel.OnLogs += () => SendMessage(new PlayerPanelLogsMessage());
|
||||
PlayerPanel.OnRejuvenate += () => SendMessage(new PlayerPanelRejuvenationMessage());
|
||||
PlayerPanel.OnDelete+= () => SendMessage(new PlayerPanelDeleteMessage());
|
||||
PlayerPanel.OnOpenJobWhitelists += id => _console.ExecuteCommand($"jobwhitelists \"{id}\""); // DeltaV
|
||||
|
||||
PlayerPanel.OnClose += () => SendMessage(new CloseEuiMessage());
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,11 @@
|
|||
<PanelContainer
|
||||
xmlns="https://spacestation14.io"
|
||||
xmlns:cc="clr-namespace:Content.Client.DeltaV.Administration.UI"
|
||||
StyleClasses="BackgroundDark"
|
||||
HorizontalExpand="True"
|
||||
Margin="4">
|
||||
<BoxContainer Orientation="Vertical">
|
||||
<CheckBox Name="Department"/> <!-- Toggles all jobs in the department at once -->
|
||||
<GridContainer Name="JobsContainer" Columns="4"/> <!-- Populated with each job to toggle individually-->
|
||||
</BoxContainer>
|
||||
</PanelContainer>
|
||||
|
|
@ -0,0 +1,46 @@
|
|||
using Content.Shared.Roles;
|
||||
using Robust.Client.AutoGenerated;
|
||||
using Robust.Client.UserInterface;
|
||||
using Robust.Client.UserInterface.Controls;
|
||||
using Robust.Client.UserInterface.CustomControls;
|
||||
using Robust.Client.UserInterface.XAML;
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
namespace Content.Client.DeltaV.Administration.UI;
|
||||
|
||||
[GenerateTypedNameReferences]
|
||||
public sealed partial class DepartmentWhitelistPanel : PanelContainer
|
||||
{
|
||||
public Action<ProtoId<JobPrototype>, bool>? OnSetJob;
|
||||
|
||||
public DepartmentWhitelistPanel(DepartmentPrototype department, IPrototypeManager proto, HashSet<ProtoId<JobPrototype>> whitelists)
|
||||
{
|
||||
RobustXamlLoader.Load(this);
|
||||
|
||||
var allWhitelisted = true;
|
||||
foreach (var id in department.Roles)
|
||||
{
|
||||
var thisJob = id; // closure capturing funny
|
||||
var button = new CheckBox();
|
||||
button.Text = proto.Index(id).LocalizedName;
|
||||
button.Pressed = whitelists.Contains(id);
|
||||
button.OnPressed += _ => OnSetJob?.Invoke(thisJob, button.Pressed);
|
||||
JobsContainer.AddChild(button);
|
||||
|
||||
allWhitelisted &= button.Pressed;
|
||||
}
|
||||
|
||||
Department.Text = Loc.GetString(department.Name);
|
||||
Department.Modulate = department.Color;
|
||||
Department.Pressed = allWhitelisted;
|
||||
Department.OnPressed += args =>
|
||||
{
|
||||
foreach (var id in department.Roles)
|
||||
{
|
||||
// only request to whitelist roles that aren't already whitelisted, and vice versa
|
||||
if (whitelists.Contains(id) != Department.Pressed)
|
||||
OnSetJob?.Invoke(id, Department.Pressed);
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,40 @@
|
|||
using Content.Client.Eui;
|
||||
using Content.Shared.DeltaV.Administration;
|
||||
using Content.Shared.Eui;
|
||||
|
||||
namespace Content.Client.DeltaV.Administration.UI;
|
||||
|
||||
public sealed class JobWhitelistsEui : BaseEui
|
||||
{
|
||||
private JobWhitelistsWindow Window;
|
||||
|
||||
public JobWhitelistsEui()
|
||||
{
|
||||
Window = new JobWhitelistsWindow();
|
||||
Window.OnClose += () => SendMessage(new CloseEuiMessage());
|
||||
Window.OnSetJob += (id, whitelisted) => SendMessage(new SetJobWhitelistedMessage(id, whitelisted));
|
||||
}
|
||||
|
||||
public override void HandleState(EuiStateBase state)
|
||||
{
|
||||
if (state is not JobWhitelistsEuiState cast)
|
||||
return;
|
||||
|
||||
Window.HandleState(cast);
|
||||
}
|
||||
|
||||
public override void Opened()
|
||||
{
|
||||
base.Opened();
|
||||
|
||||
Window.OpenCentered();
|
||||
}
|
||||
|
||||
public override void Closed()
|
||||
{
|
||||
base.Closed();
|
||||
|
||||
Window.Close();
|
||||
Window.Dispose();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
<controls:FancyWindow
|
||||
xmlns="https://spacestation14.io"
|
||||
xmlns:controls="clr-namespace:Content.Client.UserInterface.Controls"
|
||||
Title="{Loc player-panel-job-whitelists}" MinSize="750 600">
|
||||
<BoxContainer Orientation="Vertical">
|
||||
<Label Name="PlayerName" Margin="4"/>
|
||||
<ScrollContainer VerticalExpand="True">
|
||||
<BoxContainer Name="Departments" Orientation="Vertical"/> <!-- Populated with DepartmentWhitelistPanel -->
|
||||
</ScrollContainer>
|
||||
</BoxContainer>
|
||||
</controls:FancyWindow>
|
||||
|
|
@ -0,0 +1,46 @@
|
|||
using Content.Client.UserInterface.Controls;
|
||||
using Content.Shared.Database;
|
||||
using Content.Shared.DeltaV.Administration;
|
||||
using Content.Shared.Roles;
|
||||
using Robust.Client.AutoGenerated;
|
||||
using Robust.Client.UserInterface;
|
||||
using Robust.Client.UserInterface.Controls;
|
||||
using Robust.Client.UserInterface.CustomControls;
|
||||
using Robust.Client.UserInterface.XAML;
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
namespace Content.Client.DeltaV.Administration.UI;
|
||||
|
||||
/// <summary>
|
||||
/// An admin panel to toggle whitelists for individual jobs or entire departments.
|
||||
/// This should generally be preferred to a blanket whitelist (Whitelisted: True) since
|
||||
/// being good with a batong doesn't mean you know engineering and vice versa.
|
||||
/// </summary>
|
||||
[GenerateTypedNameReferences]
|
||||
public sealed partial class JobWhitelistsWindow : FancyWindow
|
||||
{
|
||||
[Dependency] private readonly IPrototypeManager _proto = default!;
|
||||
|
||||
public Action<ProtoId<JobPrototype>, bool>? OnSetJob;
|
||||
|
||||
public JobWhitelistsWindow()
|
||||
{
|
||||
RobustXamlLoader.Load(this);
|
||||
IoCManager.InjectDependencies(this);
|
||||
|
||||
PlayerName.Text = "???";
|
||||
}
|
||||
|
||||
public void HandleState(JobWhitelistsEuiState state)
|
||||
{
|
||||
PlayerName.Text = state.PlayerName;
|
||||
|
||||
Departments.RemoveAllChildren();
|
||||
foreach (var proto in _proto.EnumeratePrototypes<DepartmentPrototype>())
|
||||
{
|
||||
var panel = new DepartmentWhitelistPanel(proto, _proto, state.Whitelists);
|
||||
panel.OnSetJob += (id, whitelisting) => OnSetJob?.Invoke(id, whitelisting);
|
||||
Departments.AddChild(panel);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,45 @@
|
|||
using Content.Server.Administration;
|
||||
using Content.Server.EUI;
|
||||
using Content.Shared.Administration;
|
||||
using Robust.Shared.Console;
|
||||
|
||||
namespace Content.Server.DeltaV.Administration.Commands;
|
||||
|
||||
/// <summary>
|
||||
/// Opens the job whitelists panel for editing player whitelists.
|
||||
/// To use this ingame it's easiest to first open the player panel, then hit Job Whitelists.
|
||||
/// </summary>
|
||||
[AdminCommand(AdminFlags.Whitelist)]
|
||||
public sealed class JobWhitelistsCommand : LocalizedCommands
|
||||
{
|
||||
[Dependency] private readonly EuiManager _eui = default!;
|
||||
[Dependency] private readonly IPlayerLocator _locator = default!;
|
||||
|
||||
public override string Command => "jobwhitelists";
|
||||
|
||||
public override async void Execute(IConsoleShell shell, string argStr, string[] args)
|
||||
{
|
||||
if (shell.Player is not {} player)
|
||||
{
|
||||
shell.WriteError(Loc.GetString("shell-cannot-run-command-from-server"));
|
||||
return;
|
||||
}
|
||||
|
||||
if (args.Length != 1)
|
||||
{
|
||||
shell.WriteLine(Loc.GetString("cmd-ban-invalid-arguments"));
|
||||
shell.WriteLine(Help);
|
||||
}
|
||||
|
||||
var located = await _locator.LookupIdByNameOrIdAsync(args[0]);
|
||||
if (located is null)
|
||||
{
|
||||
shell.WriteError(Loc.GetString("cmd-jobwhitelists-player-err"));
|
||||
return;
|
||||
}
|
||||
|
||||
var ui = new JobWhitelistsEui(located.UserId, located.Username);
|
||||
ui.LoadWhitelists();
|
||||
_eui.OpenEui(ui, player);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,90 @@
|
|||
using System.Threading.Tasks;
|
||||
using Content.Server.Administration.Managers;
|
||||
using Content.Server.Database;
|
||||
using Content.Server.EUI;
|
||||
using Content.Server.Players.JobWhitelist;
|
||||
using Content.Shared.Administration;
|
||||
using Content.Shared.DeltaV.Administration;
|
||||
using Content.Shared.Eui;
|
||||
using Content.Shared.Roles;
|
||||
using Robust.Shared.Log;
|
||||
using Robust.Shared.Network;
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
namespace Content.Server.DeltaV.Administration;
|
||||
|
||||
public sealed class JobWhitelistsEui : BaseEui
|
||||
{
|
||||
[Dependency] private readonly IAdminManager _admin = default!;
|
||||
[Dependency] private readonly ILogManager _log = default!;
|
||||
[Dependency] private readonly IPrototypeManager _proto = default!;
|
||||
[Dependency] private readonly IServerDbManager _db = default!;
|
||||
[Dependency] private readonly JobWhitelistManager _jobWhitelist = default!;
|
||||
|
||||
private readonly ISawmill _sawmill;
|
||||
|
||||
public NetUserId PlayerId;
|
||||
public string PlayerName;
|
||||
|
||||
public HashSet<ProtoId<JobPrototype>> Whitelists = new();
|
||||
|
||||
public JobWhitelistsEui(NetUserId playerId, string playerName)
|
||||
{
|
||||
IoCManager.InjectDependencies(this);
|
||||
|
||||
_sawmill = _log.GetSawmill("admin.job_whitelists_eui");
|
||||
|
||||
PlayerId = playerId;
|
||||
PlayerName = playerName;
|
||||
}
|
||||
|
||||
public async void LoadWhitelists()
|
||||
{
|
||||
var jobs = await _db.GetJobWhitelists(PlayerId.UserId);
|
||||
foreach (var id in jobs)
|
||||
{
|
||||
if (_proto.HasIndex<JobPrototype>(id))
|
||||
Whitelists.Add(id);
|
||||
}
|
||||
|
||||
StateDirty();
|
||||
}
|
||||
|
||||
public override EuiStateBase GetNewState()
|
||||
{
|
||||
return new JobWhitelistsEuiState(PlayerName, Whitelists);
|
||||
}
|
||||
|
||||
public override void HandleMessage(EuiMessageBase msg)
|
||||
{
|
||||
base.HandleMessage(msg);
|
||||
|
||||
if (msg is not SetJobWhitelistedMessage args)
|
||||
return;
|
||||
|
||||
if (!_admin.HasAdminFlag(Player, AdminFlags.Whitelist))
|
||||
{
|
||||
_sawmill.Warning($"{Player.Name} ({Player.UserId}) tried to change role whitelists for {PlayerName} without whitelists flag");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!_proto.HasIndex<JobPrototype>(args.Job))
|
||||
return;
|
||||
|
||||
if (args.Whitelisting)
|
||||
{
|
||||
_jobWhitelist.AddWhitelist(PlayerId, args.Job);
|
||||
Whitelists.Add(args.Job);
|
||||
}
|
||||
else
|
||||
{
|
||||
_jobWhitelist.RemoveWhitelist(PlayerId, args.Job);
|
||||
Whitelists.Remove(args.Job);
|
||||
}
|
||||
|
||||
var verb = args.Whitelisting ? "added" : "removed";
|
||||
_sawmill.Info($"{Player.Name} ({Player.UserId}) {verb} whitelist for {args.Job} to player {PlayerName} ({PlayerId.UserId})");
|
||||
|
||||
StateDirty();
|
||||
}
|
||||
}
|
||||
|
|
@ -3,6 +3,7 @@ using System.Threading;
|
|||
using System.Threading.Tasks;
|
||||
using Content.Server.Database;
|
||||
using Content.Shared.CCVar;
|
||||
using Content.Shared.Players; // DeltaV
|
||||
using Content.Shared.Players.JobWhitelist;
|
||||
using Content.Shared.Roles;
|
||||
using Robust.Server.Player;
|
||||
|
|
@ -69,6 +70,10 @@ public sealed class JobWhitelistManager : IPostInjectInit
|
|||
return true;
|
||||
}
|
||||
|
||||
// DeltaV: Blanket player whitelist allows all roles
|
||||
if (session.ContentData()?.Whitelisted ?? false)
|
||||
return true;
|
||||
|
||||
return IsWhitelisted(session.UserId, job);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,35 @@
|
|||
using Content.Shared.Eui;
|
||||
using Content.Shared.Roles;
|
||||
using Robust.Shared.Prototypes;
|
||||
using Robust.Shared.Serialization;
|
||||
|
||||
namespace Content.Shared.DeltaV.Administration;
|
||||
|
||||
[Serializable, NetSerializable]
|
||||
public sealed class JobWhitelistsEuiState : EuiStateBase
|
||||
{
|
||||
public string PlayerName;
|
||||
public HashSet<ProtoId<JobPrototype>> Whitelists;
|
||||
|
||||
public JobWhitelistsEuiState(string playerName, HashSet<ProtoId<JobPrototype>> whitelists)
|
||||
{
|
||||
PlayerName = playerName;
|
||||
Whitelists = whitelists;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tries to add or remove a whitelist of a job for a player.
|
||||
/// </summary>
|
||||
[Serializable, NetSerializable]
|
||||
public sealed class SetJobWhitelistedMessage : EuiMessageBase
|
||||
{
|
||||
public ProtoId<JobPrototype> Job;
|
||||
public bool Whitelisting;
|
||||
|
||||
public SetJobWhitelistedMessage(ProtoId<JobPrototype> job, bool whitelisting)
|
||||
{
|
||||
Job = job;
|
||||
Whitelisting = whitelisting;
|
||||
}
|
||||
}
|
||||
|
|
@ -9,6 +9,9 @@ namespace Content.Shared.Roles;
|
|||
/// <summary>
|
||||
/// Requires the player be globally whitelisted to play a role.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Don't use this for jobs, use <c>whitelisted: true</c> on the JobPrototype instead.
|
||||
/// </remarks>
|
||||
[Serializable, NetSerializable]
|
||||
public sealed partial class WhitelistRequirement : JobRequirement
|
||||
{
|
||||
|
|
|
|||
|
|
@ -0,0 +1 @@
|
|||
player-panel-job-whitelists = Job Whitelists
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
cmd-jobwhitelists-desc = Opens the job whitelists window
|
||||
cmd-jobwhitelists-help = Usage: jobwhitelists [name or user guid]
|
||||
cmd-jobwhitelists-player-err = The specified player could not be found
|
||||
|
|
@ -15,13 +15,13 @@
|
|||
time: 36000 # 10 hours
|
||||
- !type:OverallPlaytimeRequirement
|
||||
time: 90000 # 25 hours
|
||||
- !type:WhitelistRequirement # whitelist requirement because I don't want any dingus judges
|
||||
weight: 20
|
||||
startingGear: CJGear
|
||||
icon: "JobIconChiefJustice"
|
||||
requireAdminNotify: true
|
||||
supervisors: job-supervisors-captain
|
||||
canBeAntag: false
|
||||
whitelisted: true # DeltaV: whitelist requirement because I don't want any dingus judges
|
||||
access:
|
||||
- Command
|
||||
- ChiefJustice
|
||||
|
|
|
|||
|
|
@ -24,7 +24,6 @@
|
|||
time: 108000 # DeltaV - 30 hours, was 15
|
||||
- !type:OverallPlaytimeRequirement # DeltaV - Playtime requirement
|
||||
time: 108000 # 30 hours
|
||||
- !type:WhitelistRequirement # DeltaV - Whitelist requirement
|
||||
- !type:AgeRequirement
|
||||
requiredAge: 21
|
||||
weight: 20
|
||||
|
|
@ -34,6 +33,7 @@
|
|||
joinNotifyCrew: true
|
||||
supervisors: job-supervisors-centcom
|
||||
canBeAntag: false
|
||||
whitelisted: true # DeltaV
|
||||
accessGroups:
|
||||
- AllAccess
|
||||
special:
|
||||
|
|
|
|||
|
|
@ -15,7 +15,6 @@
|
|||
time: 36000 # 10 hours
|
||||
- !type:OverallPlaytimeRequirement
|
||||
time: 90000 # DeltaV - 25 hours, was 40
|
||||
- !type:WhitelistRequirement # DeltaV - Whitelist requirement
|
||||
- !type:AgeRequirement
|
||||
requiredAge: 21
|
||||
weight: 10
|
||||
|
|
@ -24,6 +23,7 @@
|
|||
requireAdminNotify: true
|
||||
supervisors: job-supervisors-captain
|
||||
canBeAntag: false
|
||||
whitelisted: true # DeltaV
|
||||
access:
|
||||
- HeadOfSecurity
|
||||
- Command
|
||||
|
|
|
|||
Loading…
Reference in New Issue