]> git.smokeofanarchy.ru Git - space-station-14.git/commitdiff
Predict Mind Roles (#39611)
authorslarticodefast <161409025+slarticodefast@users.noreply.github.com>
Thu, 21 Aug 2025 01:10:07 +0000 (03:10 +0200)
committerGitHub <noreply@github.com>
Thu, 21 Aug 2025 01:10:07 +0000 (03:10 +0200)
Content.Server/Roles/ParadoxCloneRoleSystem.cs
Content.Server/Roles/RoleSystem.cs
Content.Shared/EntityEffects/EffectConditions/JobCondition.cs
Content.Shared/Mind/MindComponent.cs
Content.Shared/Mind/SharedMindSystem.Relay.cs
Content.Shared/Mind/SharedMindSystem.cs
Content.Shared/Roles/Components/MindRoleComponent.cs
Content.Shared/Roles/SharedRoleSystem.cs

index c957692b703cd5e875c8debd10363ddb8729310e..85332ef4a4f453dcc0ae1db76201983f7c4aec1a 100644 (file)
@@ -19,11 +19,13 @@ public sealed class ParadoxCloneRoleSystem : EntitySystem
 
     private void OnRefreshNameModifiers(Entity<ParadoxCloneRoleComponent> ent, ref MindRelayedEvent<RefreshNameModifiersEvent> args)
     {
-        if (!TryComp<MindRoleComponent>(ent.Owner, out var roleComp))
+        var mindId = Transform(ent).ParentUid; // the mind role entity is in a container in the mind entity
+
+        if (!TryComp<MindComponent>(mindId, out var mindComp))
             return;
 
         // only show for ghosts
-        if (!HasComp<GhostComponent>(roleComp.Mind.Comp.OwnedEntity))
+        if (!HasComp<GhostComponent>(mindComp.OwnedEntity))
             return;
 
         if (ent.Comp.NameModifier != null)
index 6cbd039c7307ae056774f27fb3910428e2ca11e9..346e13bd07b0c05bd0e10f34b2d41a5f4c2f7fad 100644 (file)
@@ -36,7 +36,7 @@ public sealed class RoleSystem : SharedRoleSystem
 
         // Briefing is no longer raised on the mind entity itself
         // because all the components that briefings subscribe to should be on Mind Role Entities
-        foreach(var role in mindComp.MindRoles)
+        foreach (var role in mindComp.MindRoleContainer.ContainedEntities)
         {
             RaiseLocalEvent(role, ref ev);
         }
index 0b942a3e09a3c7b7509ed75b8bb97b7d01b5d0b2..96f3be64c6f2d2449e1ac11b4a5e987fe0b2f2ea 100644 (file)
@@ -16,13 +16,13 @@ public sealed partial class JobCondition : EntityEffectCondition
     {
         args.EntityManager.TryGetComponent<MindContainerComponent>(args.TargetEntity, out var mindContainer);
 
-        if ( mindContainer is null
-             || !args.EntityManager.TryGetComponent<MindComponent>(mindContainer.Mind, out var mind))
+        if (mindContainer is null
+            || !args.EntityManager.TryGetComponent<MindComponent>(mindContainer.Mind, out var mind))
             return false;
 
-        foreach (var roleId in mind.MindRoles)
+        foreach (var roleId in mind.MindRoleContainer.ContainedEntities)
         {
-            if(!args.EntityManager.HasComponent<JobRoleComponent>(roleId))
+            if (!args.EntityManager.HasComponent<JobRoleComponent>(roleId))
                 continue;
 
             if (!args.EntityManager.TryGetComponent<MindRoleComponent>(roleId, out var mindRole))
index 57cd628f90618f2fa4d2094f8dbc12f54a3885a4..efb8e45b9425c3c1e8fd1a316d30973a71c275d9 100644 (file)
@@ -1,8 +1,7 @@
-using Content.Shared.GameTicking;
 using Content.Shared.Mind.Components;
+using Robust.Shared.Containers;
 using Robust.Shared.GameStates;
 using Robust.Shared.Network;
-using Robust.Shared.Player;
 using Robust.Shared.Prototypes;
 
 namespace Content.Shared.Mind;
@@ -100,10 +99,16 @@ public sealed partial class MindComponent : Component
     public bool PreventSuicide { get; set; }
 
     /// <summary>
-    ///     Mind Role Entities belonging to this Mind
+    /// Mind Role Entities belonging to this Mind are stored in this container.
     /// </summary>
-    [DataField, AutoNetworkedField]
-    public List<EntityUid> MindRoles = new List<EntityUid>();
+    [ViewVariables]
+    public Container MindRoleContainer = default!;
+
+    /// <summary>
+    /// The id for the MindRoleContainer.
+    /// </summary>
+    [ViewVariables]
+    public const string MindRoleContainerId = "mind_roles";
 
     /// <summary>
     ///     The mind's current antagonist/special role, or lack thereof;
index 60ad2fc30a6fbf72da3319d5c58e32f48eb7238f..0ad18e2e08cbfd464c51d7cf3ea3b6a6d053bb3a 100644 (file)
@@ -23,7 +23,7 @@ public abstract partial class SharedMindSystem : EntitySystem
         {
             RaiseLocalEvent(mindId, ref ev);
 
-            foreach (var role in mindComp.MindRoles)
+            foreach (var role in mindComp.MindRoleContainer.ContainedEntities)
                 RaiseLocalEvent(role, ref ev);
         }
     }
@@ -36,7 +36,7 @@ public abstract partial class SharedMindSystem : EntitySystem
         {
             RaiseLocalEvent(mindId, ref ev);
 
-            foreach (var role in mindComp.MindRoles)
+            foreach (var role in mindComp.MindRoleContainer.ContainedEntities)
                 RaiseLocalEvent(role, ref ev);
         }
 
index 98ff77810ce5644e6344f3a322a9dd09c218ea78..8906e73248acb35b0f337fc576cae9506f716afd 100644 (file)
@@ -15,8 +15,8 @@ using Content.Shared.Mobs.Systems;
 using Content.Shared.Objectives.Systems;
 using Content.Shared.Players;
 using Content.Shared.Speech;
-
 using Content.Shared.Whitelist;
+using Robust.Shared.Containers;
 using Robust.Shared.Map;
 using Robust.Shared.Network;
 using Robust.Shared.Player;
@@ -36,6 +36,7 @@ public abstract partial class SharedMindSystem : EntitySystem
     [Dependency] private readonly ISharedPlayerManager _playerManager = default!;
     [Dependency] private readonly MetaDataSystem _metadata = default!;
     [Dependency] private readonly EntityWhitelistSystem _whitelist = default!;
+    [Dependency] private readonly SharedContainerSystem _container = default!;
 
     [ViewVariables]
     protected readonly Dictionary<NetUserId, EntityUid> UserMinds = new();
@@ -64,6 +65,8 @@ public abstract partial class SharedMindSystem : EntitySystem
 
     private void OnMindStartup(EntityUid uid, MindComponent component, ComponentStartup args)
     {
+        component.MindRoleContainer = _container.EnsureContainer<Container>(uid, MindComponent.MindRoleContainerId);
+
         if (component.UserId == null)
             return;
 
index 45ab8081921f7b92fb2415bf0c783804b27ee563..b85ee8f5e046d13fb54d5f0fdaa83df5ddc45bfa 100644 (file)
@@ -35,14 +35,6 @@ public sealed partial class MindRoleComponent : BaseMindRoleComponent
     [DataField]
     public bool ExclusiveAntag;
 
-    /// <summary>
-    /// The Mind that this role belongs to.
-    /// </summary>
-    /// <remarks>
-    /// TODO: Make this a datafield. Also components should not store other components.
-    /// </remarks>
-    public Entity<MindComponent> Mind;
-
     /// <summary>
     /// The Antagonist prototype of this role.
     /// </summary>
index 3269680c32d67a40fb8ef87863ddf1b564195e84..d1afae9fd1c409c5df0ae202f87f38a2376085a0 100644 (file)
@@ -10,7 +10,6 @@ using Content.Shared.Whitelist;
 using Robust.Shared.Audio;
 using Robust.Shared.Audio.Systems;
 using Robust.Shared.Configuration;
-using Robust.Shared.Map;
 using Robust.Shared.Player;
 using Robust.Shared.Prototypes;
 using Robust.Shared.Serialization;
@@ -35,7 +34,6 @@ public abstract class SharedRoleSystem : EntitySystem
     {
         Subs.CVar(_cfg, CCVars.GameRoleTimerOverride, SetRequirementOverride, true);
 
-        SubscribeLocalEvent<MindRoleComponent, ComponentShutdown>(OnComponentShutdown);
         SubscribeLocalEvent<StartingMindRoleComponent, PlayerSpawnCompleteEvent>(OnSpawn);
     }
 
@@ -55,7 +53,7 @@ public abstract class SharedRoleSystem : EntitySystem
             return;
         }
 
-        if (!_prototypes.TryIndex(value, out _requirementOverride ))
+        if (!_prototypes.TryIndex(value, out _requirementOverride))
             Log.Error($"Unknown JobRequirementOverridePrototype: {value}");
     }
 
@@ -152,22 +150,23 @@ public abstract class SharedRoleSystem : EntitySystem
         //If that was somehow to occur, a second mindrole for that comp would be created
         //Meaning any mind role checks could return wrong results, since they just return the first match they find
 
-        var mindRoleId = Spawn(protoId, MapCoordinates.Nullspace);
-        EnsureComp<MindRoleComponent>(mindRoleId);
-        var mindRoleComp = Comp<MindRoleComponent>(mindRoleId);
+        if (!PredictedTrySpawnInContainer(protoId, mindId, MindComponent.MindRoleContainerId, out var mindRoleId))
+        {
+            Log.Error($"Failed to add role {protoId} to {ToPrettyString(mindId)} : Could not spawn the role entity inside the container");
+            return;
+        }
+
+        var mindRoleComp = EnsureComp<MindRoleComponent>(mindRoleId.Value);
 
-        mindRoleComp.Mind = (mindId,mind);
         if (jobPrototype is not null)
         {
             mindRoleComp.JobPrototype = jobPrototype;
-            EnsureComp<JobRoleComponent>(mindRoleId);
+            EnsureComp<JobRoleComponent>(mindRoleId.Value);
             DebugTools.AssertNull(mindRoleComp.AntagPrototype);
             DebugTools.Assert(!mindRoleComp.Antag);
             DebugTools.Assert(!mindRoleComp.ExclusiveAntag);
         }
 
-        mind.MindRoles.Add(mindRoleId);
-
         var update = MindRolesUpdate((mindId, mind));
 
         // RoleType refresh, Role time tracking, Update Admin playerlist
@@ -201,13 +200,13 @@ public abstract class SharedRoleSystem : EntitySystem
     /// </returns>>
     private bool MindRolesUpdate(Entity<MindComponent?> ent)
     {
-        if(!Resolve(ent.Owner, ref ent.Comp))
+        if (!Resolve(ent.Owner, ref ent.Comp))
             return false;
 
         //get the most important/latest mind role
         var (roleType, subtype) = GetRoleTypeByTime(ent.Comp);
 
-        if (ent.Comp.RoleType == roleType &&  ent.Comp.Subtype == subtype)
+        if (ent.Comp.RoleType == roleType && ent.Comp.Subtype == subtype)
             return false;
 
         SetRoleType(ent.Owner, roleType, subtype);
@@ -230,7 +229,7 @@ public abstract class SharedRoleSystem : EntitySystem
     {
         var roles = new List<Entity<MindRoleComponent>>();
 
-        foreach (var role in mind.MindRoles)
+        foreach (var role in mind.MindRoleContainer.ContainedEntities)
         {
             var comp = Comp<MindRoleComponent>(role);
             if (comp.RoleType is not null)
@@ -301,7 +300,7 @@ public abstract class SharedRoleSystem : EntitySystem
         var original = "'" + typeof(T).Name + "'";
         var deleteName = original;
 
-        foreach (var role in mind.Comp.MindRoles)
+        foreach (var role in mind.Comp.MindRoleContainer.ContainedEntities)
         {
             if (!HasComp<MindRoleComponent>(role))
             {
@@ -351,7 +350,7 @@ public abstract class SharedRoleSystem : EntitySystem
         return MindRemoveRole<T>((mindId, mind));
     }
 
-        /// <summary>
+    /// <summary>
     /// Finds and removes all mind roles of a specific type
     /// </summary>
     /// <param name="mind">The mind entity and component</param>
@@ -359,14 +358,14 @@ public abstract class SharedRoleSystem : EntitySystem
     /// <returns>True if the role existed and was removed</returns>
     public bool MindRemoveRole(Entity<MindComponent?> mind, EntProtoId<MindRoleComponent> protoId)
     {
-        if ( !Resolve(mind.Owner, ref mind.Comp))
+        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<EntityUid>();
-        foreach (var role in mind.Comp.MindRoles)
+        foreach (var role in mind.Comp.MindRoleContainer.ContainedEntities)
         {
             if (!HasComp<MindRoleComponent>(role))
             {
@@ -390,7 +389,7 @@ public abstract class SharedRoleSystem : EntitySystem
     /// </summary>
     private bool MindRemoveRoleDo(Entity<MindComponent?> mind, List<EntityUid> delete, string? logName = "")
     {
-        if ( !Resolve(mind.Owner, ref mind.Comp))
+        if (!Resolve(mind.Owner, ref mind.Comp))
             return false;
 
         if (delete.Count <= 0)
@@ -416,17 +415,6 @@ public abstract class SharedRoleSystem : EntitySystem
         return true;
     }
 
-    // Removing the mind role's reference on component shutdown
-    // to make sure the reference gets removed even if the mind role entity was deleted by outside code
-    private void OnComponentShutdown(Entity<MindRoleComponent> ent, ref ComponentShutdown args)
-    {
-        //TODO: Just ensure that the tests don't spawn unassociated mind role entities
-        if (ent.Comp.Mind.Comp is null)
-            return;
-
-        ent.Comp.Mind.Comp.MindRoles.Remove(ent.Owner);
-    }
-
     /// <summary>
     /// 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
@@ -442,7 +430,7 @@ public abstract class SharedRoleSystem : EntitySystem
         if (!Resolve(mind.Owner, ref mind.Comp))
             return false;
 
-        foreach (var roleEnt in mind.Comp.MindRoles)
+        foreach (var roleEnt in mind.Comp.MindRoleContainer.ContainedEntities)
         {
             if (!TryComp(roleEnt, out T? tcomp))
                 continue;
@@ -487,7 +475,7 @@ public abstract class SharedRoleSystem : EntitySystem
 
         var found = false;
 
-        foreach (var roleEnt in mind.MindRoles)
+        foreach (var roleEnt in mind.MindRoleContainer.ContainedEntities)
         {
             if (!HasComp(roleEnt, type))
                 continue;
@@ -511,7 +499,7 @@ public abstract class SharedRoleSystem : EntitySystem
     /// </summary>
     public bool MindHasRole(Entity<MindComponent> mind, EntityWhitelist whitelist)
     {
-        foreach (var roleEnt in mind.Comp.MindRoles)
+        foreach (var roleEnt in mind.Comp.MindRoleContainer.ContainedEntities)
         {
             if (_whitelist.IsWhitelistPass(whitelist, roleEnt))
                 return true;
@@ -544,10 +532,10 @@ public abstract class SharedRoleSystem : EntitySystem
 
         var mind = Comp<MindComponent>(mindId);
 
-        foreach (var uid in mind.MindRoles)
+        foreach (var uid in mind.MindRoleContainer.ContainedEntities)
         {
             if (HasComp<T>(uid) && TryComp<MindRoleComponent>(uid, out var comp))
-                result = (uid,comp);
+                result = (uid, comp);
         }
         return result;
     }
@@ -564,7 +552,7 @@ public abstract class SharedRoleSystem : EntitySystem
         if (!Resolve(mind.Owner, ref mind.Comp))
             return roleInfo;
 
-        foreach (var role in mind.Comp.MindRoles)
+        foreach (var role in mind.Comp.MindRoleContainer.ContainedEntities)
         {
             var valid = false;
             var name = "game-ticker-unknown-role";
@@ -644,14 +632,14 @@ public abstract class SharedRoleSystem : EntitySystem
         return CheckAntagonistStatus(mindId.Value).ExclusiveAntag;
     }
 
-   private (bool Antag, bool ExclusiveAntag) CheckAntagonistStatus(Entity<MindComponent?> mind)
-   {
-       if (!Resolve(mind.Owner, ref mind.Comp))
-           return (false, false);
+    private (bool Antag, bool ExclusiveAntag) CheckAntagonistStatus(Entity<MindComponent?> mind)
+    {
+        if (!Resolve(mind.Owner, ref mind.Comp))
+            return (false, false);
 
         var antagonist = false;
         var exclusiveAntag = false;
-        foreach (var role in mind.Comp.MindRoles)
+        foreach (var role in mind.Comp.MindRoleContainer.ContainedEntities)
         {
             if (!TryComp<MindRoleComponent>(role, out var roleComp))
             {