using Content.Server.DeviceLinking.Components; using Content.Server.NodeContainer; using Content.Server.Power.EntitySystems; using Content.Server.Power.Nodes; using Content.Server.Power.NodeGroups; using Content.Shared.Examine; using Content.Shared.Interaction; using Content.Shared.NodeContainer; using Content.Shared.Popups; using Content.Shared.Power.Generator; using Content.Shared.Timing; using Content.Shared.Tools.Systems; using Robust.Shared.Audio.Systems; using Robust.Shared.Map.Components; using Robust.Shared.Timing; namespace Content.Server.DeviceLinking.Systems; public sealed class PowerSensorSystem : EntitySystem { [Dependency] private readonly DeviceLinkSystem _deviceLink = default!; [Dependency] private readonly IGameTiming _timing = default!; [Dependency] private readonly PowerNetSystem _powerNet = default!; [Dependency] private readonly SharedAudioSystem _audio = default!; [Dependency] private readonly SharedPopupSystem _popup = default!; [Dependency] private readonly SharedToolSystem _tool = default!; [Dependency] private readonly UseDelaySystem _useDelay = default!; private EntityQuery _nodeQuery; private EntityQuery _xformQuery; public override void Initialize() { base.Initialize(); _nodeQuery = GetEntityQuery(); _xformQuery = GetEntityQuery(); SubscribeLocalEvent(OnInit); SubscribeLocalEvent(OnExamined); SubscribeLocalEvent(OnInteractUsing); } public override void Update(float deltaTime) { var query = EntityQueryEnumerator(); while (query.MoveNext(out var uid, out var comp)) { var now = _timing.CurTime; if (comp.NextCheck > now) continue; comp.NextCheck = now + comp.CheckDelay; UpdateOutputs(uid, comp); } } private void OnInit(EntityUid uid, PowerSensorComponent comp, ComponentInit args) { _deviceLink.EnsureSourcePorts(uid, comp.ChargingPort, comp.DischargingPort); } private void OnExamined(EntityUid uid, PowerSensorComponent comp, ExaminedEvent args) { if (!args.IsInDetailsRange) return; args.PushMarkup(Loc.GetString("power-sensor-examine", ("output", comp.Output))); } private void OnInteractUsing(EntityUid uid, PowerSensorComponent comp, InteractUsingEvent args) { if (args.Handled || !_tool.HasQuality(args.Used, comp.SwitchQuality)) return; // no sound spamming if (TryComp(uid, out var useDelay) && !_useDelay.TryResetDelay((uid, useDelay), true)) return; // switch between input and output mode. comp.Output = !comp.Output; // since the battery to be checked changed the output probably has too, update it UpdateOutputs(uid, comp); // notify the user _audio.PlayPvs(comp.SwitchSound, uid); var msg = Loc.GetString("power-sensor-switch", ("output", comp.Output)); _popup.PopupEntity(msg, uid, args.User); } private void UpdateOutputs(EntityUid uid, PowerSensorComponent comp) { // get power stats on the power network that's been switched to var powerSwitchable = Comp(uid); var cable = powerSwitchable.Cables[powerSwitchable.ActiveIndex]; var nodeContainer = Comp(uid); var deviceNode = (CableDeviceNode) nodeContainer.Nodes[cable.Node]; // update state based on the power stats retrieved from the selected power network var xform = _xformQuery.GetComponent(uid); if (!TryComp(xform.GridUid, out MapGridComponent? grid)) return; if (deviceNode.NodeGroup == null) return; var group = (IBasePowerNet) deviceNode.NodeGroup; var stats = _powerNet.GetNetworkStatistics(group.NetworkNode); var charge = comp.Output ? stats.OutStorageCurrent : stats.InStorageCurrent; var chargingState = charge > comp.LastCharge; var dischargingState = charge < comp.LastCharge; comp.LastCharge = charge; // send new signals if changed if (comp.ChargingState != chargingState) { comp.ChargingState = chargingState; _deviceLink.SendSignal(uid, comp.ChargingPort, chargingState); } if (comp.DischargingState != dischargingState) { comp.DischargingState = dischargingState; _deviceLink.SendSignal(uid, comp.DischargingPort, dischargingState); } } }