using Content.Server.GameObjects.Components.NodeContainer.NodeGroups; using Content.Shared.GameObjects.Components.Power; using Robust.Server.GameObjects; using Robust.Server.Interfaces.GameObjects; using Robust.Shared.GameObjects; using Robust.Shared.Interfaces.Map; using Robust.Shared.IoC; using Robust.Shared.Serialization; using Robust.Shared.ViewVariables; using System; namespace Content.Server.GameObjects.Components.Power.ApcNetComponents { /// /// Attempts to link with a nearby s so that it can receive power from a . /// [RegisterComponent] public class PowerReceiverComponent : Component { public override string Name => "PowerReceiver"; public event EventHandler OnPowerStateChanged; [ViewVariables] public bool Powered => (HasApcPower || !NeedsPower) && !PowerDisabled; [ViewVariables] public bool HasApcPower { get => _hasApcPower; set => SetHasApcPower(value); } private bool _hasApcPower; /// /// The max distance from a that this can receive power from. /// [ViewVariables(VVAccess.ReadWrite)] public int PowerReceptionRange { get => _powerReceptionRange; set => SetPowerReceptionRange(value); } private int _powerReceptionRange; [ViewVariables] public IPowerProvider Provider { get => _provider; set => SetProvider(value); } private IPowerProvider _provider = PowerProviderComponent.NullProvider; /// /// If this should be considered for connection by s. /// public bool Connectable => Anchored; private bool Anchored => !Owner.TryGetComponent(out var physics) || physics.Anchored; [ViewVariables] public bool NeedsProvider { get; private set; } = true; /// /// Amount of charge this needs from an APC per second to function. /// [ViewVariables] public int Load { get => _load; set => SetLoad(value); } private int _load; /// /// When true, causes this to appear powered even if not receiving power from an Apc. /// [ViewVariables(VVAccess.ReadWrite)] public bool NeedsPower { get => _needsPower; set => SetNeedsPower(value); } private bool _needsPower; /// /// When true, causes this to never appear powered. /// public bool PowerDisabled { get => _powerDisabled; set => SetPowerDisabled(value); } private bool _powerDisabled; public override void ExposeData(ObjectSerializer serializer) { base.ExposeData(serializer); serializer.DataField(ref _powerReceptionRange, "powerReceptionRange", 3); serializer.DataField(ref _load, "powerLoad", 5); serializer.DataField(ref _needsPower, "needsPower", true); serializer.DataField(ref _powerDisabled, "powerDisabled", false); } protected override void Startup() { base.Startup(); if (NeedsProvider) { TryFindAndSetProvider(); } if (Owner.TryGetComponent(out var physics)) { AnchorUpdate(); physics.AnchoredChanged += AnchorUpdate; } } public override void OnRemove() { if (Owner.TryGetComponent(out var physics)) { physics.AnchoredChanged -= AnchorUpdate; } _provider.RemoveReceiver(this); base.OnRemove(); } public void TryFindAndSetProvider() { if (TryFindAvailableProvider(out var provider)) { Provider = provider; } } private bool TryFindAvailableProvider(out IPowerProvider foundProvider) { var nearbyEntities = IoCManager.Resolve() .GetEntitiesInRange(Owner, PowerReceptionRange); var mapManager = IoCManager.Resolve(); foreach (var entity in nearbyEntities) { if (entity.TryGetComponent(out var provider)) { if (provider.Connectable) { var distanceToProvider = provider.Owner.Transform.GridPosition.Distance(mapManager, Owner.Transform.GridPosition); if (distanceToProvider < Math.Min(PowerReceptionRange, provider.PowerTransferRange)) { foundProvider = provider; return true; } } } } foundProvider = default; return false; } public void ClearProvider() { _provider.RemoveReceiver(this); _provider = PowerProviderComponent.NullProvider; NeedsProvider = true; HasApcPower = false; } private void SetProvider(IPowerProvider newProvider) { _provider.RemoveReceiver(this); _provider = newProvider; newProvider.AddReceiver(this); NeedsProvider = false; } private void SetHasApcPower(bool newHasApcPower) { var oldPowered = Powered; _hasApcPower = newHasApcPower; if (oldPowered != Powered) { OnNewPowerState(); } } private void SetPowerReceptionRange(int newPowerReceptionRange) { ClearProvider(); _powerReceptionRange = newPowerReceptionRange; TryFindAndSetProvider(); } private void SetLoad(int newLoad) { _load = newLoad; } private void SetNeedsPower(bool newNeedsPower) { var oldPowered = Powered; _needsPower = newNeedsPower; if (oldPowered != Powered) { OnNewPowerState(); } } private void SetPowerDisabled(bool newPowerDisabled) { var oldPowered = Powered; _powerDisabled = newPowerDisabled; if (oldPowered != Powered) { OnNewPowerState(); } } private void OnNewPowerState() { OnPowerStateChanged?.Invoke(this, new PowerStateEventArgs(Powered)); if (Owner.TryGetComponent(out AppearanceComponent appearance)) { appearance.SetData(PowerDeviceVisuals.Powered, Powered); } } private void AnchorUpdate() { if (Anchored) { if (NeedsProvider) { TryFindAndSetProvider(); } } else { ClearProvider(); } } } public class PowerStateEventArgs : EventArgs { public readonly bool Powered; public PowerStateEventArgs(bool powered) { Powered = powered; } } }