Add Job preference tests (#28625)
* Misc Job related changes * Add JobTest * A * Aa * Lets not confuse the yaml linter * fixes * a
This commit is contained in:
@@ -3,6 +3,7 @@ using System.Linq;
|
||||
using Content.Server.GameTicking;
|
||||
using Content.Server.Station.Components;
|
||||
using Content.Shared.CCVar;
|
||||
using Content.Shared.FixedPoint;
|
||||
using Content.Shared.GameTicking;
|
||||
using Content.Shared.Preferences;
|
||||
using Content.Shared.Roles;
|
||||
@@ -31,12 +32,25 @@ public sealed partial class StationJobsSystem : EntitySystem
|
||||
public override void Initialize()
|
||||
{
|
||||
SubscribeLocalEvent<StationInitializedEvent>(OnStationInitialized);
|
||||
SubscribeLocalEvent<StationJobsComponent, ComponentInit>(OnInit);
|
||||
SubscribeLocalEvent<StationJobsComponent, StationRenamedEvent>(OnStationRenamed);
|
||||
SubscribeLocalEvent<StationJobsComponent, ComponentShutdown>(OnStationDeletion);
|
||||
SubscribeLocalEvent<PlayerJoinedLobbyEvent>(OnPlayerJoinedLobby);
|
||||
Subs.CVar(_configurationManager, CCVars.GameDisallowLateJoins, _ => UpdateJobsAvailable(), true);
|
||||
}
|
||||
|
||||
private void OnInit(Entity<StationJobsComponent> ent, ref ComponentInit args)
|
||||
{
|
||||
ent.Comp.MidRoundTotalJobs = ent.Comp.SetupAvailableJobs.Values
|
||||
.Select(x => Math.Max(x[1], 0))
|
||||
.Sum();
|
||||
|
||||
ent.Comp.OverflowJobs = ent.Comp.SetupAvailableJobs
|
||||
.Where(x => x.Value[0] < 0)
|
||||
.Select(x => x.Key)
|
||||
.ToHashSet();
|
||||
}
|
||||
|
||||
public override void Update(float _)
|
||||
{
|
||||
if (_availableJobsDirty)
|
||||
@@ -57,28 +71,11 @@ public sealed partial class StationJobsSystem : EntitySystem
|
||||
if (!TryComp<StationJobsComponent>(msg.Station, out var stationJobs))
|
||||
return;
|
||||
|
||||
var mapJobList = stationJobs.SetupAvailableJobs;
|
||||
stationJobs.JobList = stationJobs.SetupAvailableJobs.ToDictionary(
|
||||
x => x.Key,
|
||||
x=> (int?)(x.Value[1] < 0 ? null : x.Value[1]));
|
||||
|
||||
stationJobs.RoundStartTotalJobs = mapJobList.Values.Where(x => x[0] is not null && x[0] > 0).Sum(x => x[0]!.Value);
|
||||
stationJobs.MidRoundTotalJobs = mapJobList.Values.Where(x => x[1] is not null && x[1] > 0).Sum(x => x[1]!.Value);
|
||||
|
||||
stationJobs.TotalJobs = stationJobs.MidRoundTotalJobs;
|
||||
|
||||
stationJobs.JobList = mapJobList.ToDictionary(x => x.Key, x =>
|
||||
{
|
||||
if (x.Value[1] <= -1)
|
||||
return null;
|
||||
return (uint?) x.Value[1];
|
||||
});
|
||||
|
||||
stationJobs.RoundStartJobList = mapJobList.ToDictionary(x => x.Key, x =>
|
||||
{
|
||||
if (x.Value[0] <= -1)
|
||||
return null;
|
||||
return (uint?) x.Value[0];
|
||||
});
|
||||
|
||||
stationJobs.OverflowJobs = stationJobs.OverflowJobs.ToHashSet();
|
||||
stationJobs.TotalJobs = stationJobs.JobList.Values.Select(x => x ?? 0).Sum();
|
||||
|
||||
UpdateJobsAvailable();
|
||||
}
|
||||
@@ -141,7 +138,11 @@ public sealed partial class StationJobsSystem : EntitySystem
|
||||
/// <param name="stationJobs">Resolve pattern, station jobs component of the station.</param>
|
||||
/// <returns>Whether or not slot adjustment was a success.</returns>
|
||||
/// <exception cref="ArgumentException">Thrown when the given station is not a station.</exception>
|
||||
public bool TryAdjustJobSlot(EntityUid station, string jobPrototypeId, int amount, bool createSlot = false, bool clamp = false,
|
||||
public bool TryAdjustJobSlot(EntityUid station,
|
||||
string jobPrototypeId,
|
||||
int amount,
|
||||
bool createSlot = false,
|
||||
bool clamp = false,
|
||||
StationJobsComponent? stationJobs = null)
|
||||
{
|
||||
if (!Resolve(station, ref stationJobs))
|
||||
@@ -156,7 +157,11 @@ public sealed partial class StationJobsSystem : EntitySystem
|
||||
// - Return false when you remove from a job that doesn't exist.
|
||||
// - Return false when you remove and exceed the number of slots available.
|
||||
// And additionally, if adding would add a job not previously on the manifest when createSlot is false, return false and do nothing.
|
||||
switch (jobList.ContainsKey(jobPrototypeId))
|
||||
|
||||
if (amount == 0)
|
||||
return true;
|
||||
|
||||
switch (jobList.TryGetValue(jobPrototypeId, out var available))
|
||||
{
|
||||
case false when amount < 0:
|
||||
return false;
|
||||
@@ -164,31 +169,20 @@ public sealed partial class StationJobsSystem : EntitySystem
|
||||
if (!createSlot)
|
||||
return false;
|
||||
stationJobs.TotalJobs += amount;
|
||||
jobList[jobPrototypeId] = (uint?)amount;
|
||||
jobList[jobPrototypeId] = amount;
|
||||
UpdateJobsAvailable();
|
||||
return true;
|
||||
case true:
|
||||
// Job is unlimited so just say we adjusted it and do nothing.
|
||||
if (jobList[jobPrototypeId] == null)
|
||||
if (available is not {} avail)
|
||||
return true;
|
||||
|
||||
// Would remove more jobs than we have available.
|
||||
if (amount < 0 && (jobList[jobPrototypeId] + amount < 0 && !clamp))
|
||||
if (available + amount < 0 && !clamp)
|
||||
return false;
|
||||
|
||||
stationJobs.TotalJobs += amount;
|
||||
|
||||
//C# type handling moment
|
||||
if (amount > 0)
|
||||
jobList[jobPrototypeId] += (uint)amount;
|
||||
else
|
||||
{
|
||||
if ((int)jobList[jobPrototypeId]!.Value - Math.Abs(amount) <= 0)
|
||||
jobList[jobPrototypeId] = 0;
|
||||
else
|
||||
jobList[jobPrototypeId] -= (uint) Math.Abs(amount);
|
||||
}
|
||||
|
||||
jobList[jobPrototypeId] = Math.Max(avail + amount, 0);
|
||||
stationJobs.TotalJobs = jobList.Values.Select(x => x ?? 0).Sum();
|
||||
UpdateJobsAvailable();
|
||||
return true;
|
||||
}
|
||||
@@ -239,7 +233,10 @@ public sealed partial class StationJobsSystem : EntitySystem
|
||||
/// <param name="stationJobs">Resolve pattern, station jobs component of the station.</param>
|
||||
/// <returns>Whether or not setting the value succeeded.</returns>
|
||||
/// <exception cref="ArgumentException">Thrown when the given station is not a station.</exception>
|
||||
public bool TrySetJobSlot(EntityUid station, string jobPrototypeId, int amount, bool createSlot = false,
|
||||
public bool TrySetJobSlot(EntityUid station,
|
||||
string jobPrototypeId,
|
||||
int amount,
|
||||
bool createSlot = false,
|
||||
StationJobsComponent? stationJobs = null)
|
||||
{
|
||||
if (!Resolve(station, ref stationJobs))
|
||||
@@ -255,13 +252,13 @@ public sealed partial class StationJobsSystem : EntitySystem
|
||||
if (!createSlot)
|
||||
return false;
|
||||
stationJobs.TotalJobs += amount;
|
||||
jobList[jobPrototypeId] = (uint?)amount;
|
||||
jobList[jobPrototypeId] = amount;
|
||||
UpdateJobsAvailable();
|
||||
return true;
|
||||
case true:
|
||||
stationJobs.TotalJobs += amount - (int) (jobList[jobPrototypeId] ?? 0);
|
||||
stationJobs.TotalJobs += amount - (jobList[jobPrototypeId] ?? 0);
|
||||
|
||||
jobList[jobPrototypeId] = (uint)amount;
|
||||
jobList[jobPrototypeId] = amount;
|
||||
UpdateJobsAvailable();
|
||||
return true;
|
||||
}
|
||||
@@ -289,8 +286,8 @@ public sealed partial class StationJobsSystem : EntitySystem
|
||||
throw new ArgumentException("Tried to use a non-station entity as a station!", nameof(station));
|
||||
|
||||
// Subtract out the job we're fixing to make have unlimited slots.
|
||||
if (stationJobs.JobList.ContainsKey(jobPrototypeId) && stationJobs.JobList[jobPrototypeId] != null)
|
||||
stationJobs.TotalJobs -= (int)stationJobs.JobList[jobPrototypeId]!.Value;
|
||||
if (stationJobs.JobList.TryGetValue(jobPrototypeId, out var existing))
|
||||
stationJobs.TotalJobs -= existing ?? 0;
|
||||
|
||||
stationJobs.JobList[jobPrototypeId] = null;
|
||||
|
||||
@@ -319,8 +316,7 @@ public sealed partial class StationJobsSystem : EntitySystem
|
||||
if (!Resolve(station, ref stationJobs))
|
||||
throw new ArgumentException("Tried to use a non-station entity as a station!", nameof(station));
|
||||
|
||||
var res = stationJobs.JobList.TryGetValue(jobPrototypeId, out var job) && job == null;
|
||||
return res;
|
||||
return stationJobs.JobList.TryGetValue(jobPrototypeId, out var job) && job == null;
|
||||
}
|
||||
|
||||
/// <inheritdoc cref="TryGetJobSlot(Robust.Shared.GameObjects.EntityUid,string,out System.Nullable{uint},Content.Server.Station.Components.StationJobsComponent?)"/>
|
||||
@@ -328,7 +324,7 @@ public sealed partial class StationJobsSystem : EntitySystem
|
||||
/// <param name="job">Job to get slot info for.</param>
|
||||
/// <param name="slots">The number of slots remaining. Null if infinite.</param>
|
||||
/// <param name="stationJobs">Resolve pattern, station jobs component of the station.</param>
|
||||
public bool TryGetJobSlot(EntityUid station, JobPrototype job, out uint? slots, StationJobsComponent? stationJobs = null)
|
||||
public bool TryGetJobSlot(EntityUid station, JobPrototype job, out int? slots, StationJobsComponent? stationJobs = null)
|
||||
{
|
||||
return TryGetJobSlot(station, job.ID, out slots, stationJobs);
|
||||
}
|
||||
@@ -343,21 +339,12 @@ public sealed partial class StationJobsSystem : EntitySystem
|
||||
/// <returns>Whether or not the slot exists.</returns>
|
||||
/// <exception cref="ArgumentException">Thrown when the given station is not a station.</exception>
|
||||
/// <remarks>slots will be null if the slot doesn't exist, as well, so make sure to check the return value.</remarks>
|
||||
public bool TryGetJobSlot(EntityUid station, string jobPrototypeId, out uint? slots, StationJobsComponent? stationJobs = null)
|
||||
public bool TryGetJobSlot(EntityUid station, string jobPrototypeId, out int? slots, StationJobsComponent? stationJobs = null)
|
||||
{
|
||||
if (!Resolve(station, ref stationJobs))
|
||||
throw new ArgumentException("Tried to use a non-station entity as a station!", nameof(station));
|
||||
|
||||
if (stationJobs.JobList.TryGetValue(jobPrototypeId, out var job))
|
||||
{
|
||||
slots = job;
|
||||
return true;
|
||||
}
|
||||
else // Else if slot isn't present return null.
|
||||
{
|
||||
slots = null;
|
||||
return false;
|
||||
}
|
||||
return stationJobs.JobList.TryGetValue(jobPrototypeId, out slots);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -367,12 +354,14 @@ public sealed partial class StationJobsSystem : EntitySystem
|
||||
/// <param name="stationJobs">Resolve pattern, station jobs component of the station.</param>
|
||||
/// <returns>Set containing all jobs available.</returns>
|
||||
/// <exception cref="ArgumentException">Thrown when the given station is not a station.</exception>
|
||||
public IReadOnlySet<string> GetAvailableJobs(EntityUid station, StationJobsComponent? stationJobs = null)
|
||||
public IEnumerable<ProtoId<JobPrototype>> GetAvailableJobs(EntityUid station, StationJobsComponent? stationJobs = null)
|
||||
{
|
||||
if (!Resolve(station, ref stationJobs))
|
||||
throw new ArgumentException("Tried to use a non-station entity as a station!", nameof(station));
|
||||
|
||||
return stationJobs.JobList.Where(x => x.Value != 0).Select(x => x.Key).ToHashSet();
|
||||
return stationJobs.JobList
|
||||
.Where(x => x.Value != 0)
|
||||
.Select(x => x.Key);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -382,12 +371,12 @@ public sealed partial class StationJobsSystem : EntitySystem
|
||||
/// <param name="stationJobs">Resolve pattern, station jobs component of the station.</param>
|
||||
/// <returns>Set containing all overflow jobs available.</returns>
|
||||
/// <exception cref="ArgumentException">Thrown when the given station is not a station.</exception>
|
||||
public IReadOnlySet<string> GetOverflowJobs(EntityUid station, StationJobsComponent? stationJobs = null)
|
||||
public IReadOnlySet<ProtoId<JobPrototype>> GetOverflowJobs(EntityUid station, StationJobsComponent? stationJobs = null)
|
||||
{
|
||||
if (!Resolve(station, ref stationJobs))
|
||||
throw new ArgumentException("Tried to use a non-station entity as a station!", nameof(station));
|
||||
|
||||
return stationJobs.OverflowJobs.ToHashSet();
|
||||
return stationJobs.OverflowJobs;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -397,7 +386,7 @@ public sealed partial class StationJobsSystem : EntitySystem
|
||||
/// <param name="stationJobs">Resolve pattern, station jobs component of the station.</param>
|
||||
/// <returns>List of all jobs on the station.</returns>
|
||||
/// <exception cref="ArgumentException">Thrown when the given station is not a station.</exception>
|
||||
public IReadOnlyDictionary<string, uint?> GetJobs(EntityUid station, StationJobsComponent? stationJobs = null)
|
||||
public IReadOnlyDictionary<ProtoId<JobPrototype>, int?> GetJobs(EntityUid station, StationJobsComponent? stationJobs = null)
|
||||
{
|
||||
if (!Resolve(station, ref stationJobs))
|
||||
throw new ArgumentException("Tried to use a non-station entity as a station!", nameof(station));
|
||||
@@ -412,12 +401,14 @@ public sealed partial class StationJobsSystem : EntitySystem
|
||||
/// <param name="stationJobs">Resolve pattern, station jobs component of the station.</param>
|
||||
/// <returns>List of all round-start jobs.</returns>
|
||||
/// <exception cref="ArgumentException">Thrown when the given station is not a station.</exception>
|
||||
public IReadOnlyDictionary<string, uint?> GetRoundStartJobs(EntityUid station, StationJobsComponent? stationJobs = null)
|
||||
public Dictionary<ProtoId<JobPrototype>, int?> GetRoundStartJobs(EntityUid station, StationJobsComponent? stationJobs = null)
|
||||
{
|
||||
if (!Resolve(station, ref stationJobs))
|
||||
throw new ArgumentException("Tried to use a non-station entity as a station!", nameof(station));
|
||||
|
||||
return stationJobs.RoundStartJobList;
|
||||
return stationJobs.SetupAvailableJobs.ToDictionary(
|
||||
x => x.Key,
|
||||
x=> (int?)(x.Value[0] < 0 ? null : x.Value[0]));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -428,13 +419,13 @@ public sealed partial class StationJobsSystem : EntitySystem
|
||||
/// <param name="pickOverflows">Whether or not to pick from the overflow list.</param>
|
||||
/// <param name="disallowedJobs">A set of disallowed jobs, if any.</param>
|
||||
/// <returns>The selected job, if any.</returns>
|
||||
public string? PickBestAvailableJobWithPriority(EntityUid station, IReadOnlyDictionary<string, JobPriority> jobPriorities, bool pickOverflows, IReadOnlySet<ProtoId<JobPrototype>>? disallowedJobs = null)
|
||||
public ProtoId<JobPrototype>? PickBestAvailableJobWithPriority(EntityUid station, IReadOnlyDictionary<ProtoId<JobPrototype>, JobPriority> jobPriorities, bool pickOverflows, IReadOnlySet<ProtoId<JobPrototype>>? disallowedJobs = null)
|
||||
{
|
||||
if (station == EntityUid.Invalid)
|
||||
return null;
|
||||
|
||||
var available = GetAvailableJobs(station);
|
||||
bool TryPick(JobPriority priority, [NotNullWhen(true)] out string? jobId)
|
||||
bool TryPick(JobPriority priority, [NotNullWhen(true)] out ProtoId<JobPrototype>? jobId)
|
||||
{
|
||||
var filtered = jobPriorities
|
||||
.Where(p =>
|
||||
@@ -474,7 +465,10 @@ public sealed partial class StationJobsSystem : EntitySystem
|
||||
return null;
|
||||
|
||||
var overflows = GetOverflowJobs(station);
|
||||
return overflows.Count != 0 ? _random.Pick(overflows) : null;
|
||||
if (overflows.Count == 0)
|
||||
return null;
|
||||
|
||||
return _random.Pick(overflows);
|
||||
}
|
||||
|
||||
#endregion Public API
|
||||
@@ -483,7 +477,7 @@ public sealed partial class StationJobsSystem : EntitySystem
|
||||
|
||||
private bool _availableJobsDirty;
|
||||
|
||||
private TickerJobsAvailableEvent _cachedAvailableJobs = new (new Dictionary<NetEntity, string>(), new Dictionary<NetEntity, Dictionary<string, uint?>>());
|
||||
private TickerJobsAvailableEvent _cachedAvailableJobs = new(new(), new());
|
||||
|
||||
/// <summary>
|
||||
/// Assembles an event from the current available-to-play jobs.
|
||||
@@ -494,9 +488,9 @@ public sealed partial class StationJobsSystem : EntitySystem
|
||||
{
|
||||
// If late join is disallowed, return no available jobs.
|
||||
if (_gameTicker.DisallowLateJoin)
|
||||
return new TickerJobsAvailableEvent(new Dictionary<NetEntity, string>(), new Dictionary<NetEntity, Dictionary<string, uint?>>());
|
||||
return new TickerJobsAvailableEvent(new(), new());
|
||||
|
||||
var jobs = new Dictionary<NetEntity, Dictionary<string, uint?>>();
|
||||
var jobs = new Dictionary<NetEntity, Dictionary<ProtoId<JobPrototype>, int?>>();
|
||||
var stationNames = new Dictionary<NetEntity, string>();
|
||||
|
||||
var query = EntityQueryEnumerator<StationJobsComponent>();
|
||||
|
||||
Reference in New Issue
Block a user