// SPDX-FileCopyrightText: 2025 GoobBot // SPDX-FileCopyrightText: 2025 deltanedas <39013340+deltanedas@users.noreply.github.com> // SPDX-FileCopyrightText: 2025 deltanedas <@deltanedas:kde.org> // // SPDX-License-Identifier: AGPL-3.0-or-later using Content.Shared._Goobstation.Factory.Slots; using Content.Shared.Prototypes; using Robust.Shared.Physics.Components; using Robust.Shared.Physics.Systems; using Robust.Shared.Prototypes; namespace Content.Shared._Goobstation.Factory; public sealed class AutomationSystem : EntitySystem { [Dependency] private readonly IPrototypeManager _proto = default!; [Dependency] private readonly SharedPhysicsSystem _physics = default!; private EntityQuery _slotsQuery; private EntityQuery _automatedQuery; private List _automatable = new(); /// /// All entities with , maintained on prototype reload. /// public IReadOnlyList Automatable => _automatable; public override void Initialize() { base.Initialize(); _slotsQuery = GetEntityQuery(); _automatedQuery = GetEntityQuery(); SubscribeLocalEvent(OnInit); SubscribeLocalEvent(OnMapInit); SubscribeLocalEvent(OnShutdown); SubscribeLocalEvent(OnAnchorChanged); SubscribeLocalEvent(OnPrototypesReloaded); CacheEntities(); } private void OnInit(Entity ent, ref ComponentInit args) { foreach (var slot in ent.Comp.Slots) { slot.Owner = ent; slot.Initialize(); } } private void OnMapInit(Entity ent, ref MapInitEvent args) { if (!TryComp(ent, out var comp)) return; foreach (var slot in comp.Slots) { slot.AddPorts(); } } private void OnShutdown(Entity ent, ref ComponentShutdown args) { if (!TryComp(ent, out var comp)) return; foreach (var slot in comp.Slots) { slot.RemovePorts(); } } private void OnAnchorChanged(Entity ent, ref AnchorStateChangedEvent args) { // force collision events so machines can react to objects getting unanchored // should get reset after a tick due to collision wake if (!args.Anchored) _physics.WakeBody(ent); } private void OnPrototypesReloaded(PrototypesReloadedEventArgs args) { if (!args.WasModified()) return; CacheEntities(); } private void CacheEntities() { _automatable.Clear(); var factory = EntityManager.ComponentFactory; foreach (var proto in _proto.EnumeratePrototypes()) { if (proto.HasComponent(factory)) _automatable.Add(proto.ID); } _automatable.Sort(); } #region Public API public AutomationSlot? GetSlot(Entity ent, string port, bool input) { // entity has no automation slots to begin with if (!_slotsQuery.Resolve(ent, ref ent.Comp, false)) return null; // automation isn't enabled if (!IsAutomated(ent)) return null; foreach (var slot in ent.Comp.Slots) { string? id = input ? slot.Input : slot.Output; if (id == port) return slot; } return null; } public bool IsAutomated(EntityUid uid) { return _automatedQuery.HasComp(uid); } public bool HasSlot(Entity ent, string port, bool input) { return GetSlot(ent, port, input) != null; } #endregion }