diff --git a/Content.Server/GameTicking/Rules/RevolutionaryRuleSystem.cs b/Content.Server/GameTicking/Rules/RevolutionaryRuleSystem.cs index 311e78d009..e6485a723f 100644 --- a/Content.Server/GameTicking/Rules/RevolutionaryRuleSystem.cs +++ b/Content.Server/GameTicking/Rules/RevolutionaryRuleSystem.cs @@ -234,7 +234,7 @@ public sealed class RevolutionaryRuleSystem : GameRuleSystem(mindId); + _role.MindRemoveRole(mindId); // make it very obvious to the rev they've been deconverted since // they may not see the popup due to antag and/or new player tunnel vision diff --git a/Content.Server/Mindshield/MindShieldSystem.cs b/Content.Server/Mindshield/MindShieldSystem.cs index 89ae090acd..7cc1e8fc75 100644 --- a/Content.Server/Mindshield/MindShieldSystem.cs +++ b/Content.Server/Mindshield/MindShieldSystem.cs @@ -51,7 +51,7 @@ public sealed class MindShieldSystem : EntitySystem } if (_mindSystem.TryGetMind(implanted, out var mindId, out _) && - _roleSystem.MindTryRemoveRole(mindId)) + _roleSystem.MindRemoveRole(mindId)) { _adminLogManager.Add(LogType.Mind, LogImpact.Medium, $"{ToPrettyString(implanted)} was deconverted due to being implanted with a Mindshield."); } diff --git a/Content.Server/Roles/RemoveRoleCommand.cs b/Content.Server/Roles/RemoveRoleCommand.cs index fd4bb09317..c6e11cee22 100644 --- a/Content.Server/Roles/RemoveRoleCommand.cs +++ b/Content.Server/Roles/RemoveRoleCommand.cs @@ -45,7 +45,7 @@ namespace Content.Server.Roles var roles = _entityManager.System(); var jobs = _entityManager.System(); if (jobs.MindHasJobWithId(mind, args[1])) - roles.MindTryRemoveRole(mind.Value); + roles.MindRemoveRole(mind.Value); } } } diff --git a/Content.Server/Silicons/Laws/SiliconLawSystem.cs b/Content.Server/Silicons/Laws/SiliconLawSystem.cs index 33eef8bc56..8dfc8d51f8 100644 --- a/Content.Server/Silicons/Laws/SiliconLawSystem.cs +++ b/Content.Server/Silicons/Laws/SiliconLawSystem.cs @@ -185,7 +185,7 @@ public sealed class SiliconLawSystem : SharedSiliconLawSystem base.RemoveSubvertedSiliconRole(mindId); if (_roles.MindHasRole(mindId)) - _roles.MindTryRemoveRole(mindId); + _roles.MindRemoveRole(mindId); } public SiliconLawset GetLaws(EntityUid uid, SiliconLawBoundComponent? component = null) diff --git a/Content.Server/Zombies/ZombieSystem.cs b/Content.Server/Zombies/ZombieSystem.cs index 8f8dd36ad4..d263df9ce5 100644 --- a/Content.Server/Zombies/ZombieSystem.cs +++ b/Content.Server/Zombies/ZombieSystem.cs @@ -322,7 +322,7 @@ namespace Content.Server.Zombies // Remove the role when getting cloned, getting gibbed and borged, or leaving the body via any other method. private void OnMindRemoved(Entity ent, ref MindRemovedMessage args) { - _role.MindTryRemoveRole(args.Mind); + _role.MindRemoveRole((args.Mind.Owner, args.Mind.Comp)); } } } diff --git a/Content.Shared/Roles/SharedRoleSystem.cs b/Content.Shared/Roles/SharedRoleSystem.cs index 0407251414..e45c5792bd 100644 --- a/Content.Shared/Roles/SharedRoleSystem.cs +++ b/Content.Shared/Roles/SharedRoleSystem.cs @@ -281,11 +281,11 @@ public abstract class SharedRoleSystem : EntitySystem } /// - /// Removes all instances of a specific role from this mind. + /// Finds and removes all mind roles of a specific type /// /// The mind to remove the role from. /// The type of the role to remove. - /// Returns false if the role did not exist. True if successful> + /// True if the role existed and was removed> public bool MindRemoveRole(Entity mind) where T : IComponent { if (typeof(T) == typeof(MindRoleComponent)) @@ -294,25 +294,108 @@ public abstract class SharedRoleSystem : EntitySystem if (!Resolve(mind.Owner, ref mind.Comp)) return false; - var found = false; var delete = new List(); + // If there were no matches and thus no mind role entity names, we'll need the component's name, to report what role failed to be removed + var original = "'" + typeof(T).Name + "'"; + var deleteName = original; + foreach (var role in mind.Comp.MindRoles) { - if (!HasComp(role)) - continue; - if (!HasComp(role)) { Log.Error($"Encountered mind role entity {ToPrettyString(role)} without a {nameof(MindRoleComponent)}"); continue; } + if (!HasComp(role)) + continue; + delete.Add(role); - found = true; + deleteName = RemoveRoleLogNameGeneration(deleteName, MetaData(role).EntityName, original); } - if (!found) + return MindRemoveRoleDo(mind, delete, deleteName); + } + + private string RemoveRoleLogNameGeneration(string name, string newName, string original) + { + // If there were matches for deletion, this will run, and we get a new name to replace the original input + if (name == original) + name = "'" + newName + "'"; + // It is theoretically possible to get multiple matches + // If they have different names, then we want all of them listed + else if (!name.Contains(newName)) + // and we can't just drop the multiple names within a single ' ' section later, because that would + // make it look like it's one name that is just formatted to look like a list + name = name + ", " + "'" + newName + "'"; + + return name; + } + + /// + /// Finds and removes all mind roles of a specific type + /// + /// The mind entity + /// The type of the role to remove. + /// True if the role existed and was removed + public bool MindRemoveRole(EntityUid mindId) where T : IComponent + { + if (!TryComp(mindId, out var mind)) + { + Log.Error($"The specified mind entity '{ToPrettyString(mindId)}' does not have a {nameof(MindComponent)}"); return false; + } + + return MindRemoveRole((mindId, mind)); + } + + /// + /// Finds and removes all mind roles of a specific type + /// + /// The mind entity and component + /// /// The prototype ID of the mind role to be removed + /// True if the role existed and was removed + public bool MindRemoveRole(Entity mind, EntProtoId protoId) + { + if ( !Resolve(mind.Owner, ref mind.Comp)) + return false; + + // If there were no matches and thus no mind role entity names, we'll need the protoId, to report what role failed to be removed + var original = "'" + protoId + "'"; + var deleteName = original; + var delete = new List(); + foreach (var role in mind.Comp.MindRoles) + { + if (!HasComp(role)) + { + Log.Error($"Encountered mind role entity {ToPrettyString(role)} without a {nameof(MindRoleComponent)}"); + continue; + } + + var id = MetaData(role).EntityPrototype?.ID; + if (id is null || id != protoId) + continue; + + delete.Add(role); + deleteName = RemoveRoleLogNameGeneration(deleteName, MetaData(role).EntityName, original); + } + + return MindRemoveRoleDo(mind, delete, deleteName); + } + + /// + /// Performs the actual role entity deletion. + /// + private bool MindRemoveRoleDo(Entity mind, List delete, string? logName = "") + { + if ( !Resolve(mind.Owner, ref mind.Comp)) + return false; + + if (delete.Count <= 0) + { + Log.Warning($"Failed to remove mind role {logName} from {ToPrettyString(mind.Owner)} : mind does not have this role "); + return false; + } foreach (var role in delete) { @@ -326,7 +409,7 @@ public abstract class SharedRoleSystem : EntitySystem _adminLogger.Add(LogType.Mind, LogImpact.Low, - $"All roles of type '{typeof(T).Name}' removed from mind of {ToPrettyString(mind.Comp.OwnedEntity)}"); + $"All roles of type {logName} removed from mind of {ToPrettyString(mind.Comp.OwnedEntity)}"); return true; } @@ -342,24 +425,6 @@ public abstract class SharedRoleSystem : EntitySystem ent.Comp.Mind.Comp.MindRoles.Remove(ent.Owner); } - /// - /// Finds and removes all mind roles of a specific type - /// - /// The mind entity - /// The type of the role to remove. - /// True if the role existed and was removed - public bool MindTryRemoveRole(EntityUid mindId) where T : IComponent - { - if (typeof(T) == typeof(MindRoleComponent)) - return false; - - if (MindRemoveRole(mindId)) - return true; - - Log.Warning($"Failed to remove role {typeof(T)} from {ToPrettyString(mindId)} : mind does not have role "); - return false; - } - /// /// Finds the first mind role of a specific T type on a mind entity. /// Outputs entity components for the mind role's MindRoleComponent and for T