using System.Diagnostics.CodeAnalysis; using Content.Shared.Administration.Logs; using Content.Shared.Database; using Content.Shared.Power.Components; using Robust.Shared.Audio; using Robust.Shared.Audio.Systems; using Robust.Shared.Network; namespace Content.Shared.Power.EntitySystems; public abstract class SharedPowerReceiverSystem : EntitySystem { [Dependency] private readonly INetManager _netMan = default!; [Dependency] private readonly ISharedAdminLogManager _adminLogger = default!; [Dependency] private readonly SharedAudioSystem _audio = default!; [Dependency] private readonly SharedPowerNetSystem _net = default!; public abstract bool ResolveApc(EntityUid entity, [NotNullWhen(true)] ref SharedApcPowerReceiverComponent? component); public void SetNeedsPower(EntityUid uid, bool value, SharedApcPowerReceiverComponent? receiver = null) { if (!ResolveApc(uid, ref receiver) || receiver.NeedsPower == value) return; receiver.NeedsPower = value; Dirty(uid, receiver); } public void SetPowerDisabled(EntityUid uid, bool value, SharedApcPowerReceiverComponent? receiver = null) { if (!ResolveApc(uid, ref receiver) || receiver.PowerDisabled == value) return; receiver.PowerDisabled = value; Dirty(uid, receiver); } /// /// Turn this machine on or off. /// Returns true if we turned it on, false if we turned it off. /// public bool TogglePower(EntityUid uid, bool playSwitchSound = true, SharedApcPowerReceiverComponent? receiver = null, EntityUid? user = null) { if (!ResolveApc(uid, ref receiver)) return true; // it'll save a lot of confusion if 'always powered' means 'always powered' if (!receiver.NeedsPower) { var powered = _net.IsPoweredCalculate(receiver); // Server won't raise it here as it can raise the load event later with NeedsPower? // This is mostly here for clientside predictions. if (receiver.Powered != powered) { RaisePower((uid, receiver)); } SetPowerDisabled(uid, false, receiver); return true; } SetPowerDisabled(uid, !receiver.PowerDisabled, receiver); if (user != null) _adminLogger.Add(LogType.Action, LogImpact.Low, $"{ToPrettyString(user.Value):player} hit power button on {ToPrettyString(uid)}, it's now {(!receiver.PowerDisabled ? "on" : "off")}"); if (playSwitchSound) { _audio.PlayPredicted(new SoundPathSpecifier("/Audio/Machines/machine_switch.ogg"), uid, user: user, AudioParams.Default.WithVolume(-2f)); } if (_netMan.IsClient && receiver.PowerDisabled) { var powered = _net.IsPoweredCalculate(receiver); // Server won't raise it here as it can raise the load event later with NeedsPower? // This is mostly here for clientside predictions. if (receiver.Powered != powered) { receiver.Powered = powered; RaisePower((uid, receiver)); } } return !receiver.PowerDisabled; // i.e. PowerEnabled } protected virtual void RaisePower(Entity entity) { // NOOP on server because client has 0 idea of load so we can't raise it properly in shared. } /// /// Checks if entity is APC-powered device, and if it have power. /// public bool IsPowered(Entity entity) { if (!ResolveApc(entity.Owner, ref entity.Comp)) return true; return entity.Comp.Powered; } protected string GetExamineText(bool powered) { return Loc.GetString("power-receiver-component-on-examine-main", ("stateText", Loc.GetString(powered ? "power-receiver-component-on-examine-powered" : "power-receiver-component-on-examine-unpowered"))); } }