SharedJobSystem.cs 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180
  1. using System.Diagnostics.CodeAnalysis;
  2. using System.Linq;
  3. using Content.Shared.Players;
  4. using Content.Shared.Players.PlayTimeTracking;
  5. using Robust.Shared.Player;
  6. using Robust.Shared.Prototypes;
  7. using Robust.Shared.Utility;
  8. namespace Content.Shared.Roles.Jobs;
  9. /// <summary>
  10. /// Handles the job data on mind entities.
  11. /// </summary>
  12. public abstract class SharedJobSystem : EntitySystem
  13. {
  14. [Dependency] private readonly SharedPlayerSystem _playerSystem = default!;
  15. [Dependency] private readonly IPrototypeManager _prototypes = default!;
  16. [Dependency] private readonly SharedRoleSystem _roles = default!;
  17. private readonly Dictionary<string, string> _inverseTrackerLookup = new();
  18. public override void Initialize()
  19. {
  20. base.Initialize();
  21. SubscribeLocalEvent<PrototypesReloadedEventArgs>(OnProtoReload);
  22. SetupTrackerLookup();
  23. }
  24. private void OnProtoReload(PrototypesReloadedEventArgs obj)
  25. {
  26. if (obj.WasModified<JobPrototype>())
  27. SetupTrackerLookup();
  28. }
  29. private void SetupTrackerLookup()
  30. {
  31. _inverseTrackerLookup.Clear();
  32. // This breaks if you have N trackers to 1 JobId but future concern.
  33. foreach (var job in _prototypes.EnumeratePrototypes<JobPrototype>())
  34. {
  35. _inverseTrackerLookup.Add(job.PlayTimeTracker, job.ID);
  36. }
  37. }
  38. /// <summary>
  39. /// Gets the corresponding Job Prototype to a <see cref="PlayTimeTrackerPrototype"/>
  40. /// </summary>
  41. /// <param name="trackerProto"></param>
  42. /// <returns></returns>
  43. public string GetJobPrototype(string trackerProto)
  44. {
  45. DebugTools.Assert(_prototypes.HasIndex<PlayTimeTrackerPrototype>(trackerProto));
  46. return _inverseTrackerLookup[trackerProto];
  47. }
  48. /// <summary>
  49. /// Tries to get the first corresponding department for this job prototype.
  50. /// </summary>
  51. public bool TryGetDepartment(string jobProto, [NotNullWhen(true)] out DepartmentPrototype? departmentPrototype)
  52. {
  53. // Not that many departments so we can just eat the cost instead of storing the inverse lookup.
  54. var departmentProtos = _prototypes.EnumeratePrototypes<DepartmentPrototype>().ToList();
  55. departmentProtos.Sort((x, y) => string.Compare(x.ID, y.ID, StringComparison.Ordinal));
  56. foreach (var department in departmentProtos)
  57. {
  58. if (department.Roles.Contains(jobProto))
  59. {
  60. departmentPrototype = department;
  61. return true;
  62. }
  63. }
  64. departmentPrototype = null;
  65. return false;
  66. }
  67. /// <summary>
  68. /// Like <see cref="TryGetDepartment"/> but ignores any non-primary departments.
  69. /// For example, with CE it will return Engineering but with captain it will
  70. /// not return anything, since Command is not a primary department.
  71. /// </summary>
  72. public bool TryGetPrimaryDepartment(string jobProto, [NotNullWhen(true)] out DepartmentPrototype? departmentPrototype)
  73. {
  74. // not sorting it since there should only be 1 primary department for a job.
  75. // this is enforced by the job tests.
  76. var departmentProtos = _prototypes.EnumeratePrototypes<DepartmentPrototype>();
  77. foreach (var department in departmentProtos)
  78. {
  79. if (department.Primary && department.Roles.Contains(jobProto))
  80. {
  81. departmentPrototype = department;
  82. return true;
  83. }
  84. }
  85. departmentPrototype = null;
  86. return false;
  87. }
  88. public bool MindHasJobWithId(EntityUid? mindId, string prototypeId)
  89. {
  90. if (mindId is null)
  91. return false;
  92. _roles.MindHasRole<JobRoleComponent>(mindId.Value, out var role);
  93. if (role is null)
  94. return false;
  95. return role.Value.Comp1.JobPrototype == prototypeId;
  96. }
  97. public bool MindTryGetJob(
  98. [NotNullWhen(true)] EntityUid? mindId,
  99. [NotNullWhen(true)] out JobPrototype? prototype)
  100. {
  101. prototype = null;
  102. MindTryGetJobId(mindId, out var protoId);
  103. return _prototypes.TryIndex(protoId, out prototype) || prototype is not null;
  104. }
  105. public bool MindTryGetJobId(
  106. [NotNullWhen(true)] EntityUid? mindId,
  107. out ProtoId<JobPrototype>? job)
  108. {
  109. job = null;
  110. if (mindId is null)
  111. return false;
  112. if (_roles.MindHasRole<JobRoleComponent>(mindId.Value, out var role))
  113. job = role.Value.Comp1.JobPrototype;
  114. return job is not null;
  115. }
  116. /// <summary>
  117. /// Tries to get the job name for this mind.
  118. /// Returns unknown if not found.
  119. /// </summary>
  120. public bool MindTryGetJobName([NotNullWhen(true)] EntityUid? mindId, out string name)
  121. {
  122. if (MindTryGetJob(mindId, out var prototype))
  123. {
  124. name = prototype.LocalizedName;
  125. return true;
  126. }
  127. name = Loc.GetString("generic-unknown-title");
  128. return false;
  129. }
  130. /// <summary>
  131. /// Tries to get the job name for this mind.
  132. /// Returns unknown if not found.
  133. /// </summary>
  134. public string MindTryGetJobName([NotNullWhen(true)] EntityUid? mindId)
  135. {
  136. MindTryGetJobName(mindId, out var name);
  137. return name;
  138. }
  139. public bool CanBeAntag(ICommonSession player)
  140. {
  141. // If the player does not have any mind associated with them (e.g., has not spawned in or is in the lobby), then
  142. // they are eligible to be given an antag role/entity.
  143. if (_playerSystem.ContentData(player) is not { Mind: { } mindId })
  144. return true;
  145. if (!MindTryGetJob(mindId, out var prototype))
  146. return true;
  147. return prototype.CanBeAntag;
  148. }
  149. }