Predict Mind Roles (#39611)

This commit is contained in:
slarticodefast
2025-08-21 03:10:07 +02:00
committed by GitHub
parent b124d0def5
commit 9c546a0072
8 changed files with 53 additions and 63 deletions

View File

@@ -19,11 +19,13 @@ public sealed class ParadoxCloneRoleSystem : EntitySystem
private void OnRefreshNameModifiers(Entity<ParadoxCloneRoleComponent> ent, ref MindRelayedEvent<RefreshNameModifiersEvent> args) 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; return;
// only show for ghosts // only show for ghosts
if (!HasComp<GhostComponent>(roleComp.Mind.Comp.OwnedEntity)) if (!HasComp<GhostComponent>(mindComp.OwnedEntity))
return; return;
if (ent.Comp.NameModifier != null) if (ent.Comp.NameModifier != null)

View File

@@ -36,7 +36,7 @@ public sealed class RoleSystem : SharedRoleSystem
// Briefing is no longer raised on the mind entity itself // Briefing is no longer raised on the mind entity itself
// because all the components that briefings subscribe to should be on Mind Role Entities // 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); RaiseLocalEvent(role, ref ev);
} }

View File

@@ -20,7 +20,7 @@ public sealed partial class JobCondition : EntityEffectCondition
|| !args.EntityManager.TryGetComponent<MindComponent>(mindContainer.Mind, out var mind)) || !args.EntityManager.TryGetComponent<MindComponent>(mindContainer.Mind, out var mind))
return false; 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; continue;

View File

@@ -1,8 +1,7 @@
using Content.Shared.GameTicking;
using Content.Shared.Mind.Components; using Content.Shared.Mind.Components;
using Robust.Shared.Containers;
using Robust.Shared.GameStates; using Robust.Shared.GameStates;
using Robust.Shared.Network; using Robust.Shared.Network;
using Robust.Shared.Player;
using Robust.Shared.Prototypes; using Robust.Shared.Prototypes;
namespace Content.Shared.Mind; namespace Content.Shared.Mind;
@@ -100,10 +99,16 @@ public sealed partial class MindComponent : Component
public bool PreventSuicide { get; set; } public bool PreventSuicide { get; set; }
/// <summary> /// <summary>
/// Mind Role Entities belonging to this Mind /// Mind Role Entities belonging to this Mind are stored in this container.
/// </summary> /// </summary>
[DataField, AutoNetworkedField] [ViewVariables]
public List<EntityUid> MindRoles = new List<EntityUid>(); public Container MindRoleContainer = default!;
/// <summary>
/// The id for the MindRoleContainer.
/// </summary>
[ViewVariables]
public const string MindRoleContainerId = "mind_roles";
/// <summary> /// <summary>
/// The mind's current antagonist/special role, or lack thereof; /// The mind's current antagonist/special role, or lack thereof;

View File

@@ -23,7 +23,7 @@ public abstract partial class SharedMindSystem : EntitySystem
{ {
RaiseLocalEvent(mindId, ref ev); RaiseLocalEvent(mindId, ref ev);
foreach (var role in mindComp.MindRoles) foreach (var role in mindComp.MindRoleContainer.ContainedEntities)
RaiseLocalEvent(role, ref ev); RaiseLocalEvent(role, ref ev);
} }
} }
@@ -36,7 +36,7 @@ public abstract partial class SharedMindSystem : EntitySystem
{ {
RaiseLocalEvent(mindId, ref ev); RaiseLocalEvent(mindId, ref ev);
foreach (var role in mindComp.MindRoles) foreach (var role in mindComp.MindRoleContainer.ContainedEntities)
RaiseLocalEvent(role, ref ev); RaiseLocalEvent(role, ref ev);
} }

View File

