From 4e0018697fbc358e6c0bb3243e67f05b126e5f9e Mon Sep 17 00:00:00 2001
From: Leon Friedrich <60421075+ElectroJr@users.noreply.github.com>
Date: Mon, 14 Oct 2024 16:05:25 +1300
Subject: [PATCH] Add role prototype validation tests (#32801)
* Add role prototype validation test
* Rejig GetPrototypesWithComponent
* More tests n stuff
---
.../Pair/TestPair.Helpers.cs | 32 ++-
.../Tests/Minds/RoleTests.cs | 95 +++++++++
.../Tests/Sprite/ItemSpriteTest.cs | 2 +-
Content.IntegrationTests/Tests/StorageTest.cs | 7 +-
.../EffectConditions/JobCondition.cs | 12 +-
.../Rules/RevolutionaryRuleSystem.cs | 4 +-
Content.Server/Ghost/Roles/GhostRoleSystem.cs | 4 +-
Content.Shared/Roles/Jobs/SharedJobSystem.cs | 11 +-
Content.Shared/Roles/SharedRoleSystem.cs | 193 +++++++++---------
9 files changed, 238 insertions(+), 122 deletions(-)
create mode 100644 Content.IntegrationTests/Tests/Minds/RoleTests.cs
diff --git a/Content.IntegrationTests/Pair/TestPair.Helpers.cs b/Content.IntegrationTests/Pair/TestPair.Helpers.cs
index 4604cd82966..1b4825cc9c7 100644
--- a/Content.IntegrationTests/Pair/TestPair.Helpers.cs
+++ b/Content.IntegrationTests/Pair/TestPair.Helpers.cs
@@ -107,13 +107,41 @@ public async Task WaitClientCommand(string cmd, int numTicks = 10)
///
/// Retrieve all entity prototypes that have some component.
///
- public List GetPrototypesWithComponent(
+ public List<(EntityPrototype, T)> GetPrototypesWithComponent(
HashSet? ignored = null,
bool ignoreAbstract = true,
bool ignoreTestPrototypes = true)
where T : IComponent
{
var id = Server.ResolveDependency().GetComponentName(typeof(T));
+ var list = new List<(EntityPrototype, T)>();
+ foreach (var proto in Server.ProtoMan.EnumeratePrototypes())
+ {
+ if (ignored != null && ignored.Contains(proto.ID))
+ continue;
+
+ if (ignoreAbstract && proto.Abstract)
+ continue;
+
+ if (ignoreTestPrototypes && IsTestPrototype(proto))
+ continue;
+
+ if (proto.Components.TryGetComponent(id, out var cmp))
+ list.Add((proto, (T)cmp));
+ }
+
+ return list;
+ }
+
+ ///
+ /// Retrieve all entity prototypes that have some component.
+ ///
+ public List GetPrototypesWithComponent(Type type,
+ HashSet? ignored = null,
+ bool ignoreAbstract = true,
+ bool ignoreTestPrototypes = true)
+ {
+ var id = Server.ResolveDependency().GetComponentName(type);
var list = new List();
foreach (var proto in Server.ProtoMan.EnumeratePrototypes())
{
@@ -127,7 +155,7 @@ public List GetPrototypesWithComponent(
continue;
if (proto.Components.ContainsKey(id))
- list.Add(proto);
+ list.Add((proto));
}
return list;
diff --git a/Content.IntegrationTests/Tests/Minds/RoleTests.cs b/Content.IntegrationTests/Tests/Minds/RoleTests.cs
new file mode 100644
index 00000000000..fcfe1236cfc
--- /dev/null
+++ b/Content.IntegrationTests/Tests/Minds/RoleTests.cs
@@ -0,0 +1,95 @@
+using System.Linq;
+using Content.Server.Roles;
+using Content.Shared.Roles;
+using Content.Shared.Roles.Jobs;
+using Robust.Shared.GameObjects;
+using Robust.Shared.Reflection;
+
+namespace Content.IntegrationTests.Tests.Minds;
+
+[TestFixture]
+public sealed class RoleTests
+{
+ ///
+ /// Check that any prototype with a is properly configured
+ ///
+ [Test]
+ public async Task ValidateRolePrototypes()
+ {
+ await using var pair = await PoolManager.GetServerClient();
+
+ var jobComp = pair.Server.ResolveDependency().GetComponentName(typeof(JobRoleComponent));
+
+ Assert.Multiple(() =>
+ {
+ foreach (var (proto, comp) in pair.GetPrototypesWithComponent())
+ {
+ Assert.That(comp.AntagPrototype == null || comp.JobPrototype == null, $"Role {proto.ID} has both a job and antag prototype.");
+ Assert.That(!comp.ExclusiveAntag || comp.Antag, $"Role {proto.ID} is marked as an exclusive antag, despite not being an antag.");
+ Assert.That(comp.Antag || comp.AntagPrototype == null, $"Role {proto.ID} has an antag prototype, despite not being an antag.");
+
+ if (comp.JobPrototype != null)
+ Assert.That(proto.Components.ContainsKey(jobComp), $"Role {proto.ID} is a job, despite not having a job prototype.");
+
+ // It is possible that this is meant to be supported? Though I would assume that it would be for
+ // admin / prototype uploads, and that pre-defined roles should still check this.
+ Assert.That(!comp.Antag || comp.AntagPrototype != null , $"Role {proto.ID} is an antag, despite not having a antag prototype.");
+ }
+ });
+
+ await pair.CleanReturnAsync();
+ }
+
+ ///
+ /// Check that any prototype with a also has a properly configured
+ ///
+ ///
+ [Test]
+ public async Task ValidateJobPrototypes()
+ {
+ await using var pair = await PoolManager.GetServerClient();
+
+ var mindCompId = pair.Server.ResolveDependency().GetComponentName(typeof(MindRoleComponent));
+
+ Assert.Multiple(() =>
+ {
+ foreach (var (proto, comp) in pair.GetPrototypesWithComponent())
+ {
+ if (proto.Components.TryGetComponent(mindCompId, out var mindComp))
+ Assert.That(((MindRoleComponent)mindComp).JobPrototype, Is.Not.Null);
+ }
+ });
+
+ await pair.CleanReturnAsync();
+ }
+
+ ///
+ /// Check that any prototype with a component that inherits from also has a
+ ///
+ ///
+ [Test]
+ public async Task ValidateRolesHaveMindRoleComp()
+ {
+ await using var pair = await PoolManager.GetServerClient();
+
+ var refMan = pair.Server.ResolveDependency();
+ var mindCompId = pair.Server.ResolveDependency().GetComponentName(typeof(MindRoleComponent));
+
+ var compTypes = refMan.GetAllChildren(typeof(BaseMindRoleComponent))
+ .Append(typeof(RoleBriefingComponent))
+ .Where(x => !x.IsAbstract);
+
+ Assert.Multiple(() =>
+ {
+ foreach (var comp in compTypes)
+ {
+ foreach (var proto in pair.GetPrototypesWithComponent(comp))
+ {
+ Assert.That(proto.Components.ContainsKey(mindCompId), $"Role {proto.ID} does not have a {nameof(MindRoleComponent)} despite having a {comp.Name}");
+ }
+ }
+ });
+
+ await pair.CleanReturnAsync();
+ }
+}
diff --git a/Content.IntegrationTests/Tests/Sprite/ItemSpriteTest.cs b/Content.IntegrationTests/Tests/Sprite/ItemSpriteTest.cs
index bf75188f029..da7e1e8e9b0 100644
--- a/Content.IntegrationTests/Tests/Sprite/ItemSpriteTest.cs
+++ b/Content.IntegrationTests/Tests/Sprite/ItemSpriteTest.cs
@@ -40,7 +40,7 @@ public async Task AllItemsHaveSpritesTest()
await pair.Client.WaitPost(() =>
{
- foreach (var proto in pair.GetPrototypesWithComponent(Ignored))
+ foreach (var (proto, _) in pair.GetPrototypesWithComponent(Ignored))
{
var dummy = pair.Client.EntMan.Spawn(proto.ID);
pair.Client.EntMan.RunMapInit(dummy, pair.Client.MetaData(dummy));
diff --git a/Content.IntegrationTests/Tests/StorageTest.cs b/Content.IntegrationTests/Tests/StorageTest.cs
index 2d28534347d..983ec709362 100644
--- a/Content.IntegrationTests/Tests/StorageTest.cs
+++ b/Content.IntegrationTests/Tests/StorageTest.cs
@@ -94,14 +94,13 @@ public async Task TestSufficientSpaceForFill()
await Assert.MultipleAsync(async () =>
{
- foreach (var proto in pair.GetPrototypesWithComponent())
+ foreach (var (proto, fill) in pair.GetPrototypesWithComponent())
{
if (proto.HasComponent(compFact))
continue;
StorageComponent? storage = null;
ItemComponent? item = null;
- StorageFillComponent fill = default!;
var size = 0;
await server.WaitAssertion(() =>
{
@@ -112,7 +111,6 @@ await server.WaitAssertion(() =>
}
proto.TryGetComponent("Item", out item);
- fill = (StorageFillComponent) proto.Components[id].Component;
size = GetFillSize(fill, false, protoMan, itemSys);
});
@@ -179,7 +177,7 @@ public async Task TestSufficientSpaceForEntityStorageFill()
var itemSys = entMan.System();
- foreach (var proto in pair.GetPrototypesWithComponent())
+ foreach (var (proto, fill) in pair.GetPrototypesWithComponent())
{
if (proto.HasComponent(compFact))
continue;
@@ -192,7 +190,6 @@ await server.WaitAssertion(() =>
if (entStorage == null)
return;
- var fill = (StorageFillComponent) proto.Components[id].Component;
var size = GetFillSize(fill, true, protoMan, itemSys);
Assert.That(size, Is.LessThanOrEqualTo(entStorage.Capacity),
$"{proto.ID} storage fill is too large.");
diff --git a/Content.Server/EntityEffects/EffectConditions/JobCondition.cs b/Content.Server/EntityEffects/EffectConditions/JobCondition.cs
index 9c7bda839e4..9621d6945f6 100644
--- a/Content.Server/EntityEffects/EffectConditions/JobCondition.cs
+++ b/Content.Server/EntityEffects/EffectConditions/JobCondition.cs
@@ -26,9 +26,17 @@ public override bool Condition(EntityEffectBaseArgs args)
if(!args.EntityManager.HasComponent(roleId))
continue;
- if(!args.EntityManager.TryGetComponent(roleId, out var mindRole)
- || mindRole.JobPrototype is null)
+ if (!args.EntityManager.TryGetComponent(roleId, out var mindRole))
+ {
+ Logger.Error($"Encountered job mind role entity {roleId} without a {nameof(MindRoleComponent)}");
continue;
+ }
+
+ if (mindRole.JobPrototype == null)
+ {
+ Logger.Error($"Encountered job mind role entity {roleId} without a {nameof(JobPrototype)}");
+ continue;
+ }
if (Job.Contains(mindRole.JobPrototype.Value))
return true;
diff --git a/Content.Server/GameTicking/Rules/RevolutionaryRuleSystem.cs b/Content.Server/GameTicking/Rules/RevolutionaryRuleSystem.cs
index 939ab871153..a313b78eaf1 100644
--- a/Content.Server/GameTicking/Rules/RevolutionaryRuleSystem.cs
+++ b/Content.Server/GameTicking/Rules/RevolutionaryRuleSystem.cs
@@ -155,8 +155,8 @@ private void OnPostFlash(EntityUid uid, HeadRevolutionaryComponent comp, ref Aft
if (_mind.TryGetMind(ev.User.Value, out var revMindId, out _))
{
- if (_role.MindHasRole(revMindId, out _, out var role))
- role.Value.Comp.ConvertedCount++;
+ if (_role.MindHasRole(revMindId, out var role))
+ role.Value.Comp2.ConvertedCount++;
}
}
diff --git a/Content.Server/Ghost/Roles/GhostRoleSystem.cs b/Content.Server/Ghost/Roles/GhostRoleSystem.cs
index bb95b827a7f..cd01c964ef6 100644
--- a/Content.Server/Ghost/Roles/GhostRoleSystem.cs
+++ b/Content.Server/Ghost/Roles/GhostRoleSystem.cs
@@ -516,8 +516,8 @@ public void GhostRoleInternalCreateMindAndTransfer(ICommonSession player, Entity
_roleSystem.MindAddRole(newMind, "MindRoleGhostMarker");
- if(_roleSystem.MindHasRole(newMind, out _, out var markerRole))
- markerRole.Value.Comp.Name = role.RoleName;
+ if(_roleSystem.MindHasRole(newMind!, out var markerRole))
+ markerRole.Value.Comp2.Name = role.RoleName;
_mindSystem.SetUserId(newMind, player.UserId);
_mindSystem.TransferTo(newMind, mob);
diff --git a/Content.Shared/Roles/Jobs/SharedJobSystem.cs b/Content.Shared/Roles/Jobs/SharedJobSystem.cs
index 94447a5af46..8a4733c8340 100644
--- a/Content.Shared/Roles/Jobs/SharedJobSystem.cs
+++ b/Content.Shared/Roles/Jobs/SharedJobSystem.cs
@@ -103,7 +103,6 @@ public bool TryGetPrimaryDepartment(string jobProto, [NotNullWhen(true)] out Dep
public bool MindHasJobWithId(EntityUid? mindId, string prototypeId)
{
- MindRoleComponent? comp = null;
if (mindId is null)
return false;
@@ -112,9 +111,7 @@ public bool MindHasJobWithId(EntityUid? mindId, string prototypeId)
if (role is null)
return false;
- comp = role.Value.Comp;
-
- return (comp.JobPrototype == prototypeId);
+ return role.Value.Comp1.JobPrototype == prototypeId;
}
public bool MindTryGetJob(
@@ -124,7 +121,7 @@ public bool MindTryGetJob(
prototype = null;
MindTryGetJobId(mindId, out var protoId);
- return (_prototypes.TryIndex(protoId, out prototype) || prototype is not null);
+ return _prototypes.TryIndex(protoId, out prototype) || prototype is not null;
}
public bool MindTryGetJobId(
@@ -137,9 +134,9 @@ public bool MindTryGetJobId(
return false;
if (_roles.MindHasRole(mindId.Value, out var role))
- job = role.Value.Comp.JobPrototype;
+ job = role.Value.Comp1.JobPrototype;
- return (job is not null);
+ return job is not null;
}
///
diff --git a/Content.Shared/Roles/SharedRoleSystem.cs b/Content.Shared/Roles/SharedRoleSystem.cs
index 925f61e7c75..00271693abe 100644
--- a/Content.Shared/Roles/SharedRoleSystem.cs
+++ b/Content.Shared/Roles/SharedRoleSystem.cs
@@ -10,6 +10,7 @@
using Robust.Shared.Configuration;
using Robust.Shared.Map;
using Robust.Shared.Prototypes;
+using Robust.Shared.Utility;
namespace Content.Shared.Roles;
@@ -92,19 +93,18 @@ public void MindAddJobRole(EntityUid mindId,
bool silent = false,
string? jobPrototype = null)
{
+ if (!Resolve(mindId, ref mind))
+ return;
+
// Can't have someone get paid for two jobs now, can we
- if (MindHasRole(mindId, out var jobRole)
- && jobRole.Value.Comp.JobPrototype != jobPrototype)
+ if (MindHasRole((mindId, mind), out var jobRole)
+ && jobRole.Value.Comp1.JobPrototype != jobPrototype)
{
- Resolve(mindId, ref mind);
- if (mind is not null)
- {
- _adminLogger.Add(LogType.Mind,
- LogImpact.Low,
- $"Job Role of {ToPrettyString(mind.OwnedEntity)} changed from '{jobRole.Value.Comp.JobPrototype}' to '{jobPrototype}'");
- }
+ _adminLogger.Add(LogType.Mind,
+ LogImpact.Low,
+ $"Job Role of {ToPrettyString(mind.OwnedEntity)} changed from '{jobRole.Value.Comp1.JobPrototype}' to '{jobPrototype}'");
- jobRole.Value.Comp.JobPrototype = jobPrototype;
+ jobRole.Value.Comp1.JobPrototype = jobPrototype;
}
else
MindAddRoleDo(mindId, "MindRoleJob", mind, silent, jobPrototype);
@@ -146,11 +146,12 @@ private void MindAddRoleDo(EntityUid mindId,
{
mindRoleComp.JobPrototype = jobPrototype;
EnsureComp(mindRoleId);
+ DebugTools.AssertNull(mindRoleComp.AntagPrototype);
+ DebugTools.Assert(!mindRoleComp.Antag);
+ DebugTools.Assert(!mindRoleComp.ExclusiveAntag);
}
- if (mindRoleComp.Antag || mindRoleComp.ExclusiveAntag)
- antagonist = true;
-
+ antagonist |= mindRoleComp.Antag;
mind.MindRoles.Add(mindRoleId);
var mindEv = new MindRoleAddedEvent(silent);
@@ -182,51 +183,55 @@ private void MindAddRoleDo(EntityUid mindId,
///
/// Removes all instances of a specific role from this mind.
///
- /// The mind to remove the role from.
+ /// The mind to remove the role from.
/// The type of the role to remove.
- /// Thrown if the mind does not exist or does not have this role.
- /// Returns False if there was something wrong with the mind or the removal. True if successful>
- public bool MindRemoveRole(EntityUid mindId) where T : IComponent
+ /// Returns false if the role did not exist. True if successful>
+ public bool MindRemoveRole(Entity mind) where T : IComponent
{
- if (!TryComp(mindId, out var mind) )
- throw new ArgumentException($"{mindId} does not exist or does not have mind component");
+ if (typeof(T) == typeof(MindRoleComponent))
+ throw new InvalidOperationException();
+
+ if (!Resolve(mind.Owner, ref mind.Comp))
+ return false;
var found = false;
var antagonist = false;
var delete = new List();
- foreach (var role in mind.MindRoles)
+ foreach (var role in mind.Comp.MindRoles)
{
if (!HasComp(role))
continue;
- var roleComp = Comp(role);
- antagonist = roleComp.Antag;
- _entityManager.DeleteEntity(role);
+ if (!TryComp(role, out MindRoleComponent? roleComp))
+ {
+ Log.Error($"Encountered mind role entity {ToPrettyString(role)} without a {nameof(MindRoleComponent)}");
+ continue;
+ }
+ antagonist |= roleComp.Antag | roleComp.ExclusiveAntag;
+ _entityManager.DeleteEntity(role);
delete.Add(role);
found = true;
-
}
+ if (!found)
+ return false;
+
foreach (var role in delete)
{
- mind.MindRoles.Remove(role);
+ mind.Comp.MindRoles.Remove(role);
}
- if (!found)
+ if (mind.Comp.OwnedEntity != null)
{
- throw new ArgumentException($"{mindId} does not have this role: {typeof(T)}");
+ var message = new RoleRemovedEvent(mind.Owner, mind.Comp, antagonist);
+ RaiseLocalEvent(mind.Comp.OwnedEntity.Value, message, true);
}
- var message = new RoleRemovedEvent(mindId, mind, antagonist);
-
- if (mind.OwnedEntity != null)
- {
- RaiseLocalEvent(mind.OwnedEntity.Value, message, true);
- }
_adminLogger.Add(LogType.Mind,
LogImpact.Low,
- $"'Role {typeof(T).Name}' removed from mind of {ToPrettyString(mind.OwnedEntity)}");
+ $"All roles of type '{typeof(T).Name}' removed from mind of {ToPrettyString(mind.Comp.OwnedEntity)}");
+
return true;
}
@@ -238,16 +243,14 @@ public bool MindRemoveRole(EntityUid mindId) where T : IComponent
/// True if the role existed and was removed
public bool MindTryRemoveRole(EntityUid mindId) where T : IComponent
{
- if (!MindHasRole(mindId))
- {
- Log.Warning($"Failed to remove role {typeof(T)} from {mindId} : mind does not have role ");
- return false;
- }
-
if (typeof(T) == typeof(MindRoleComponent))
return false;
- return MindRemoveRole(mindId);
+ if (MindRemoveRole(mindId))
+ return true;
+
+ Log.Warning($"Failed to remove role {typeof(T)} from {ToPrettyString(mindId)} : mind does not have role ");
+ return false;
}
///
@@ -259,30 +262,29 @@ public bool MindTryRemoveRole(EntityUid mindId) where T : IComponent
/// The Mind Role entity component
/// The Mind Role's entity component for T
/// True if the role is found
- public bool MindHasRole(EntityUid mindId,
- [NotNullWhen(true)] out Entity? role,
- [NotNullWhen(true)] out Entity? roleT) where T : IComponent
+ public bool MindHasRole(Entity mind,
+ [NotNullWhen(true)] out Entity? role) where T : IComponent
{
role = null;
- roleT = null;
-
- if (!TryComp(mindId, out var mind))
+ if (!Resolve(mind.Owner, ref mind.Comp))
return false;
- var found = false;
-
- foreach (var roleEnt in mind.MindRoles)
+ foreach (var roleEnt in mind.Comp.MindRoles)
{
- if (!HasComp(roleEnt))
+ if (!TryComp(roleEnt, out T? tcomp))
continue;
- role = (roleEnt,Comp(roleEnt));
- roleT = (roleEnt,Comp(roleEnt));
- found = true;
- break;
+ if (!TryComp(roleEnt, out MindRoleComponent? roleComp))
+ {
+ Log.Error($"Encountered mind role entity {ToPrettyString(roleEnt)} without a {nameof(MindRoleComponent)}");
+ continue;
+ }
+
+ role = (roleEnt, roleComp, tcomp);
+ return true;
}
- return found;
+ return false;
}
///
@@ -317,7 +319,13 @@ public bool MindHasRole(EntityUid mindId,
if (!HasComp(roleEnt, type))
continue;
- role = (roleEnt,Comp(roleEnt));
+ if (!TryComp(roleEnt, out MindRoleComponent? roleComp))
+ {
+ Log.Error($"Encountered mind role entity {ToPrettyString(roleEnt)} without a {nameof(MindRoleComponent)}");
+ continue;
+ }
+
+ role = (roleEnt, roleComp);
found = true;
break;
}
@@ -325,20 +333,6 @@ public bool MindHasRole(EntityUid mindId,
return found;
}
- ///
- /// Finds the first mind role of a specific type on a mind entity.
- /// Outputs an entity component for the mind role's MindRoleComponent
- ///
- /// The mind entity
- /// The Mind Role entity component
- /// The type of the role to find.
- /// True if the role is found
- public bool MindHasRole(EntityUid mindId,
- [NotNullWhen(true)] out Entity? role) where T : IComponent
- {
- return MindHasRole(mindId, out role, out _);
- }
-
///
/// Finds the first mind role of a specific type on a mind entity.
///
@@ -347,7 +341,7 @@ public bool MindHasRole(EntityUid mindId,
/// True if the role is found
public bool MindHasRole(EntityUid mindId) where T : IComponent
{
- return MindHasRole(mindId, out _, out _);
+ return MindHasRole(mindId, out _);
}
//TODO: Delete this later
@@ -374,28 +368,31 @@ public bool MindHasRole(EntityUid mindId) where T : IComponent
///
/// Reads all Roles of a mind Entity and returns their data as RoleInfo
///
- /// The mind entity
+ /// The mind entity
/// RoleInfo list
- public List MindGetAllRoleInfo(EntityUid mindId)
+ public List MindGetAllRoleInfo(Entity mind)
{
var roleInfo = new List();
- if (!TryComp(mindId, out var mind))
+ if (!Resolve(mind.Owner, ref mind.Comp))
return roleInfo;
- foreach (var role in mind.MindRoles)
+ foreach (var role in mind.Comp.MindRoles)
{
var valid = false;
var name = "game-ticker-unknown-role";
var prototype = "";
- string? playTimeTracker = null;
+ string? playTimeTracker = null;
- var comp = Comp(role);
- if (comp.AntagPrototype is not null)
+ if (!TryComp(role, out MindRoleComponent? comp))
{
- prototype = comp.AntagPrototype;
+ Log.Error($"Encountered mind role entity {ToPrettyString(role)} without a {nameof(MindRoleComponent)}");
+ continue;
}
+ if (comp.AntagPrototype is not null)
+ prototype = comp.AntagPrototype;
+
if (comp.JobPrototype is not null && comp.AntagPrototype is null)
{
prototype = comp.JobPrototype;
@@ -429,7 +426,7 @@ public List MindGetAllRoleInfo(EntityUid mindId)
}
if (valid)
- roleInfo.Add(new RoleInfo(name, comp.Antag || comp.ExclusiveAntag , playTimeTracker, prototype));
+ roleInfo.Add(new RoleInfo(name, comp.Antag, playTimeTracker, prototype));
}
return roleInfo;
}
@@ -442,12 +439,9 @@ public List MindGetAllRoleInfo(EntityUid mindId)
public bool MindIsAntagonist(EntityUid? mindId)
{
if (mindId is null)
- {
- Log.Warning($"Antagonist status of mind entity {mindId} could not be determined - mind entity not found");
return false;
- }
- return CheckAntagonistStatus(mindId.Value).Item1;
+ return CheckAntagonistStatus(mindId.Value).Antag;
}
///
@@ -458,37 +452,28 @@ public bool MindIsAntagonist(EntityUid? mindId)
public bool MindIsExclusiveAntagonist(EntityUid? mindId)
{
if (mindId is null)
- {
- Log.Warning($"Antagonist status of mind entity {mindId} could not be determined - mind entity not found");
return false;
- }
- return CheckAntagonistStatus(mindId.Value).Item2;
+ return CheckAntagonistStatus(mindId.Value).ExclusiveAntag;
}
- private (bool, bool) CheckAntagonistStatus(EntityUid mindId)
+ public (bool Antag, bool ExclusiveAntag) CheckAntagonistStatus(Entity mind)
{
- if (!TryComp(mindId, out var mind))
- {
- Log.Warning($"Antagonist status of mind entity {mindId} could not be determined - mind component not found");
+ if (!Resolve(mind.Owner, ref mind.Comp))
return (false, false);
- }
var antagonist = false;
var exclusiveAntag = false;
- foreach (var role in mind.MindRoles)
+ foreach (var role in mind.Comp.MindRoles)
{
if (!TryComp(role, out var roleComp))
{
- //If this ever shows up outside of an integration test, then we need to look into this further.
- Log.Warning($"Mind Role Entity {role} does not have MindRoleComponent!");
+ Log.Error($"Mind Role Entity {ToPrettyString(role)} does not have a MindRoleComponent, despite being listed as a role belonging to {ToPrettyString(mind)}|");
continue;
}
- if (roleComp.Antag || exclusiveAntag)
- antagonist = true;
- if (roleComp.ExclusiveAntag)
- exclusiveAntag = true;
+ antagonist |= roleComp.Antag;
+ exclusiveAntag |= roleComp.ExclusiveAntag;
}
return (antagonist, exclusiveAntag);
@@ -504,6 +489,9 @@ public void MindPlaySound(EntityUid mindId, SoundSpecifier? sound, MindComponent
_audio.PlayGlobal(sound, mind.Session);
}
+ // TODO ROLES Change to readonly.
+ // Passing around a reference to a prototype's hashset makes me uncomfortable because it might be accidentally
+ // mutated.
public HashSet? GetJobRequirement(JobPrototype job)
{
if (_requirementOverride != null && _requirementOverride.Jobs.TryGetValue(job.ID, out var req))
@@ -512,6 +500,7 @@ public void MindPlaySound(EntityUid mindId, SoundSpecifier? sound, MindComponent
return job.Requirements;
}
+ // TODO ROLES Change to readonly.
public HashSet? GetJobRequirement(ProtoId job)
{
if (_requirementOverride != null && _requirementOverride.Jobs.TryGetValue(job, out var req))
@@ -520,6 +509,7 @@ public void MindPlaySound(EntityUid mindId, SoundSpecifier? sound, MindComponent
return _prototypes.Index(job).Requirements;
}
+ // TODO ROLES Change to readonly.
public HashSet? GetAntagRequirement(ProtoId antag)
{
if (_requirementOverride != null && _requirementOverride.Antags.TryGetValue(antag, out var req))
@@ -528,6 +518,7 @@ public void MindPlaySound(EntityUid mindId, SoundSpecifier? sound, MindComponent
return _prototypes.Index(antag).Requirements;
}
+ // TODO ROLES Change to readonly.
public HashSet? GetAntagRequirement(AntagPrototype antag)
{
if (_requirementOverride != null && _requirementOverride.Antags.TryGetValue(antag.ID, out var req))