diff --git a/Content.Client/Entry/IgnoredComponents.cs b/Content.Client/Entry/IgnoredComponents.cs index fc7e2b17e9..0876a1f078 100644 --- a/Content.Client/Entry/IgnoredComponents.cs +++ b/Content.Client/Entry/IgnoredComponents.cs @@ -283,9 +283,13 @@ namespace Content.Client.Entry "LitOnPowered", "TriggerOnSignalReceived", "ToggleDoorOnTrigger", - "DeviceNetworkConnection", + "DeviceNetworkComponent", "WiredNetworkConnection", "WirelessNetworkConnection", + "ExtensionCableReceiver", + "ExtensionCableProvider", + "ApcNetworkConnection", + "ApcNetSwitch", "HandLabeler", "Label", "GhostRadio", diff --git a/Content.IntegrationTests/Tests/DeviceNetwork/DeviceNetworkTest.cs b/Content.IntegrationTests/Tests/DeviceNetwork/DeviceNetworkTest.cs index f098b516f3..ceac721e96 100644 --- a/Content.IntegrationTests/Tests/DeviceNetwork/DeviceNetworkTest.cs +++ b/Content.IntegrationTests/Tests/DeviceNetwork/DeviceNetworkTest.cs @@ -28,7 +28,7 @@ namespace Content.IntegrationTests.Tests.DeviceNetwork id: DummyWiredNetworkDevice components: - type: DeviceNetworkComponent - deviceNetId: 1 + deviceNetId: Wired - type: WiredNetworkConnection - type: ApcPowerReceiver @@ -38,7 +38,7 @@ namespace Content.IntegrationTests.Tests.DeviceNetwork components: - type: DeviceNetworkComponent frequency: 100 - deviceNetId: 1 + deviceNetId: Wireless - type: WirelessNetworkConnection range: 100 "; diff --git a/Content.IntegrationTests/Tests/Power/PowerTest.cs b/Content.IntegrationTests/Tests/Power/PowerTest.cs index b8453821f3..44fef5b504 100644 --- a/Content.IntegrationTests/Tests/Power/PowerTest.cs +++ b/Content.IntegrationTests/Tests/Power/PowerTest.cs @@ -3,6 +3,7 @@ using System.Threading.Tasks; using Content.Server.NodeContainer; using Content.Server.NodeContainer.Nodes; using Content.Server.Power.Components; +using Content.Server.Power.EntitySystems; using Content.Server.Power.Nodes; using Content.Shared.Coordinates; using NUnit.Framework; @@ -152,6 +153,7 @@ namespace Content.IntegrationTests.Tests.Power id: ApcPowerReceiverDummy components: - type: ApcPowerReceiver + - type: ExtensionCableReceiver - type: Transform anchored: true "; @@ -160,6 +162,7 @@ namespace Content.IntegrationTests.Tests.Power private IMapManager _mapManager = default!; private IEntityManager _entityManager = default!; private IGameTiming _gameTiming = default!; + private ExtensionCableSystem _extensionCableSystem = default!; [OneTimeSetUp] public async Task Setup() @@ -171,6 +174,7 @@ namespace Content.IntegrationTests.Tests.Power _mapManager = _server.ResolveDependency(); _entityManager = _server.ResolveDependency(); _gameTiming = _server.ResolveDependency(); + _extensionCableSystem = _entityManager.EntitySysManager.GetEntitySystem(); } /// @@ -968,13 +972,12 @@ namespace Content.IntegrationTests.Tests.Power var apcExtensionEnt = _entityManager.SpawnEntity("CableApcExtension", grid.ToCoordinates(0, 0)); var powerReceiverEnt = _entityManager.SpawnEntity("ApcPowerReceiverDummy", grid.ToCoordinates(0, 2)); - var provider = apcExtensionEnt.GetComponent(); receiver = powerReceiverEnt.GetComponent(); var battery = apcEnt.GetComponent(); apcNetBattery = apcEnt.GetComponent(); - provider.PowerTransferRange = 5; //arbitrary range to reach receiver - receiver.PowerReceptionRange = 5; //arbitrary range to reach provider + _extensionCableSystem.SetProviderTransferRange(apcExtensionEnt.Uid, 5); + _extensionCableSystem.SetReceiverReceptionRange(powerReceiverEnt.Uid, 5); battery.MaxCharge = 10000; //arbitrary nonzero amount of charge battery.CurrentCharge = battery.MaxCharge; //fill battery diff --git a/Content.Server/DeviceNetwork/Components/ApcNetworkComponent.cs b/Content.Server/DeviceNetwork/Components/ApcNetworkComponent.cs new file mode 100644 index 0000000000..202f98c3ff --- /dev/null +++ b/Content.Server/DeviceNetwork/Components/ApcNetworkComponent.cs @@ -0,0 +1,20 @@ +using Content.Server.DeviceNetwork.Systems; +using Content.Server.NodeContainer.Nodes; +using Robust.Shared.Analyzers; +using Robust.Shared.GameObjects; +using Robust.Shared.ViewVariables; + +namespace Content.Server.DeviceNetwork.Components +{ + [RegisterComponent] + [Friend(typeof(ApcNetworkSystem))] + public class ApcNetworkComponent : Component + { + public override string Name => "ApcNetworkConnection"; + + /// + /// The node Group the ApcNetworkConnection is connected to + /// + [ViewVariables] public Node? ConnectedNode; + } +} diff --git a/Content.Server/DeviceNetwork/Components/DeviceNetworkComponent.cs b/Content.Server/DeviceNetwork/Components/DeviceNetworkComponent.cs index 1f4a671f70..918c035a0b 100644 --- a/Content.Server/DeviceNetwork/Components/DeviceNetworkComponent.cs +++ b/Content.Server/DeviceNetwork/Components/DeviceNetworkComponent.cs @@ -1,3 +1,4 @@ +using System; using Robust.Shared.GameObjects; using Robust.Shared.Serialization.Manager.Attributes; using Robust.Shared.ViewVariables; @@ -9,16 +10,22 @@ namespace Content.Server.DeviceNetwork.Components { public override string Name => "DeviceNetworkComponent"; + /// - /// The device networks netID this DeviceNetworkComponent connects to. - /// The netID is used to seperate device networks that shouldn't interact with each other e.g. wireless and wired. - /// The default netID's are_ - /// 0 -> Private - /// 1 -> Wired - /// 2 -> Wireless + /// Valid device network NetIDs. + /// The netID is used to separate device networks that shouldn't interact with each other e.g. wireless and wired. /// + [Serializable] + public enum ConnectionType + { + Private, + Wired, + Wireless, + Apc + } + [DataField("deviceNetId")] - public int DeviceNetId { get; set; } = (int)DeviceNetworkConstants.ConnectionType.Private; + public ConnectionType DeviceNetId { get; set; } = ConnectionType.Private; [DataField("frequency")] public int Frequency { get; set; } = 0; diff --git a/Content.Server/DeviceNetwork/Components/Devices/ApcNetSwitchComponent.cs b/Content.Server/DeviceNetwork/Components/Devices/ApcNetSwitchComponent.cs new file mode 100644 index 0000000000..e9f2438885 --- /dev/null +++ b/Content.Server/DeviceNetwork/Components/Devices/ApcNetSwitchComponent.cs @@ -0,0 +1,16 @@ +using Content.Server.DeviceNetwork.Systems.Devices; +using Robust.Shared.Analyzers; +using Robust.Shared.GameObjects; +using Robust.Shared.ViewVariables; + +namespace Content.Server.DeviceNetwork.Components.Devices +{ + [RegisterComponent] + [Friend(typeof(ApcNetSwitchSystem))] + public class ApcNetSwitchComponent : Component + { + public override string Name => "ApcNetSwitch"; + + [ViewVariables] public bool State; + } +} diff --git a/Content.Server/DeviceNetwork/DeviceNetworkConstants.cs b/Content.Server/DeviceNetwork/DeviceNetworkConstants.cs index b8533fd5d2..6136a210ae 100644 --- a/Content.Server/DeviceNetwork/DeviceNetworkConstants.cs +++ b/Content.Server/DeviceNetwork/DeviceNetworkConstants.cs @@ -1,21 +1,38 @@ namespace Content.Server.DeviceNetwork { /// - /// A collection of utilities to help with using device networks + /// A collection of constants to help with using device networks /// public static class DeviceNetworkConstants { - public enum ConnectionType - { - Private, - Wired, - Wireless - } + /// + /// Invalid address used for broadcasting + /// + public const string NullAddress = "######"; + + #region Commands /// /// The key for command names /// E.g. [DeviceNetworkConstants.Command] = "ping" /// public const string Command = "command"; + + /// + /// The command for setting a devices state + /// E.g. to turn a light on or off + /// + public const string CmdSetState = "set_state"; + + #endregion + + #region SetState + + /// + /// Used with the command to turn a device on or off + /// + public const string StateEnabled = "state_enabled"; + + #endregion } } diff --git a/Content.Server/DeviceNetwork/Systems/ApcNetworkSystem.cs b/Content.Server/DeviceNetwork/Systems/ApcNetworkSystem.cs new file mode 100644 index 0000000000..2320420f83 --- /dev/null +++ b/Content.Server/DeviceNetwork/Systems/ApcNetworkSystem.cs @@ -0,0 +1,56 @@ +using Content.Server.DeviceNetwork.Components; +using Content.Server.NodeContainer; +using JetBrains.Annotations; +using Robust.Shared.GameObjects; +using Content.Server.Power.EntitySystems; +using Content.Server.Power.Nodes; + +namespace Content.Server.DeviceNetwork.Systems +{ + [UsedImplicitly] + public class ApcNetworkSystem : EntitySystem + { + public override void Initialize() + { + base.Initialize(); + + SubscribeLocalEvent(OnBeforePacketSent); + + SubscribeLocalEvent(OnProviderConnected); + SubscribeLocalEvent(OnProviderDisconnected); + } + + /// + /// Checks if both devices are connected to the same apc + /// + private void OnBeforePacketSent(EntityUid uid, ApcNetworkComponent receiver, BeforePacketSentEvent args) + { + if (!EntityManager.TryGetComponent(args.Sender, out ApcNetworkComponent? sender)) return; + + if (sender.ConnectedNode?.NodeGroup == null || !sender.ConnectedNode.NodeGroup.Equals(receiver.ConnectedNode?.NodeGroup)) + { + args.Cancel(); + } + } + + private void OnProviderConnected(EntityUid uid, ApcNetworkComponent component, ExtensionCableSystem.ProviderConnectedEvent args) + { + if (!args.Provider.Owner.TryGetComponent(out NodeContainerComponent? nodeContainer)) return; + + if (nodeContainer.TryGetNode("power", out CableNode? node)) + { + component.ConnectedNode = node; + } + else if (nodeContainer.TryGetNode("output", out CableDeviceNode? deviceNode)) + { + component.ConnectedNode = deviceNode; + } + + } + + private void OnProviderDisconnected(EntityUid uid, ApcNetworkComponent component, ExtensionCableSystem.ProviderDisconnectedEvent args) + { + component.ConnectedNode = null; + } + } +} diff --git a/Content.Server/DeviceNetwork/Systems/DeviceNetworkSystem.cs b/Content.Server/DeviceNetwork/Systems/DeviceNetworkSystem.cs index e5e5d25e4e..244ce6b4c2 100644 --- a/Content.Server/DeviceNetwork/Systems/DeviceNetworkSystem.cs +++ b/Content.Server/DeviceNetwork/Systems/DeviceNetworkSystem.cs @@ -17,7 +17,7 @@ namespace Content.Server.DeviceNetwork.Systems { [Dependency] private readonly IRobustRandom _random = default!; - private readonly Dictionary> _connections = new(); + private readonly Dictionary> _connections = new(); private readonly Queue _packets = new(); public override void Initialize() @@ -139,7 +139,7 @@ namespace Content.Server.DeviceNetwork.Systems /// /// Generates a valid address by randomly generating one and checking if it already exists on the device network with the given device netId. /// - private string GenerateValidAddress(int netId) + private string GenerateValidAddress(DeviceNetworkComponent.ConnectionType netId) { var unique = false; var connections = _connections[netId]; @@ -154,7 +154,7 @@ namespace Content.Server.DeviceNetwork.Systems return address; } - private List ConnectionsForFrequency(int netId, int frequency) + private List ConnectionsForFrequency(DeviceNetworkComponent.ConnectionType netId, int frequency) { if (!_connections.ContainsKey(netId)) return new List(); @@ -164,7 +164,7 @@ namespace Content.Server.DeviceNetwork.Systems return result; } - private bool TryGetConnectionWithAddress(int netId, int frequency, string address, [NotNullWhen(true)] out DeviceNetworkComponent connection) + private bool TryGetConnectionWithAddress(DeviceNetworkComponent.ConnectionType netId, int frequency, string address, [NotNullWhen(true)] out DeviceNetworkComponent connection) { var connections = ConnectionsForFrequency(netId, frequency); @@ -180,7 +180,7 @@ namespace Content.Server.DeviceNetwork.Systems return false; } - private List ConnectionsWithReceiveAll(int netId, int frequency) + private List ConnectionsWithReceiveAll(DeviceNetworkComponent.ConnectionType netId, int frequency) { if (!_connections.ContainsKey(netId)) return new List(); @@ -195,7 +195,7 @@ namespace Content.Server.DeviceNetwork.Systems if (!TryGetConnectionWithAddress(packet.NetId, packet.Frequency, packet.Address, out var connection)) return; - var receivers = ConnectionsWithReceiveAll(packet.Frequency, packet.NetId); + var receivers = ConnectionsWithReceiveAll(packet.NetId, packet.Frequency); receivers.Add(connection); SendToConnections(receivers, packet); @@ -203,7 +203,7 @@ namespace Content.Server.DeviceNetwork.Systems private void BroadcastPacket(NetworkPacket packet) { - var receivers = ConnectionsForFrequency(packet.Frequency, packet.NetId); + var receivers = ConnectionsForFrequency(packet.NetId, packet.Frequency); SendToConnections(receivers, packet); } @@ -223,7 +223,7 @@ namespace Content.Server.DeviceNetwork.Systems internal struct NetworkPacket { - public int NetId; + public DeviceNetworkComponent.ConnectionType NetId; public int Frequency; public string Address; public bool Broadcast; diff --git a/Content.Server/DeviceNetwork/Systems/Devices/ApcNetSwitchSystem.cs b/Content.Server/DeviceNetwork/Systems/Devices/ApcNetSwitchSystem.cs new file mode 100644 index 0000000000..20fd540829 --- /dev/null +++ b/Content.Server/DeviceNetwork/Systems/Devices/ApcNetSwitchSystem.cs @@ -0,0 +1,54 @@ +using Content.Server.DeviceNetwork.Components; +using Content.Server.DeviceNetwork.Components.Devices; +using Content.Shared.Interaction; +using Robust.Shared.GameObjects; +using Robust.Shared.IoC; + +namespace Content.Server.DeviceNetwork.Systems.Devices +{ + public sealed class ApcNetSwitchSystem : EntitySystem + { + [Dependency] private readonly DeviceNetworkSystem _deviceNetworkSystem = default!; + + public override void Initialize() + { + base.Initialize(); + + SubscribeLocalEvent(OnInteracted); + SubscribeLocalEvent(OnPackedReceived); + } + + /// + /// Toggles the state of the switch and sents a command with the + /// value set to state. + /// + private void OnInteracted(EntityUid uid, ApcNetSwitchComponent component, InteractHandEvent args) + { + if (!EntityManager.TryGetComponent(uid, out DeviceNetworkComponent? networkComponent)) return; + + component.State = !component.State; + + var payload = new NetworkPayload + { + [DeviceNetworkConstants.Command] = DeviceNetworkConstants.CmdSetState, + [DeviceNetworkConstants.StateEnabled] = component.State, + }; + + _deviceNetworkSystem.QueuePacket(uid, DeviceNetworkConstants.NullAddress, networkComponent.Frequency, payload, true); + + args.Handled = true; + } + + /// + /// Listens to the command of other switches to sync state + /// + private void OnPackedReceived(EntityUid uid, ApcNetSwitchComponent component, PacketSentEvent args) + { + if (!EntityManager.TryGetComponent(uid, out DeviceNetworkComponent? networkComponent) || args.SenderAddress == networkComponent.Address) return; + if (!args.Data.TryGetValue(DeviceNetworkConstants.Command, out string? command) || command != DeviceNetworkConstants.CmdSetState) return; + if (!args.Data.TryGetValue(DeviceNetworkConstants.StateEnabled, out bool enabled)) return; + + component.State = enabled; + } + } +} diff --git a/Content.Server/Light/Components/PoweredLightComponent.cs b/Content.Server/Light/Components/PoweredLightComponent.cs index 2089351e84..700a701f9b 100644 --- a/Content.Server/Light/Components/PoweredLightComponent.cs +++ b/Content.Server/Light/Components/PoweredLightComponent.cs @@ -317,6 +317,10 @@ namespace Content.Server.Light.Components UpdateLight(); } - + public void SetState(bool state) + { + _on = state; + UpdateLight(); + } } } diff --git a/Content.Server/Light/EntitySystems/PoweredLightSystem.cs b/Content.Server/Light/EntitySystems/PoweredLightSystem.cs index 90f4d7e926..e9ac10eae4 100644 --- a/Content.Server/Light/EntitySystems/PoweredLightSystem.cs +++ b/Content.Server/Light/EntitySystems/PoweredLightSystem.cs @@ -1,4 +1,6 @@ using System; +using Content.Server.DeviceNetwork; +using Content.Server.DeviceNetwork.Systems; using Content.Server.Ghost; using Content.Server.Light.Components; using Content.Server.MachineLinking.Events; @@ -24,9 +26,11 @@ namespace Content.Server.Light.EntitySystems { base.Initialize(); SubscribeLocalEvent(OnGhostBoo); - SubscribeLocalEvent(OnSignalReceived); SubscribeLocalEvent(HandleLightDamaged); + SubscribeLocalEvent(OnSignalReceived); + SubscribeLocalEvent(OnPacketReceived); + SubscribeLocalEvent(OnPowerChanged); SubscribeLocalEvent(OnPowerSupply); } @@ -90,6 +94,18 @@ namespace Content.Server.Light.EntitySystems } } + /// + /// Turns the light on or of when receiving a command. + /// The light is turned on or of according to the value + /// + private void OnPacketReceived(EntityUid uid, PoweredLightComponent component, PacketSentEvent args) + { + if (!args.Data.TryGetValue(DeviceNetworkConstants.Command, out string? command) || command != DeviceNetworkConstants.CmdSetState) return; + if (!args.Data.TryGetValue(DeviceNetworkConstants.StateEnabled, out bool enabled)) return; + + component.SetState(enabled); + } + private void OnPowerChanged(EntityUid uid, LitOnPoweredComponent component, PowerChangedEvent args) { if (EntityManager.TryGetComponent(uid, out var light)) diff --git a/Content.Server/Power/Components/ApcPowerProviderComponent.cs b/Content.Server/Power/Components/ApcPowerProviderComponent.cs index dd8c3501ce..4d8ffc9092 100644 --- a/Content.Server/Power/Components/ApcPowerProviderComponent.cs +++ b/Content.Server/Power/Components/ApcPowerProviderComponent.cs @@ -1,9 +1,6 @@ -using System; using System.Collections.Generic; using Content.Server.Power.NodeGroups; using Robust.Shared.GameObjects; -using Robust.Shared.IoC; -using Robust.Shared.Serialization.Manager.Attributes; using Robust.Shared.ViewVariables; namespace Content.Server.Power.Components @@ -13,24 +10,8 @@ namespace Content.Server.Power.Components { public override string Name => "PowerProvider"; - public IEntity ProviderOwner => Owner; - - /// - /// The max distance this can transmit power to s from. - /// - [ViewVariables(VVAccess.ReadWrite)] - public int PowerTransferRange { get => _powerTransferRange; set => SetPowerTransferRange(value); } - [DataField("powerTransferRange")] - private int _powerTransferRange = 3; - [ViewVariables] public List LinkedReceivers { get; } = new(); - /// - /// If s should consider connecting to this. - /// - [ViewVariables(VVAccess.ReadWrite)] - public bool Connectable { get; private set; } = true; - public void AddReceiver(ApcPowerReceiverComponent receiver) { LinkedReceivers.Add(receiver); @@ -47,49 +28,6 @@ namespace Content.Server.Power.Components Net?.QueueNetworkReconnect(); } - protected override void Startup() - { - base.Startup(); - - foreach (var receiver in FindAvailableReceivers()) - { - receiver.Provider = this; - } - } - - protected override void OnRemove() - { - Connectable = false; - var receivers = LinkedReceivers.ToArray(); - foreach (var receiver in receivers) - { - receiver.Provider = null; - } - foreach (var receiver in receivers) - { - receiver.TryFindAndSetProvider(); - } - base.OnRemove(); - } - - private IEnumerable FindAvailableReceivers() - { - var nearbyEntities = IoCManager.Resolve() - .GetEntitiesInRange(Owner, PowerTransferRange); - - foreach (var entity in nearbyEntities) - { - if (entity.TryGetComponent(out var receiver) && - receiver.Connectable && - receiver.NeedsProvider && - receiver.Owner.Transform.Coordinates.TryDistance(Owner.EntityManager, Owner.Transform.Coordinates, out var distance) && - distance < Math.Min(PowerTransferRange, receiver.PowerReceptionRange)) - { - yield return receiver; - } - } - } - protected override void AddSelfToNet(IApcNet apcNet) { apcNet.AddPowerProvider(this); @@ -99,22 +37,5 @@ namespace Content.Server.Power.Components { apcNet.RemovePowerProvider(this); } - - private void SetPowerTransferRange(int newPowerTransferRange) - { - var receivers = LinkedReceivers.ToArray(); - - foreach (var receiver in receivers) - { - receiver.Provider = null; - } - - _powerTransferRange = newPowerTransferRange; - - foreach (var receiver in receivers) - { - receiver.TryFindAndSetProvider(); - } - } } } diff --git a/Content.Server/Power/Components/ApcPowerReceiverComponent.cs b/Content.Server/Power/Components/ApcPowerReceiverComponent.cs index 16d30d9674..7f0cc03e1b 100644 --- a/Content.Server/Power/Components/ApcPowerReceiverComponent.cs +++ b/Content.Server/Power/Components/ApcPowerReceiverComponent.cs @@ -23,47 +23,11 @@ namespace Content.Server.Power.Components [RegisterComponent] public class ApcPowerReceiverComponent : Component, IExamine { - [ViewVariables] [ComponentDependency] private readonly IPhysBody? _physicsComponent = null; - public override string Name => "ApcPowerReceiver"; [ViewVariables] public bool Powered => (MathHelper.CloseToPercent(NetworkLoad.ReceivingPower, Load) || !NeedsPower) && !PowerDisabled; - /// - /// The max distance from a that this can receive power from. - /// - [ViewVariables(VVAccess.ReadWrite)] - public int PowerReceptionRange { get => _powerReceptionRange; set => SetPowerReceptionRange(value); } - [DataField("powerReceptionRange")] - private int _powerReceptionRange = 3; - - [ViewVariables] - public ApcPowerProviderComponent? Provider - { - get => _provider; - set - { - // Will get updated before power networks process. - NetworkLoad.LinkedNetwork = default; - _provider?.RemoveReceiver(this); - _provider = value; - value?.AddReceiver(this); - ApcPowerChanged(); - } - } - - private ApcPowerProviderComponent? _provider; - - /// - /// If this should be considered for connection by s. - /// - public bool Connectable => Anchored; - - private bool Anchored => _physicsComponent == null || _physicsComponent.BodyType == BodyType.Static; - - [ViewVariables] public bool NeedsProvider => Provider == null; - /// /// Amount of charge this needs from an APC per second to function. /// @@ -104,73 +68,11 @@ namespace Content.Server.Power.Components DesiredPower = 5 }; - protected override void Startup() - { - base.Startup(); - if (NeedsProvider) - { - TryFindAndSetProvider(); - } - if (_physicsComponent != null) - { - AnchorUpdate(); - } - } - - protected override void OnRemove() - { - _provider?.RemoveReceiver(this); - - base.OnRemove(); - } - - public void TryFindAndSetProvider() - { - if (TryFindAvailableProvider(out var provider)) - { - Provider = provider; - } - } - public void ApcPowerChanged() { OnNewPowerState(); } - private bool TryFindAvailableProvider([NotNullWhen(true)] out ApcPowerProviderComponent? foundProvider) - { - var nearbyEntities = IoCManager.Resolve() - .GetEntitiesInRange(Owner, PowerReceptionRange); - - foreach (var entity in nearbyEntities) - { - if (entity.TryGetComponent(out var provider)) - { - if (provider.Connectable) - { - if (provider.Owner.Transform.Coordinates.TryDistance(Owner.EntityManager, Owner.Transform.Coordinates, out var distance)) - { - if (distance < Math.Min(PowerReceptionRange, provider.PowerTransferRange)) - { - foundProvider = provider; - return true; - } - } - } - } - } - - foundProvider = default; - return false; - } - - private void SetPowerReceptionRange(int newPowerReceptionRange) - { - Provider = null; - _powerReceptionRange = newPowerReceptionRange; - TryFindAndSetProvider(); - } - private void OnNewPowerState() { SendMessage(new PowerChangedMessage(Powered)); @@ -182,21 +84,6 @@ namespace Content.Server.Power.Components } } - public void AnchorUpdate() - { - if (Anchored) - { - if (NeedsProvider) - { - TryFindAndSetProvider(); - } - } - else - { - Provider = null; - } - } - /// ///Adds some markup to the examine text of whatever object is using this component to tell you if it's powered or not, even if it doesn't have an icon state to do this for you. /// diff --git a/Content.Server/Power/Components/ExtensionCableProviderComponent.cs b/Content.Server/Power/Components/ExtensionCableProviderComponent.cs new file mode 100644 index 0000000000..fb3a6d5f37 --- /dev/null +++ b/Content.Server/Power/Components/ExtensionCableProviderComponent.cs @@ -0,0 +1,33 @@ +using System.Collections.Generic; +using Content.Server.Power.EntitySystems; +using Robust.Shared.Analyzers; +using Robust.Shared.GameObjects; +using Robust.Shared.Serialization.Manager.Attributes; +using Robust.Shared.ViewVariables; + +namespace Content.Server.Power.Components +{ + [RegisterComponent] + [Friend(typeof(ExtensionCableSystem))] + public class ExtensionCableProviderComponent : Component + { + public override string Name => "ExtensionCableProvider"; + + /// + /// The max distance this can connect to s from. + /// + [ViewVariables(VVAccess.ReadWrite)] + [DataField("transferRange")] + public int TransferRange { get; set; } = 3; + + [ViewVariables] public List LinkedReceivers { get; } = new(); + + /// + /// If s should consider connecting to this. + /// + [ViewVariables(VVAccess.ReadWrite)] + public bool Connectable { get; set; } = true; + + + } +} diff --git a/Content.Server/Power/Components/ExtensionCableReceiverComponent.cs b/Content.Server/Power/Components/ExtensionCableReceiverComponent.cs new file mode 100644 index 0000000000..cac443ccb4 --- /dev/null +++ b/Content.Server/Power/Components/ExtensionCableReceiverComponent.cs @@ -0,0 +1,28 @@ +using Content.Server.Power.EntitySystems; +using Robust.Shared.Analyzers; +using Robust.Shared.GameObjects; +using Robust.Shared.Serialization.Manager.Attributes; +using Robust.Shared.ViewVariables; + +namespace Content.Server.Power.Components +{ + [RegisterComponent] + [Friend(typeof(ExtensionCableSystem))] + public class ExtensionCableReceiverComponent : Component + { + public override string Name => "ExtensionCableReceiver"; + + [ViewVariables] + public ExtensionCableProviderComponent? Provider { get; set; } + + [ViewVariables] + public bool Connectable = false; + + /// + /// The max distance from a that this can receive power from. + /// + [ViewVariables(VVAccess.ReadWrite)] + [DataField("receptionRange")] + public int ReceptionRange { get; set; } = 3; + } +} diff --git a/Content.Server/Power/EntitySystems/ExtensionCableSystem.cs b/Content.Server/Power/EntitySystems/ExtensionCableSystem.cs new file mode 100644 index 0000000000..32f0ab433c --- /dev/null +++ b/Content.Server/Power/EntitySystems/ExtensionCableSystem.cs @@ -0,0 +1,256 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using Content.Server.Power.Components; +using Robust.Shared.GameObjects; +using Robust.Shared.IoC; +using Robust.Shared.Physics; + +namespace Content.Server.Power.EntitySystems +{ + public sealed class ExtensionCableSystem : EntitySystem + { + public override void Initialize() + { + base.Initialize(); + + //Lifecycle events + SubscribeLocalEvent(OnProviderStarted); + SubscribeLocalEvent(OnProviderShutdown); + SubscribeLocalEvent(OnReceiverStarted); + SubscribeLocalEvent(OnReceiverShutdown); + + //Anchoring + SubscribeLocalEvent(AnchorStateChanged); + } + + #region Provider + + public void SetProviderTransferRange(EntityUid uid, int range, ExtensionCableProviderComponent? provider = null) + { + if (!Resolve(uid, ref provider)) + return; + + provider.TransferRange = range; + ResetReceivers(provider); + } + + private void OnProviderStarted(EntityUid uid, ExtensionCableProviderComponent provider, ComponentStartup args) + { + foreach (var receiver in FindAvailableReceivers(uid, provider.TransferRange)) + { + receiver.Provider?.LinkedReceivers.Remove(receiver); + receiver.Provider = provider; + provider.LinkedReceivers.Add(receiver); + RaiseLocalEvent(receiver.Owner.Uid, new ProviderConnectedEvent(provider), broadcast: false); + RaiseLocalEvent(uid, new ReceiverConnectedEvent(receiver), broadcast: false); + } + } + + private void OnProviderShutdown(EntityUid uid, ExtensionCableProviderComponent provider, ComponentShutdown args) + { + provider.Connectable = false; + ResetReceivers(provider); + } + + private void ResetReceivers(ExtensionCableProviderComponent provider) + { + var receivers = provider.LinkedReceivers.ToArray(); + + foreach (var receiver in receivers) + { + receiver.Provider = null; + RaiseLocalEvent(receiver.Owner.Uid, new ProviderDisconnectedEvent(provider), broadcast: false); + RaiseLocalEvent(provider.Owner.Uid, new ReceiverDisconnectedEvent(receiver), broadcast: false); + } + + foreach (var receiver in receivers) + { + TryFindAndSetProvider(receiver); + } + } + + private IEnumerable FindAvailableReceivers(EntityUid uid, float range) + { + var owner = EntityManager.GetEntity(uid); + + var nearbyEntities = IoCManager.Resolve() + .GetEntitiesInRange(owner, range); + + foreach (var entity in nearbyEntities) + { + if (entity.TryGetComponent(out var receiver) && + receiver.Connectable && + receiver.Provider == null && + entity.Transform.Coordinates.TryDistance(owner.EntityManager, owner.Transform.Coordinates, out var distance) && + distance < Math.Min(range, receiver.ReceptionRange)) + { + yield return receiver; + } + } + } + + #endregion + + #region Receiver + + public void SetReceiverReceptionRange(EntityUid uid, int range, ExtensionCableReceiverComponent? receiver = null) + { + if (!Resolve(uid, ref receiver)) + return; + + var provider = receiver.Provider; + receiver.Provider = null; + RaiseLocalEvent(uid, new ProviderDisconnectedEvent(provider), broadcast: false); + + if (provider != null) + RaiseLocalEvent(provider.Owner.Uid, new ReceiverDisconnectedEvent(receiver), broadcast: false); + + receiver.ReceptionRange = range; + TryFindAndSetProvider(receiver); + } + + private void OnReceiverStarted(EntityUid uid, ExtensionCableReceiverComponent receiver, ComponentStartup args) + { + if (receiver.Owner.TryGetComponent(out PhysicsComponent? physicsComponent)) + { + receiver.Connectable = physicsComponent.BodyType == BodyType.Static; + } + + if (receiver.Provider == null) + { + TryFindAndSetProvider(receiver); + } + } + + private void OnReceiverShutdown(EntityUid uid, ExtensionCableReceiverComponent receiver, ComponentShutdown args) + { + if (receiver.Provider == null) return; + + receiver.Provider.LinkedReceivers.Remove(receiver); + RaiseLocalEvent(uid, new ProviderDisconnectedEvent(receiver.Provider), broadcast: false); + RaiseLocalEvent(receiver.Provider.Owner.Uid, new ReceiverDisconnectedEvent(receiver), broadcast: false); + } + + private void AnchorStateChanged(EntityUid uid, ExtensionCableReceiverComponent receiver, ref AnchorStateChangedEvent args) + { + if (args.Anchored) + { + receiver.Connectable = true; + if (receiver.Provider == null) + { + TryFindAndSetProvider(receiver); + } + } + else + { + receiver.Connectable = false; + RaiseLocalEvent(uid, new ProviderDisconnectedEvent(receiver.Provider), broadcast: false); + + if (receiver.Provider != null) + RaiseLocalEvent(receiver.Provider.Owner.Uid, new ReceiverDisconnectedEvent(receiver), broadcast: false); + + receiver.Provider = null; + } + } + + private void TryFindAndSetProvider(ExtensionCableReceiverComponent receiver) + { + if (!TryFindAvailableProvider(receiver.Owner, receiver.ReceptionRange, out var provider)) return; + + receiver.Provider = provider; + RaiseLocalEvent(receiver.Owner.Uid, new ProviderConnectedEvent(provider), broadcast: false); + RaiseLocalEvent(provider.Owner.Uid, new ReceiverConnectedEvent(receiver), broadcast: false); + } + + private static bool TryFindAvailableProvider(IEntity owner, float range, [NotNullWhen(true)] out ExtensionCableProviderComponent? foundProvider) + { + var nearbyEntities = IoCManager.Resolve() + .GetEntitiesInRange(owner, range); + + foreach (var entity in nearbyEntities) + { + if (!entity.TryGetComponent(out var provider)) continue; + + if (!provider.Connectable) continue; + + if (!entity.Transform.Coordinates.TryDistance(owner.EntityManager, owner.Transform.Coordinates, out var distance)) continue; + + if (!(distance < Math.Min(range, provider.TransferRange))) continue; + + foundProvider = provider; + return true; + } + + foundProvider = default; + return false; + } + + #endregion + + #region Events + + /// + /// Sent when a connects to a + /// + public class ProviderConnectedEvent : EntityEventArgs + { + /// + /// The that connected. + /// + public ExtensionCableProviderComponent Provider; + + public ProviderConnectedEvent(ExtensionCableProviderComponent provider) + { + Provider = provider; + } + } + /// + /// Sent when a disconnects from a + /// + public class ProviderDisconnectedEvent : EntityEventArgs + { + /// + /// The that disconnected. + /// + public ExtensionCableProviderComponent? Provider; + + public ProviderDisconnectedEvent(ExtensionCableProviderComponent? provider) + { + Provider = provider; + } + } + /// + /// Sent when a connects to a + /// + public class ReceiverConnectedEvent : EntityEventArgs + { + /// + /// The that connected. + /// + public ExtensionCableReceiverComponent Receiver; + + public ReceiverConnectedEvent(ExtensionCableReceiverComponent receiver) + { + Receiver = receiver; + } + } + /// + /// Sent when a disconnects from a + /// + public class ReceiverDisconnectedEvent : EntityEventArgs + { + /// + /// The that disconnected. + /// + public ExtensionCableReceiverComponent Receiver; + + public ReceiverDisconnectedEvent(ExtensionCableReceiverComponent receiver) + { + Receiver = receiver; + } + } + + #endregion + } +} diff --git a/Content.Server/Power/EntitySystems/PowerReceiverSystem.cs b/Content.Server/Power/EntitySystems/PowerReceiverSystem.cs index 119e66195c..de39ec242d 100644 --- a/Content.Server/Power/EntitySystems/PowerReceiverSystem.cs +++ b/Content.Server/Power/EntitySystems/PowerReceiverSystem.cs @@ -9,15 +9,43 @@ namespace Content.Server.Power.EntitySystems { base.Initialize(); - SubscribeLocalEvent(BodyTypeChanged); + SubscribeLocalEvent(OnProviderConnected); + SubscribeLocalEvent(OnProviderDisconnected); + + SubscribeLocalEvent(OnReceiverConnected); + SubscribeLocalEvent(OnReceiverDisconnected); } - private static void BodyTypeChanged( - EntityUid uid, - ApcPowerReceiverComponent component, - PhysicsBodyTypeChangedEvent args) + private void OnProviderConnected(EntityUid uid, ApcPowerReceiverComponent receiver, ExtensionCableSystem.ProviderConnectedEvent args) { - component.AnchorUpdate(); + ProviderChanged(receiver); + } + + private void OnProviderDisconnected(EntityUid uid, ApcPowerReceiverComponent receiver, ExtensionCableSystem.ProviderDisconnectedEvent args) + { + ProviderChanged(receiver); + } + + private void OnReceiverConnected(EntityUid uid, ApcPowerProviderComponent provider, ExtensionCableSystem.ReceiverConnectedEvent args) + { + if (EntityManager.TryGetComponent(args.Receiver.Owner.Uid, out ApcPowerReceiverComponent receiver)) + { + provider.AddReceiver(receiver); + } + } + + private void OnReceiverDisconnected(EntityUid uid, ApcPowerProviderComponent provider, ExtensionCableSystem.ReceiverDisconnectedEvent args) + { + if (EntityManager.TryGetComponent(args.Receiver.Owner.Uid, out ApcPowerReceiverComponent receiver)) + { + provider.RemoveReceiver(receiver); + } + } + + private static void ProviderChanged(ApcPowerReceiverComponent receiver) + { + receiver.NetworkLoad.LinkedNetwork = default; + receiver.ApcPowerChanged(); } } } diff --git a/Resources/Prototypes/Entities/Structures/Dispensers/base.yml b/Resources/Prototypes/Entities/Structures/Dispensers/base.yml index 9a6e37cebb..1c41c37989 100644 --- a/Resources/Prototypes/Entities/Structures/Dispensers/base.yml +++ b/Resources/Prototypes/Entities/Structures/Dispensers/base.yml @@ -24,6 +24,7 @@ - MobImpassable - SmallImpassable - type: ApcPowerReceiver + - type: ExtensionCableReceiver - type: UserInterface interfaces: - key: enum.ReagentDispenserUiKey.Key diff --git a/Resources/Prototypes/Entities/Structures/Dispensers/chem.yml b/Resources/Prototypes/Entities/Structures/Dispensers/chem.yml index 57315b8f64..d1f61978fb 100644 --- a/Resources/Prototypes/Entities/Structures/Dispensers/chem.yml +++ b/Resources/Prototypes/Entities/Structures/Dispensers/chem.yml @@ -10,3 +10,4 @@ - type: ReagentDispenser pack: ChemDispenserStandardInventory - type: ApcPowerReceiver + - type: ExtensionCableReceiver diff --git a/Resources/Prototypes/Entities/Structures/Doors/Airlocks/base.yml b/Resources/Prototypes/Entities/Structures/Doors/Airlocks/base.yml index 15077a39ec..adffd0c88f 100644 --- a/Resources/Prototypes/Entities/Structures/Doors/Airlocks/base.yml +++ b/Resources/Prototypes/Entities/Structures/Doors/Airlocks/base.yml @@ -53,6 +53,7 @@ - type: AirlockVisualizer - type: WiresVisualizer - type: ApcPowerReceiver + - type: ExtensionCableReceiver - type: Wires BoardName: "Airlock Control" LayoutId: Airlock diff --git a/Resources/Prototypes/Entities/Structures/Doors/Windoors/base.yml b/Resources/Prototypes/Entities/Structures/Doors/Windoors/base.yml index da746936f7..846a825d54 100644 --- a/Resources/Prototypes/Entities/Structures/Doors/Windoors/base.yml +++ b/Resources/Prototypes/Entities/Structures/Doors/Windoors/base.yml @@ -37,6 +37,7 @@ - state: panel_open map: ["enum.WiresVisualLayers.MaintenancePanel"] - type: ApcPowerReceiver + - type: ExtensionCableReceiver - type: Damageable damageContainer: Inorganic damageModifierSet: Glass diff --git a/Resources/Prototypes/Entities/Structures/Machines/Computers/arcades.yml b/Resources/Prototypes/Entities/Structures/Machines/Computers/arcades.yml index d7fa83e6cc..52de78ffbc 100644 --- a/Resources/Prototypes/Entities/Structures/Machines/Computers/arcades.yml +++ b/Resources/Prototypes/Entities/Structures/Machines/Computers/arcades.yml @@ -6,6 +6,7 @@ parent: ComputerBase components: - type: ApcPowerReceiver + - type: ExtensionCableReceiver - type: PointLight radius: 1.5 energy: 1.6 diff --git a/Resources/Prototypes/Entities/Structures/Machines/Computers/base.yml b/Resources/Prototypes/Entities/Structures/Machines/Computers/base.yml index 8fbbd8446b..3aa6a0466e 100644 --- a/Resources/Prototypes/Entities/Structures/Machines/Computers/base.yml +++ b/Resources/Prototypes/Entities/Structures/Machines/Computers/base.yml @@ -11,6 +11,7 @@ node: computer - type: Computer - type: ApcPowerReceiver + - type: ExtensionCableReceiver - type: Sprite sprite: Structures/Machines/computers.rsi layers: diff --git a/Resources/Prototypes/Entities/Structures/Machines/Computers/computers.yml b/Resources/Prototypes/Entities/Structures/Machines/Computers/computers.yml index 48dbbffd7b..1950c686a7 100644 --- a/Resources/Prototypes/Entities/Structures/Machines/Computers/computers.yml +++ b/Resources/Prototypes/Entities/Structures/Machines/Computers/computers.yml @@ -20,6 +20,7 @@ - type: ShuttleConsole - type: ApcPowerReceiver powerLoad: 200 + - type: ExtensionCableReceiver - type: PointLight radius: 1.5 energy: 1.6 @@ -108,6 +109,7 @@ - type: ApcPowerReceiver powerLoad: 200 priority: Low + - type: ExtensionCableReceiver - type: Computer board: ResearchComputerCircuitboard - type: PointLight diff --git a/Resources/Prototypes/Entities/Structures/Machines/base.yml b/Resources/Prototypes/Entities/Structures/Machines/base.yml index 1085c7fc5f..a7413268d9 100644 --- a/Resources/Prototypes/Entities/Structures/Machines/base.yml +++ b/Resources/Prototypes/Entities/Structures/Machines/base.yml @@ -38,3 +38,4 @@ id: BaseMachinePowered components: - type: ApcPowerReceiver + - type: ExtensionCableReceiver diff --git a/Resources/Prototypes/Entities/Structures/Machines/chem_master.yml b/Resources/Prototypes/Entities/Structures/Machines/chem_master.yml index 31675fc370..0546cca23a 100644 --- a/Resources/Prototypes/Entities/Structures/Machines/chem_master.yml +++ b/Resources/Prototypes/Entities/Structures/Machines/chem_master.yml @@ -17,6 +17,7 @@ state: mixer_loaded - type: ChemMaster - type: ApcPowerReceiver + - type: ExtensionCableReceiver - type: InteractionOutline - type: Anchorable - type: Physics diff --git a/Resources/Prototypes/Entities/Structures/Machines/gravity_generator.yml b/Resources/Prototypes/Entities/Structures/Machines/gravity_generator.yml index ba53d40d67..880a715883 100644 --- a/Resources/Prototypes/Entities/Structures/Machines/gravity_generator.yml +++ b/Resources/Prototypes/Entities/Structures/Machines/gravity_generator.yml @@ -24,6 +24,7 @@ anchored: true - type: ApcPowerReceiver powerLoad: 500 + - type: ExtensionCableReceiver - type: Physics bodyType: Static fixtures: diff --git a/Resources/Prototypes/Entities/Structures/Machines/research.yml b/Resources/Prototypes/Entities/Structures/Machines/research.yml index a0d229a9c8..613c37ab87 100644 --- a/Resources/Prototypes/Entities/Structures/Machines/research.yml +++ b/Resources/Prototypes/Entities/Structures/Machines/research.yml @@ -12,6 +12,7 @@ - type: ApcPowerReceiver powerLoad: 200 priority: Low + - type: ExtensionCableReceiver - type: Destructible thresholds: - trigger: diff --git a/Resources/Prototypes/Entities/Structures/Power/Generation/PA/control_box.yml b/Resources/Prototypes/Entities/Structures/Power/Generation/PA/control_box.yml index 4b003dd5f4..4549a54d38 100644 --- a/Resources/Prototypes/Entities/Structures/Power/Generation/PA/control_box.yml +++ b/Resources/Prototypes/Entities/Structures/Power/Generation/PA/control_box.yml @@ -18,6 +18,7 @@ - type: ParticleAcceleratorPartVisualizer baseState: unlit - type: ApcPowerReceiver + - type: ExtensionCableReceiver - type: ParticleAcceleratorControlBox - type: Construction graph: particleAcceleratorControlBox diff --git a/Resources/Prototypes/Entities/Structures/Power/Generation/ame.yml b/Resources/Prototypes/Entities/Structures/Power/Generation/ame.yml index e7096aa172..ccea996fd6 100644 --- a/Resources/Prototypes/Entities/Structures/Power/Generation/ame.yml +++ b/Resources/Prototypes/Entities/Structures/Power/Generation/ame.yml @@ -62,6 +62,7 @@ !type:CableDeviceNode nodeGroupID: HVPower - type: ApcPowerReceiver + - type: ExtensionCableReceiver - type: PowerSupplier supplyRate: 0 diff --git a/Resources/Prototypes/Entities/Structures/Power/apc.yml b/Resources/Prototypes/Entities/Structures/Power/apc.yml index ff3335bcae..0472f6b509 100644 --- a/Resources/Prototypes/Entities/Structures/Power/apc.yml +++ b/Resources/Prototypes/Entities/Structures/Power/apc.yml @@ -56,6 +56,7 @@ voltage: Apc - type: Apc voltage: Apc + - type: ExtensionCableProvider - type: UserInterface interfaces: - key: enum.ApcUiKey.Key diff --git a/Resources/Prototypes/Entities/Structures/Power/cables.yml b/Resources/Prototypes/Entities/Structures/Power/cables.yml index b3d873de47..75ec4726aa 100644 --- a/Resources/Prototypes/Entities/Structures/Power/cables.yml +++ b/Resources/Prototypes/Entities/Structures/Power/cables.yml @@ -50,9 +50,6 @@ power: !type:CableNode nodeGroupID: HVPower - wire: - !type:AdjacentNode - nodeGroupID: WireNet - type: Cable cableDroppedOnCutPrototype: CableHVStack1 cableType: HighVoltage @@ -93,9 +90,6 @@ power: !type:CableNode nodeGroupID: MVPower - wire: - !type:AdjacentNode - nodeGroupID: WireNet - type: Cable cableDroppedOnCutPrototype: CableMVStack1 cableType: MediumVoltage @@ -136,11 +130,9 @@ power: !type:CableNode nodeGroupID: Apc - wire: - !type:AdjacentNode - nodeGroupID: WireNet - type: PowerProvider voltage: Apc + - type: ExtensionCableProvider - type: Cable cableDroppedOnCutPrototype: CableApcStack1 cableType: Apc diff --git a/Resources/Prototypes/Entities/Structures/Power/chargers.yml b/Resources/Prototypes/Entities/Structures/Power/chargers.yml index bc02c847fa..77dcebc5a2 100644 --- a/Resources/Prototypes/Entities/Structures/Power/chargers.yml +++ b/Resources/Prototypes/Entities/Structures/Power/chargers.yml @@ -12,6 +12,7 @@ - type: PowerCellCharger transfer_efficiency: 0.85 - type: ApcPowerReceiver + - type: ExtensionCableReceiver - type: Appearance visuals: - type: PowerChargerVisualizer @@ -33,6 +34,7 @@ - type: WeaponCapacitorCharger transfer_efficiency: 0.85 - type: ApcPowerReceiver + - type: ExtensionCableReceiver - type: Appearance visuals: - type: PowerChargerVisualizer @@ -54,6 +56,7 @@ - type: WeaponCapacitorCharger transfer_efficiency: 0.95 - type: ApcPowerReceiver + - type: ExtensionCableReceiver - type: Appearance visuals: - type: PowerChargerVisualizer diff --git a/Resources/Prototypes/Entities/Structures/Power/debug_power.yml b/Resources/Prototypes/Entities/Structures/Power/debug_power.yml index 9a79659914..226e95d992 100644 --- a/Resources/Prototypes/Entities/Structures/Power/debug_power.yml +++ b/Resources/Prototypes/Entities/Structures/Power/debug_power.yml @@ -164,4 +164,5 @@ sprite: Structures/Power/power.rsi state: wirelessmachine - type: ApcPowerReceiver + - type: ExtensionCableReceiver - type: Anchorable diff --git a/Resources/Prototypes/Entities/Structures/Wallmounts/Signs/bar_sign.yml b/Resources/Prototypes/Entities/Structures/Wallmounts/Signs/bar_sign.yml index 22301b92bb..158b0d897e 100644 --- a/Resources/Prototypes/Entities/Structures/Wallmounts/Signs/bar_sign.yml +++ b/Resources/Prototypes/Entities/Structures/Wallmounts/Signs/bar_sign.yml @@ -15,6 +15,7 @@ sprite: Structures/Wallmounts/barsign.rsi state: empty - type: ApcPowerReceiver + - type: ExtensionCableReceiver - type: BarSign - type: Destructible thresholds: @@ -38,6 +39,7 @@ sprite: Structures/Wallmounts/sylphs.rsi state: sylph - type: ApcPowerReceiver + - type: ExtensionCableReceiver - type: BarSign - type: entity diff --git a/Resources/Prototypes/Entities/Structures/Wallmounts/emergency_light.yml b/Resources/Prototypes/Entities/Structures/Wallmounts/emergency_light.yml index 285cbad421..2c1a9683f5 100644 --- a/Resources/Prototypes/Entities/Structures/Wallmounts/emergency_light.yml +++ b/Resources/Prototypes/Entities/Structures/Wallmounts/emergency_light.yml @@ -12,6 +12,7 @@ color: "#FF4020" mask: /Textures/Effects/LightMasks/cone.png - type: ApcPowerReceiver + - type: ExtensionCableReceiver - type: Battery maxCharge: 30000 startingCharge: 0 diff --git a/Resources/Prototypes/Entities/Structures/Wallmounts/lighting.yml b/Resources/Prototypes/Entities/Structures/Wallmounts/lighting.yml index b7e14672e1..d5c5cdbe9a 100644 --- a/Resources/Prototypes/Entities/Structures/Wallmounts/lighting.yml +++ b/Resources/Prototypes/Entities/Structures/Wallmounts/lighting.yml @@ -74,6 +74,10 @@ types: Heat: 20 - type: ApcPowerReceiver + - type: ExtensionCableReceiver + - type: DeviceNetworkComponent + deviceNetId: Apc + - type: ApcNetworkConnection - type: Appearance visuals: - type: PoweredLightVisualizer @@ -159,6 +163,10 @@ types: Heat: 20 - type: ApcPowerReceiver + - type: ExtensionCableReceiver + - type: DeviceNetworkComponent + deviceNetId: Apc + - type: ApcNetworkConnection - type: Appearance visuals: - type: PoweredLightVisualizer diff --git a/Resources/Prototypes/Entities/Structures/Wallmounts/switch.yml b/Resources/Prototypes/Entities/Structures/Wallmounts/switch.yml index 710ac85c3c..cd9dfa4f54 100644 --- a/Resources/Prototypes/Entities/Structures/Wallmounts/switch.yml +++ b/Resources/Prototypes/Entities/Structures/Wallmounts/switch.yml @@ -43,3 +43,27 @@ placement: snap: - Wallmount + +- type: entity + id: ApcNetSwitch + name: apc net switch + description: Its a switch for toggling lights that are connected to the same apc. + components: + - type: Clickable + - type: InteractionOutline + - type: Physics + - type: Sprite + sprite: Structures/Wallmounts/switch.rsi + state: on + - type: Rotatable + - type: Construction + graph: lightSwitch + node: lightSwitch + - type: ExtensionCableReceiver + - type: DeviceNetworkComponent + deviceNetId: Apc + - type: ApcNetworkConnection + - type: ApcNetSwitch + placement: + snap: + - Wallmount diff --git a/Resources/Prototypes/Entities/Structures/cargo_telepad.yml b/Resources/Prototypes/Entities/Structures/cargo_telepad.yml index 970cd54270..887a39b7ad 100644 --- a/Resources/Prototypes/Entities/Structures/cargo_telepad.yml +++ b/Resources/Prototypes/Entities/Structures/cargo_telepad.yml @@ -35,4 +35,5 @@ - !type:DoActsBehavior acts: ["Destruction"] - type: ApcPowerReceiver + - type: ExtensionCableReceiver - type: CargoTelepad diff --git a/Resources/Prototypes/Entities/Structures/conveyor.yml b/Resources/Prototypes/Entities/Structures/conveyor.yml index 97b0fc425e..946e8ceeba 100644 --- a/Resources/Prototypes/Entities/Structures/conveyor.yml +++ b/Resources/Prototypes/Entities/Structures/conveyor.yml @@ -31,6 +31,7 @@ type: Content.Shared.MachineLinking.TwoWayLeverSignal maxConnections: 1 - type: ApcPowerReceiver + - type: ExtensionCableReceiver - type: Conveyor - type: Appearance visuals: diff --git a/Resources/Prototypes/Recipes/Construction/Graphs/lighting.yml b/Resources/Prototypes/Recipes/Construction/Graphs/lighting.yml index 6b8b75fcc2..4dc9959ac4 100644 --- a/Resources/Prototypes/Recipes/Construction/Graphs/lighting.yml +++ b/Resources/Prototypes/Recipes/Construction/Graphs/lighting.yml @@ -44,3 +44,27 @@ prototype: SheetSteel1 amount: 1 - !type:DeleteEntity {} + +- type: constructionGraph + id: lightSwitch + start: start + graph: + - node: start + edges: + - to: lightSwitch + steps: + - material: Steel + amount: 1 + doAfter: 2.0 + - node: lightSwitch + entity: ApcNetSwitch + edges: + - to: start + steps: + - tool: Screwing + doAfter: 2.0 + completed: + - !type:SpawnPrototype + prototype: SheetSteel1 + amount: 1 + - !type:DeleteEntity {} diff --git a/Resources/Prototypes/Recipes/Construction/lighting.yml b/Resources/Prototypes/Recipes/Construction/lighting.yml index adf9d8cbff..c910b31805 100644 --- a/Resources/Prototypes/Recipes/Construction/lighting.yml +++ b/Resources/Prototypes/Recipes/Construction/lighting.yml @@ -34,3 +34,22 @@ conditions: - !type:WallmountCondition {} +- type: construction + name: light switch + id: LightSwitchRecipe + graph: lightSwitch + startNode: start + targetNode: lightSwitch + category: Structures + description: A switch for toggling lights that are connected to the same apc. + icon: + sprite: Structures/Wallmounts/switch.rsi + state: on + objectType: Structure + placementMode: SnapgridCenter + canRotate: true + canBuildInImpassable: true + conditions: + - !type:WallmountCondition {} + +