@@ -15,8 +15,8 @@ using Content.Shared.Mobs.Systems;
using Content.Shared.Objectives.Systems; using Content.Shared.Objectives.Systems;
using Content.Shared.Players; using Content.Shared.Players;
using Content.Shared.Speech; using Content.Shared.Speech;
using Content.Shared.Whitelist; using Content.Shared.Whitelist;
using Robust.Shared.Containers;
using Robust.Shared.Map; using Robust.Shared.Map;
using Robust.Shared.Network; using Robust.Shared.Network;
using Robust.Shared.Player; using Robust.Shared.Player;
@@ -36,6 +36,7 @@ public abstract partial class SharedMindSystem : EntitySystem
[Dependency] private readonly ISharedPlayerManager _playerManager = default!; [Dependency] private readonly ISharedPlayerManager _playerManager = default!;
[Dependency] private readonly MetaDataSystem _metadata = default!; [Dependency] private readonly MetaDataSystem _metadata = default!;
[Dependency] private readonly EntityWhitelistSystem _whitelist = default!; [Dependency] private readonly EntityWhitelistSystem _whitelist = default!;
[Dependency] private readonly SharedContainerSystem _container = default!;
[ViewVariables] [ViewVariables]
protected readonly Dictionary<NetUserId, EntityUid> UserMinds = new(); 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) private void OnMindStartup(EntityUid uid, MindComponent component, ComponentStartup args)
{ {
component.MindRoleContainer = _container.EnsureContainer<Container>(uid, MindComponent.MindRoleContainerId);
if (component.UserId == null) if (component.UserId == null)
return; return;

View File

@@ -35,14 +35,6 @@ public sealed partial class MindRoleComponent : BaseMindRoleComponent
[DataField] [DataField]
public bool ExclusiveAntag; 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> /// <summary>
/// The Antagonist prototype of this role. /// The Antagonist prototype of this role.
/// </summary> /// </summary>

View File

@@ -10,7 +10,6 @@ using Content.Shared.Whitelist;
using Robust.Shared.Audio; using Robust.Shared.Audio;
using Robust.Shared.Audio.Systems; using Robust.Shared.Audio.Systems;
using Robust.Shared.Configuration; using Robust.Shared.Configuration;
using Robust.Shared.Map;
using Robust.Shared.Player; using Robust.Shared.Player;
using Robust.Shared.Prototypes; using Robust.Shared.Prototypes;
using Robust.Shared.Serialization; using Robust.Shared.Serialization;
@@ -35,7 +34,6 @@ public abstract class SharedRoleSystem : EntitySystem
{ {
Subs.CVar(_cfg, CCVars.GameRoleTimerOverride, SetRequirementOverride, true); Subs.CVar(_cfg, CCVars.GameRoleTimerOverride, SetRequirementOverride, true);
SubscribeLocalEvent<MindRoleComponent, ComponentShutdown>(OnComponentShutdown);
SubscribeLocalEvent<StartingMindRoleComponent, PlayerSpawnCompleteEvent>(OnSpawn); SubscribeLocalEvent<StartingMindRoleComponent, PlayerSpawnCompleteEvent>(OnSpawn);
} }
@@ -152,22 +150,23 @@ public abstract class SharedRoleSystem : EntitySystem
//If that was somehow to occur, a second mindrole for that comp would be created //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 //Meaning any mind role checks could return wrong results, since they just return the first match they find
var mindRoleId = Spawn(protoId, MapCoordinates.Nullspace); if (!PredictedTrySpawnInContainer(protoId, mindId, MindComponent.MindRoleContainerId, out var mindRoleId))
EnsureComp<MindRoleComponent>(mindRoleId); {
var mindRoleComp = Comp<MindRoleComponent>(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) if (jobPrototype is not null)
{ {
mindRoleComp.JobPrototype = jobPrototype; mindRoleComp.JobPrototype = jobPrototype;
EnsureComp<JobRoleComponent>(mindRoleId); EnsureComp<JobRoleComponent>(mindRoleId.Value);
DebugTools.AssertNull(mindRoleComp.AntagPrototype); DebugTools.AssertNull(mindRoleComp.AntagPrototype);
DebugTools.Assert(!mindRoleComp.Antag); DebugTools.Assert(!mindRoleComp.Antag);
DebugTools.Assert(!mindRoleComp.ExclusiveAntag); DebugTools.Assert(!mindRoleComp.ExclusiveAntag);
} }
mind.MindRoles.Add(mindRoleId);
var update = MindRolesUpdate((mindId, mind)); var update = MindRolesUpdate((mindId, mind));
// RoleType refresh, Role time tracking, Update Admin playerlist // RoleType refresh, Role time tracking, Update Admin playerlist
@@ -230,7 +229,7 @@ public abstract class SharedRoleSystem : EntitySystem
{ {
var roles = new List<Entity<MindRoleComponent>>(); var roles = new List<Entity<MindRoleComponent>>();
foreach (var role in mind.MindRoles) foreach (var role in mind.MindRoleContainer.ContainedEntities)
{ {
var comp = Comp<MindRoleComponent>(role); var comp = Comp<MindRoleComponent>(role);
if (comp.RoleType is not null) if (comp.RoleType is not null)
@@ -301,7 +300,7 @@ public abstract class SharedRoleSystem : EntitySystem
var original = "'" + typeof(T).Name + "'"; var original = "'" + typeof(T).Name + "'";
var deleteName = original; var deleteName = original;
foreach (var role in mind.Comp.MindRoles) foreach (var role in mind.Comp.MindRoleContainer.ContainedEntities)
{ {
if (!HasComp<MindRoleComponent>(role)) if (!HasComp<MindRoleComponent>(role))
{ {
@@ -366,7 +365,7 @@ public abstract class SharedRoleSystem : EntitySystem
var original = "'" + protoId + "'"; var original = "'" + protoId + "'";
var deleteName = original; var deleteName = original;
var delete = new List<EntityUid>(); var delete = new List<EntityUid>();
foreach (var role in mind.Comp.MindRoles) foreach (var role in mind.Comp.MindRoleContainer.ContainedEntities)
{ {
if (!HasComp<MindRoleComponent>(role)) if (!HasComp<MindRoleComponent>(role))
{ {
@@ -416,17 +415,6 @@ public abstract class SharedRoleSystem : EntitySystem
return true; 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> /// <summary>
/// Finds the first mind role of a specific T type on a mind entity. /// 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 /// 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)) if (!Resolve(mind.Owner, ref mind.Comp))
return false; return false;
foreach (var roleEnt in mind.Comp.MindRoles) foreach (var roleEnt in mind.Comp.MindRoleContainer.ContainedEntities)
{ {
if (!TryComp(roleEnt, out T? tcomp)) if (!TryComp(roleEnt, out T? tcomp))
continue; continue;
@@ -487,7 +475,7 @@ public abstract class SharedRoleSystem : EntitySystem
var found = false; var found = false;
foreach (var roleEnt in mind.MindRoles) foreach (var roleEnt in mind.MindRoleContainer.ContainedEntities)
{ {
if (!HasComp(roleEnt, type)) if (!HasComp(roleEnt, type))
continue; continue;
@@ -511,7 +499,7 @@ public abstract class SharedRoleSystem : EntitySystem
/// </summary> /// </summary>
public bool MindHasRole(Entity<MindComponent> mind, EntityWhitelist whitelist) 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)) if (_whitelist.IsWhitelistPass(whitelist, roleEnt))
return true; return true;
@@ -544,7 +532,7 @@ public abstract class SharedRoleSystem : EntitySystem
var mind = Comp<MindComponent>(mindId); 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)) if (HasComp<T>(uid) && TryComp<MindRoleComponent>(uid, out var comp))
result = (uid, comp); result = (uid, comp);
@@ -564,7 +552,7 @@ public abstract class SharedRoleSystem : EntitySystem
if (!Resolve(mind.Owner, ref mind.Comp)) if (!Resolve(mind.Owner, ref mind.Comp))
return roleInfo; return roleInfo;
foreach (var role in mind.Comp.MindRoles) foreach (var role in mind.Comp.MindRoleContainer.ContainedEntities)
{ {
var valid = false; var valid = false;
var name = "game-ticker-unknown-role"; var name = "game-ticker-unknown-role";
@@ -651,7 +639,7 @@ public abstract class SharedRoleSystem : EntitySystem
var antagonist = false; var antagonist = false;
var exclusiveAntag = 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)) if (!TryComp<MindRoleComponent>(role, out var roleComp))
{ {