using Content.Shared.Access.Components; using Content.Shared.Roles; using Robust.Shared.GameStates; using Robust.Shared.Prototypes; using Robust.Shared.Serialization; namespace Content.Shared.Access.Systems { public abstract class SharedAccessSystem : EntitySystem { [Dependency] private readonly IPrototypeManager _prototypeManager = default!; public override void Initialize() { base.Initialize(); SubscribeLocalEvent(OnAccessInit); SubscribeLocalEvent(OnAccessGetState); SubscribeLocalEvent(OnAccessHandleState); } private void OnAccessHandleState(EntityUid uid, AccessComponent component, ref ComponentHandleState args) { if (args.Current is not AccessComponentState state) return; // Don't do = because prediction and refs component.Tags.Clear(); component.Groups.Clear(); component.Tags.UnionWith(state.Tags); component.Groups.UnionWith(state.Groups); } private void OnAccessGetState(EntityUid uid, AccessComponent component, ref ComponentGetState args) { args.State = new AccessComponentState() { Tags = component.Tags, Groups = component.Groups, }; } private void OnAccessInit(EntityUid uid, AccessComponent component, MapInitEvent args) { // Add all tags in groups to the list of tags. foreach (var group in component.Groups) { if (!_prototypeManager.TryIndex(group, out var proto)) continue; component.Tags.UnionWith(proto.Tags); } } /// /// Replaces the set of access tags we have with the provided set. /// /// The new access tags public bool TrySetTags(EntityUid uid, IEnumerable newTags, AccessComponent? access = null) { if (!Resolve(uid, ref access)) return false; access.Tags.Clear(); access.Tags.UnionWith(newTags); Dirty(access); return true; } public bool TryAddGroups(EntityUid uid, IEnumerable newGroups, AccessComponent? access = null) { if (!Resolve(uid, ref access)) return false; foreach (var group in newGroups) { if (!_prototypeManager.TryIndex(group, out var proto)) continue; access.Tags.UnionWith(proto.Tags); } Dirty(access); return true; } /// /// Set the access on an to the access for a specific job. /// /// The ID of the entity with the access component. /// The job prototype to use access from. /// Whether to apply extended job access. /// The access component. public void SetAccessToJob( EntityUid uid, JobPrototype prototype, bool extended, AccessComponent? access = null) { if (!Resolve(uid, ref access)) return; access.Tags.Clear(); access.Tags.UnionWith(prototype.Access); TryAddGroups(uid, prototype.AccessGroups, access); if (extended) { access.Tags.UnionWith(prototype.ExtendedAccess); TryAddGroups(uid, prototype.ExtendedAccessGroups, access); } } [Serializable, NetSerializable] private sealed class AccessComponentState : ComponentState { public HashSet Tags = new(); public HashSet Groups = new(); } } }