Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

JobRequirement refactor #30347

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion Content.Client/LateJoin/LateJoinGui.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,11 @@
using System.Numerics;
using Content.Client.CrewManifest;
using Content.Client.GameTicking.Managers;
using Content.Client.Lobby;
using Content.Client.UserInterface.Controls;
using Content.Client.Players.PlayTimeTracking;
using Content.Shared.CCVar;
using Content.Shared.Preferences;
using Content.Shared.Roles;
using Content.Shared.StatusIcon;
using Robust.Client.Console;
Expand All @@ -26,6 +28,7 @@ public sealed class LateJoinGui : DefaultWindow
[Dependency] private readonly IConfigurationManager _configManager = default!;
[Dependency] private readonly IEntitySystemManager _entitySystem = default!;
[Dependency] private readonly JobRequirementsManager _jobRequirements = default!;
[Dependency] private readonly IClientPreferencesManager _preferencesManager = default!;

public event Action<(NetEntity, string)> SelectedId;

Expand Down Expand Up @@ -254,7 +257,7 @@ private void RebuildUI()

jobButton.OnPressed += _ => SelectedId.Invoke((id, jobButton.JobId));

if (!_jobRequirements.IsAllowed(prototype, out var reason))
if (!_jobRequirements.IsAllowed(prototype, (HumanoidCharacterProfile?)_preferencesManager.Preferences?.SelectedCharacter, out var reason))
{
jobButton.Disabled = true;

Expand Down
4 changes: 2 additions & 2 deletions Content.Client/Lobby/UI/HumanoidProfileEditor.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -634,7 +634,7 @@ public void RefreshAntags()
selector.Select(Profile?.AntagPreferences.Contains(antag.ID) == true ? 0 : 1);

var requirements = _entManager.System<SharedRoleSystem>().GetAntagRequirement(antag);
if (!_requirements.CheckRoleTime(requirements, out var reason))
if (!_requirements.CheckRoleRequirements(requirements, (HumanoidCharacterProfile?)_preferencesManager.Preferences?.SelectedCharacter, out var reason))
{
selector.LockRequirements(reason);
Profile = Profile?.WithAntagPreference(antag.ID, false);
Expand Down Expand Up @@ -887,7 +887,7 @@ public void RefreshJobs()
icon.Texture = jobIcon.Icon.Frame0();
selector.Setup(items, job.LocalizedName, 200, job.LocalizedDescription, icon, job.Guides);

if (!_requirements.IsAllowed(job, out var reason))
if (!_requirements.IsAllowed(job, (HumanoidCharacterProfile?)_preferencesManager.Preferences?.SelectedCharacter, out var reason))
{
selector.LockRequirements(reason);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
using System.Diagnostics.CodeAnalysis;
using Content.Client.Lobby;
using Content.Shared.CCVar;
using Content.Shared.Players;
using Content.Shared.Players.JobWhitelist;
using Content.Shared.Players.PlayTimeTracking;
using Content.Shared.Preferences;
using Content.Shared.Roles;
using Robust.Client;
using Robust.Client.Player;
Expand Down Expand Up @@ -89,7 +91,7 @@ private void RxJobWhitelist(MsgJobWhitelist message)
Updated?.Invoke();
}

public bool IsAllowed(JobPrototype job, [NotNullWhen(false)] out FormattedMessage? reason)
public bool IsAllowed(JobPrototype job, HumanoidCharacterProfile? profile, [NotNullWhen(false)] out FormattedMessage? reason)
{
reason = null;

Expand All @@ -106,16 +108,16 @@ public bool IsAllowed(JobPrototype job, [NotNullWhen(false)] out FormattedMessag
if (player == null)
return true;

return CheckRoleTime(job, out reason);
return CheckRoleRequirements(job, profile, out reason);
}

public bool CheckRoleTime(JobPrototype job, [NotNullWhen(false)] out FormattedMessage? reason)
public bool CheckRoleRequirements(JobPrototype job, HumanoidCharacterProfile? profile, [NotNullWhen(false)] out FormattedMessage? reason)
{
var reqs = _entManager.System<SharedRoleSystem>().GetJobRequirement(job);
return CheckRoleTime(reqs, out reason);
return CheckRoleRequirements(reqs, profile, out reason);
}

public bool CheckRoleTime(HashSet<JobRequirement>? requirements, [NotNullWhen(false)] out FormattedMessage? reason)
public bool CheckRoleRequirements(HashSet<JobRequirement>? requirements, HumanoidCharacterProfile? profile, [NotNullWhen(false)] out FormattedMessage? reason)
{
reason = null;

Expand All @@ -125,7 +127,7 @@ public bool CheckRoleTime(HashSet<JobRequirement>? requirements, [NotNullWhen(fa
var reasons = new List<string>();
foreach (var requirement in requirements)
{
if (JobRequirements.TryRequirementMet(requirement, _roles, out var jobReason, _entManager, _prototypes))
if (requirement.Check(_entManager, _prototypes, profile, _roles, out var jobReason))
continue;

reasons.Add(jobReason.ToMarkup());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ public override void HandleState(EuiStateBase state)
bool hasAccess = true;
FormattedMessage? reason;

if (!requirementsManager.CheckRoleTime(group.Key.Requirements, out reason))
if (!requirementsManager.CheckRoleRequirements(group.Key.Requirements, null, out reason))
{
hasAccess = false;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,15 @@
using Content.Server.GameTicking;
using Content.Server.GameTicking.Events;
using Content.Server.Mind;
using Content.Server.Preferences.Managers;
using Content.Server.Station.Events;
using Content.Shared.CCVar;
using Content.Shared.GameTicking;
using Content.Shared.Mobs;
using Content.Shared.Mobs.Components;
using Content.Shared.Players;
using Content.Shared.Players.PlayTimeTracking;
using Content.Shared.Preferences;
using Content.Shared.Roles;
using Robust.Server.Player;
using Robust.Shared.Configuration;
Expand All @@ -35,6 +37,7 @@ public sealed class PlayTimeTrackingSystem : EntitySystem
[Dependency] private readonly MindSystem _minds = default!;
[Dependency] private readonly PlayTimeTrackingManager _tracking = default!;
[Dependency] private readonly IAdminManager _adminManager = default!;
[Dependency] private readonly IServerPreferencesManager _preferencesManager = default!;

public override void Initialize()
{
Expand Down Expand Up @@ -206,7 +209,7 @@ public bool IsAllowed(ICommonSession player, string role)
playTimes = new Dictionary<string, TimeSpan>();
}

return JobRequirements.TryRequirementsMet(job, playTimes, out _, EntityManager, _prototypes);
return JobRequirements.TryRequirementsMet(job, playTimes, out _, EntityManager, _prototypes, (HumanoidCharacterProfile?) _preferencesManager.GetPreferences(player.UserId).SelectedCharacter);
}

public HashSet<ProtoId<JobPrototype>> GetDisallowedJobs(ICommonSession player)
Expand All @@ -223,7 +226,7 @@ public HashSet<ProtoId<JobPrototype>> GetDisallowedJobs(ICommonSession player)

foreach (var job in _prototypes.EnumeratePrototypes<JobPrototype>())
{
if (JobRequirements.TryRequirementsMet(job, playTimes, out _, EntityManager, _prototypes))
if (JobRequirements.TryRequirementsMet(job, playTimes, out _, EntityManager, _prototypes, (HumanoidCharacterProfile?) _preferencesManager.GetPreferences(player.UserId).SelectedCharacter))
roles.Add(job.ID);
}

Expand All @@ -246,7 +249,7 @@ public void RemoveDisallowedJobs(NetUserId userId, List<ProtoId<JobPrototype>> j
for (var i = 0; i < jobs.Count; i++)
{
if (_prototypes.TryIndex(jobs[i], out var job)
&& JobRequirements.TryRequirementsMet(job, playTimes, out _, EntityManager, _prototypes))
&& JobRequirements.TryRequirementsMet(job, playTimes, out _, EntityManager, _prototypes, (HumanoidCharacterProfile?) _preferencesManager.GetPreferences(userId).SelectedCharacter))
{
continue;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,10 @@ public override bool Validate(HumanoidCharacterProfile profile, RoleLoadout load

var manager = collection.Resolve<ISharedPlaytimeManager>();
var playtimes = manager.GetPlayTimes(session);
return JobRequirements.TryRequirementMet(Requirement, playtimes, out reason,
collection.Resolve<IEntityManager>(),
collection.Resolve<IPrototypeManager>());
return Requirement.Check(collection.Resolve<IEntityManager>(),
collection.Resolve<IPrototypeManager>(),
profile,
playtimes,
out reason);
}
}
10 changes: 8 additions & 2 deletions Content.Shared/Roles/DepartmentPrototype.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,16 @@ public sealed partial class DepartmentPrototype : IPrototype
public string ID { get; } = string.Empty;

/// <summary>
/// A description string to display in the character menu as an explanation of the department's function.
/// The name LocId of the department that will be displayed in the various menus.
/// </summary>
[DataField(required: true)]
public string Description = string.Empty;
public LocId Name = string.Empty;

/// <summary>
/// A description LocId to display in the character menu as an explanation of the department's function.
/// </summary>
[DataField(required: true)]
public LocId Description = string.Empty;

/// <summary>
/// A color representing this department to use for text.
Expand Down
50 changes: 50 additions & 0 deletions Content.Shared/Roles/JobRequirement/AgeRequirement.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
using System.Diagnostics.CodeAnalysis;
using Content.Shared.Preferences;
using JetBrains.Annotations;
using Robust.Shared.Prototypes;
using Robust.Shared.Serialization;
using Robust.Shared.Utility;

namespace Content.Shared.Roles;

/// <summary>
/// Requires the character to be older or younger than a certain age (inclusive)
/// </summary>
[UsedImplicitly]
[Serializable, NetSerializable]
public sealed partial class AgeRequirement : JobRequirement
{
[DataField(required: true)]
public int RequiredAge;

public override bool Check(IEntityManager entManager,
IPrototypeManager protoManager,
HumanoidCharacterProfile? profile,
IReadOnlyDictionary<string, TimeSpan> playTimes,
[NotNullWhen(false)] out FormattedMessage? reason)
{
reason = new FormattedMessage();

if (profile is null) //the profile could be null if the player is a ghost. In this case we don't need to block the role selection for ghostrole
return true;

if (!Inverted)
{
reason = FormattedMessage.FromMarkupPermissive(Loc.GetString("role-timer-age-to-young",
("age", RequiredAge)));

if (profile.Age <= RequiredAge)
return false;
}
else
{
reason = FormattedMessage.FromMarkupPermissive(Loc.GetString("role-timer-age-to-old",
("age", RequiredAge)));

if (profile.Age >= RequiredAge)
return false;
}

return true;
}
}
83 changes: 83 additions & 0 deletions Content.Shared/Roles/JobRequirement/DepartmentTimeRequirement.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
using System.Diagnostics.CodeAnalysis;
using Content.Shared.Preferences;
using JetBrains.Annotations;
using Robust.Shared.Prototypes;
using Robust.Shared.Serialization;
using Robust.Shared.Utility;

namespace Content.Shared.Roles;

[UsedImplicitly]
[Serializable, NetSerializable]
public sealed partial class DepartmentTimeRequirement : JobRequirement
{
/// <summary>
/// Which department needs the required amount of time.
/// </summary>
[DataField(required: true)]
public ProtoId<DepartmentPrototype> Department = default!;

/// <summary>
/// How long (in seconds) this requirement is.
/// </summary>
[DataField(required: true)]
public TimeSpan Time;

public override bool Check(IEntityManager entManager,
IPrototypeManager protoManager,
HumanoidCharacterProfile? profile,
IReadOnlyDictionary<string, TimeSpan> playTimes,
[NotNullWhen(false)] out FormattedMessage? reason)
{
reason = new FormattedMessage();
var playtime = TimeSpan.Zero;

// Check all jobs' departments
var department = protoManager.Index(Department);
var jobs = department.Roles;
string proto;

// Check all jobs' playtime
foreach (var other in jobs)
{
// The schema is stored on the Job role but we want to explode if the timer isn't found anyway.
proto = protoManager.Index(other).PlayTimeTracker;

playTimes.TryGetValue(proto, out var otherTime);
playtime += otherTime;
}

var deptDiff = Time.TotalMinutes - playtime.TotalMinutes;
var nameDepartment = "role-timer-department-unknown";

if (protoManager.TryIndex(Department, out var departmentIndexed))
{
nameDepartment = departmentIndexed.Name;
}

if (!Inverted)
{
if (deptDiff <= 0)
return true;

reason = FormattedMessage.FromMarkupPermissive(Loc.GetString(
"role-timer-department-insufficient",
("time", Math.Ceiling(deptDiff)),
("department", Loc.GetString(nameDepartment)),
("departmentColor", department.Color.ToHex())));
return false;
}

if (deptDiff <= 0)
{
reason = FormattedMessage.FromMarkupPermissive(Loc.GetString(
"role-timer-department-too-high",
("time", -deptDiff),
("department", Loc.GetString(nameDepartment)),
("departmentColor", department.Color.ToHex())));
return false;
}

return true;
}
}
50 changes: 50 additions & 0 deletions Content.Shared/Roles/JobRequirement/OverallPlaytimeRequirement.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
using System.Diagnostics.CodeAnalysis;
using Content.Shared.Players.PlayTimeTracking;
using Content.Shared.Preferences;
using JetBrains.Annotations;
using Robust.Shared.Prototypes;
using Robust.Shared.Serialization;
using Robust.Shared.Utility;

namespace Content.Shared.Roles;

[UsedImplicitly]
[Serializable, NetSerializable]
public sealed partial class OverallPlaytimeRequirement : JobRequirement
{
/// <inheritdoc cref="DepartmentTimeRequirement.Time"/>
[DataField(required: true)]
public TimeSpan Time;

public override bool Check(IEntityManager entManager,
IPrototypeManager protoManager,
HumanoidCharacterProfile? profile,
IReadOnlyDictionary<string, TimeSpan> playTimes,
[NotNullWhen(false)] out FormattedMessage? reason)
{
reason = new FormattedMessage();

var overallTime = playTimes.GetValueOrDefault(PlayTimeTrackingShared.TrackerOverall);
var overallDiff = Time.TotalMinutes - overallTime.TotalMinutes;

if (!Inverted)
{
if (overallDiff <= 0 || overallTime >= Time)
return true;

reason = FormattedMessage.FromMarkupPermissive(Loc.GetString(
"role-timer-overall-insufficient",
("time", Math.Ceiling(overallDiff))));
return false;
}

if (overallDiff <= 0 || overallTime >= Time)
{
reason = FormattedMessage.FromMarkupPermissive(Loc.GetString("role-timer-overall-too-high",
("time", -overallDiff)));
return false;
}

return true;
}
}
Loading
Loading