diff --git a/Content.Client/Nyanotrasen/Players/PlayTimeTracking/JobRequirementsManager.Whitelist.cs b/Content.Client/Nyanotrasen/Players/PlayTimeTracking/JobRequirementsManager.Whitelist.cs new file mode 100644 index 00000000000..9b1f2d203f4 --- /dev/null +++ b/Content.Client/Nyanotrasen/Players/PlayTimeTracking/JobRequirementsManager.Whitelist.cs @@ -0,0 +1,22 @@ +using System.Diagnostics.CodeAnalysis; +using Content.Shared.CCVar; +using Content.Shared.Players.PlayTimeTracking; +using Content.Shared.Roles; +using Robust.Shared.Utility; + +namespace Content.Client.Players.PlayTimeTracking; + +public sealed partial class JobRequirementsManager +{ + private bool _whitelisted = false; + + private void RxWhitelist(MsgWhitelist message) + { + _whitelisted = message.Whitelisted; + } + + public bool IsWhitelisted() + { + return _whitelisted; + } +} diff --git a/Content.Client/Players/PlayTimeTracking/JobRequirementsManager.cs b/Content.Client/Players/PlayTimeTracking/JobRequirementsManager.cs index 34b3ec10b5f..a92b88a8263 100644 --- a/Content.Client/Players/PlayTimeTracking/JobRequirementsManager.cs +++ b/Content.Client/Players/PlayTimeTracking/JobRequirementsManager.cs @@ -14,7 +14,7 @@ namespace Content.Client.Players.PlayTimeTracking; -public sealed class JobRequirementsManager +public sealed partial class JobRequirementsManager { [Dependency] private readonly IBaseClient _client = default!; [Dependency] private readonly IClientNetManager _net = default!; @@ -30,8 +30,6 @@ public sealed class JobRequirementsManager public event Action? Updated; - private bool _whitelisted = false; - public void Initialize() { _sawmill = Logger.GetSawmill("job_requirements"); @@ -40,6 +38,7 @@ public void Initialize() _net.RegisterNetMessage(RxRoleBans); _net.RegisterNetMessage(RxPlayTime); _net.RegisterNetMessage(RxWhitelist); + _client.RunLevelChanged += ClientOnRunLevelChanged; } @@ -81,10 +80,6 @@ private void RxPlayTime(MsgPlayTime message) }*/ Updated?.Invoke(); } - private void RxWhitelist(MsgWhitelist message) - { - _whitelisted = message.Whitelisted; - } public bool IsAllowed(JobPrototype job, [NotNullWhen(false)] out FormattedMessage? reason) { @@ -119,7 +114,7 @@ public bool CheckRoleTime(HashSet? requirements, [NotNullWhen(fa var reasons = new List(); foreach (var requirement in requirements) { - if (JobRequirements.TryRequirementMet(requirement, _roles, out var jobReason, _entManager, _prototypes)) + if (JobRequirements.TryRequirementMet(requirement, _roles, out var jobReason, _entManager, _prototypes, _whitelisted)) continue; reasons.Add(jobReason.ToMarkup()); diff --git a/Content.Server/GameTicking/GameTicker.Player.cs b/Content.Server/GameTicking/GameTicker.Player.cs index 3aef1bbe785..9161137a252 100644 --- a/Content.Server/GameTicking/GameTicker.Player.cs +++ b/Content.Server/GameTicking/GameTicker.Player.cs @@ -128,6 +128,8 @@ async void SpawnWaitDb() { await _userDb.WaitLoadComplete(session); + session.ContentData()!.Whitelisted = await _db.GetWhitelistStatusAsync(session.UserId); // Nyanotrasen - Whitelist + SpawnPlayer(session, EntityUid.Invalid); } diff --git a/Content.Server/Nyanotrasen/Players/PlayTimeTracking/PlayTimeTrackingManager.Whitelist.cs b/Content.Server/Nyanotrasen/Players/PlayTimeTracking/PlayTimeTrackingManager.Whitelist.cs new file mode 100644 index 00000000000..335384934ca --- /dev/null +++ b/Content.Server/Nyanotrasen/Players/PlayTimeTracking/PlayTimeTrackingManager.Whitelist.cs @@ -0,0 +1,20 @@ +using Content.Server.Players; +using Content.Shared.Players.PlayTimeTracking; +using Robust.Server.Player; + +namespace Content.Server.Players.PlayTimeTracking; + +public sealed partial class PlayTimeTrackingManager +{ + public void SendWhitelistCached(IPlayerSession playerSession) + { + var whitelist = playerSession.ContentData()?.Whitelisted ?? false; + + var msg = new MsgWhitelist + { + Whitelisted = whitelist + }; + + _net.ServerSendMessage(msg, playerSession.ConnectedClient); + } +} diff --git a/Content.Server/Players/PlayTimeTracking/PlayTimeTrackingManager.cs b/Content.Server/Players/PlayTimeTracking/PlayTimeTrackingManager.cs index 4103311fde9..3ecb6a744d9 100644 --- a/Content.Server/Players/PlayTimeTracking/PlayTimeTrackingManager.cs +++ b/Content.Server/Players/PlayTimeTracking/PlayTimeTrackingManager.cs @@ -54,7 +54,7 @@ namespace Content.Server.Players.PlayTimeTracking; /// Operations like refreshing and sending play time info to clients are deferred until the next frame (note: not tick). /// /// -public sealed class PlayTimeTrackingManager +public sealed partial class PlayTimeTrackingManager { [Dependency] private readonly IServerDbManager _db = default!; [Dependency] private readonly IServerNetManager _net = default!; diff --git a/Content.Server/Players/PlayTimeTracking/PlayTimeTrackingSystem.cs b/Content.Server/Players/PlayTimeTracking/PlayTimeTrackingSystem.cs index 13d0794dd5e..7d62c54fc26 100644 --- a/Content.Server/Players/PlayTimeTracking/PlayTimeTrackingSystem.cs +++ b/Content.Server/Players/PlayTimeTracking/PlayTimeTrackingSystem.cs @@ -165,7 +165,9 @@ public bool IsAllowed(IPlayerSession player, string role) var playTimes = _tracking.GetTrackerTimes(player); - return JobRequirements.TryRequirementsMet(job, playTimes, out _, EntityManager, _prototypes); + var isWhitelisted = player.ContentData()?.Whitelisted ?? false; // DeltaV - Whitelist requirement + + return JobRequirements.TryRequirementsMet(job, playTimes, out _, EntityManager, _prototypes, isWhitelisted); } public HashSet GetDisallowedJobs(IPlayerSession player) @@ -175,6 +177,7 @@ public HashSet GetDisallowedJobs(IPlayerSession player) return roles; var playTimes = _tracking.GetTrackerTimes(player); + var isWhitelisted = player.ContentData()?.Whitelisted ?? false; // DeltaV - Whitelist requirement foreach (var job in _prototypes.EnumeratePrototypes()) { @@ -182,7 +185,7 @@ public HashSet GetDisallowedJobs(IPlayerSession player) { foreach (var requirement in job.Requirements) { - if (JobRequirements.TryRequirementMet(requirement, playTimes, out _, EntityManager, _prototypes)) + if (JobRequirements.TryRequirementMet(requirement, playTimes, out _, EntityManager, _prototypes, isWhitelisted)) continue; goto NoRole; @@ -209,6 +212,8 @@ public void RemoveDisallowedJobs(NetUserId userId, ref List jobs) playTimes ??= new Dictionary(); } + var isWhitelisted = player.ContentData()?.Whitelisted ?? false; // DeltaV - Whitelist requirement + for (var i = 0; i < jobs.Count; i++) { var job = jobs[i]; @@ -220,7 +225,7 @@ public void RemoveDisallowedJobs(NetUserId userId, ref List jobs) foreach (var requirement in jobber.Requirements) { - if (JobRequirements.TryRequirementMet(requirement, playTimes, out _, EntityManager, _prototypes)) + if (JobRequirements.TryRequirementMet(requirement, playTimes, out _, EntityManager, _prototypes, isWhitelisted)) continue; jobs.RemoveSwap(i); diff --git a/Content.Server/Whitelist/WhitelistCommands.cs b/Content.Server/Whitelist/WhitelistCommands.cs index 59b576e7ca4..67d9645414c 100644 --- a/Content.Server/Whitelist/WhitelistCommands.cs +++ b/Content.Server/Whitelist/WhitelistCommands.cs @@ -1,7 +1,9 @@ using Content.Server.Administration; using Content.Server.Database; +using Content.Server.Players.PlayTimeTracking; using Content.Shared.Administration; using Content.Shared.CCVar; +using Content.Shared.Players; using Robust.Server.Player; using Robust.Shared.Configuration; using Robust.Shared.Console; @@ -22,6 +24,8 @@ public async void Execute(IConsoleShell shell, string argStr, string[] args) var db = IoCManager.Resolve(); var loc = IoCManager.Resolve(); + var player = IoCManager.Resolve(); + var playtime = IoCManager.Resolve(); var name = args[0]; var data = await loc.LookupIdByNameAsync(name); @@ -37,6 +41,15 @@ public async void Execute(IConsoleShell shell, string argStr, string[] args) } await db.AddToWhitelistAsync(guid); + + // Nyanotrasen - Update whitelist status in player data. + if (player.TryGetPlayerDataByUsername(name, out var playerData) && + player.TryGetSessionByUsername(name, out var session)) + { + playerData.ContentData()!.Whitelisted = true; + playtime.SendWhitelistCached(session); + } + shell.WriteLine(Loc.GetString("command-whitelistadd-added", ("username", data.Username))); return; } @@ -58,6 +71,8 @@ public async void Execute(IConsoleShell shell, string argStr, string[] args) var db = IoCManager.Resolve(); var loc = IoCManager.Resolve(); + var player = IoCManager.Resolve(); + var playtime = IoCManager.Resolve(); var name = args[0]; var data = await loc.LookupIdByNameAsync(name); @@ -73,6 +88,15 @@ public async void Execute(IConsoleShell shell, string argStr, string[] args) } await db.RemoveFromWhitelistAsync(guid); + + // Nyanotrasen - Update whitelist status in player data. + if (player.TryGetPlayerDataByUsername(name, out var playerData) && + player.TryGetSessionByUsername(name, out var session)) + { + playerData.ContentData()!.Whitelisted = false; + playtime.SendWhitelistCached(session); + } + shell.WriteLine(Loc.GetString("command-whitelistremove-removed", ("username", data.Username))); return; } diff --git a/Content.Shared/DeltaV/Roles/JobRequirements.Whitelist.cs b/Content.Shared/DeltaV/Roles/JobRequirements.Whitelist.cs new file mode 100644 index 00000000000..a6e352991e9 --- /dev/null +++ b/Content.Shared/DeltaV/Roles/JobRequirements.Whitelist.cs @@ -0,0 +1,11 @@ +using JetBrains.Annotations; +using Robust.Shared.Serialization; + +namespace Content.Shared.Roles +{ + [UsedImplicitly] + [Serializable, NetSerializable] + public sealed partial class WhitelistRequirement : JobRequirement + { + } +} diff --git a/Content.Shared/_NF/PlayTime/MsgWhiteList.cs b/Content.Shared/Nyanotrasen/Players/PlayTimeTracking/MsgWhitelist.cs similarity index 100% rename from Content.Shared/_NF/PlayTime/MsgWhiteList.cs rename to Content.Shared/Nyanotrasen/Players/PlayTimeTracking/MsgWhitelist.cs diff --git a/Content.Shared/Players/PlayerData.cs b/Content.Shared/Players/PlayerData.cs index c6274c950bd..d94bef2e387 100644 --- a/Content.Shared/Players/PlayerData.cs +++ b/Content.Shared/Players/PlayerData.cs @@ -38,6 +38,12 @@ public sealed class PlayerData /// public bool ExplicitlyDeadminned { get; set; } + /// + /// Nyanotrasen - Are they whitelisted? Lets us avoid async. + /// + [ViewVariables] + public bool Whitelisted { get; set; } + public PlayerData(NetUserId userId, string name) { UserId = userId; diff --git a/Content.Shared/Roles/JobRequirements.cs b/Content.Shared/Roles/JobRequirements.cs index fc3b759a9c2..2785e988bcd 100644 --- a/Content.Shared/Roles/JobRequirements.cs +++ b/Content.Shared/Roles/JobRequirements.cs @@ -2,6 +2,7 @@ using Content.Shared.Players.PlayTimeTracking; using Content.Shared.Roles.Jobs; using JetBrains.Annotations; +using Robust.Shared.Players; using Robust.Shared.Prototypes; using Robust.Shared.Serialization; using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype; @@ -76,7 +77,8 @@ public static bool TryRequirementsMet( Dictionary playTimes, [NotNullWhen(false)] out FormattedMessage? reason, IEntityManager entManager, - IPrototypeManager prototypes) + IPrototypeManager prototypes, + bool isWhitelisted) { reason = null; if (job.Requirements == null) @@ -84,7 +86,7 @@ public static bool TryRequirementsMet( foreach (var requirement in job.Requirements) { - if (!TryRequirementMet(requirement, playTimes, out reason, entManager, prototypes)) + if (!TryRequirementMet(requirement, playTimes, out reason, entManager, prototypes, isWhitelisted)) return false; } @@ -99,7 +101,8 @@ public static bool TryRequirementMet( Dictionary playTimes, [NotNullWhen(false)] out FormattedMessage? reason, IEntityManager entManager, - IPrototypeManager prototypes) + IPrototypeManager prototypes, + bool isWhitelisted) { reason = null; @@ -216,6 +219,15 @@ public static bool TryRequirementMet( return true; } + case WhitelistRequirement _: // DeltaV - Whitelist requirement + if (isWhitelisted == null) + throw new ArgumentNullException(nameof(isWhitelisted), "isWhitelisted cannot be null."); + + if (isWhitelisted) + return true; + + reason = FormattedMessage.FromMarkup(Loc.GetString("playtime-deny-reason-not-whitelisted")); + return false; default: throw new NotImplementedException(); } diff --git a/Resources/Locale/en-US/players/play-time/whitelist.ftl b/Resources/Locale/en-US/players/play-time/whitelist.ftl new file mode 100644 index 00000000000..c6a5a9e07a8 --- /dev/null +++ b/Resources/Locale/en-US/players/play-time/whitelist.ftl @@ -0,0 +1 @@ +playtime-deny-reason-not-whitelisted = You need to be whitelisted. diff --git a/Resources/Prototypes/Roles/Jobs/Command/head_of_personnel.yml b/Resources/Prototypes/Roles/Jobs/Command/head_of_personnel.yml index 1db56c16caa..d7538485cf9 100644 --- a/Resources/Prototypes/Roles/Jobs/Command/head_of_personnel.yml +++ b/Resources/Prototypes/Roles/Jobs/Command/head_of_personnel.yml @@ -6,6 +6,7 @@ requirements: - !type:OverallPlaytimeRequirement time: 36000 + - !type:WhitelistRequirement weight: 20 startingGear: HoPGear icon: "JobIconHeadOfPersonnel" diff --git a/Resources/Prototypes/Roles/Jobs/Security/head_of_security.yml b/Resources/Prototypes/Roles/Jobs/Security/head_of_security.yml index 872d389992b..008684cf962 100644 --- a/Resources/Prototypes/Roles/Jobs/Security/head_of_security.yml +++ b/Resources/Prototypes/Roles/Jobs/Security/head_of_security.yml @@ -6,6 +6,7 @@ requirements: - !type:OverallPlaytimeRequirement time: 50400 + - !type:WhitelistRequirement # - !type:RoleTimeRequirement # role: JobWarden # time: 21600 #6 hrs