From 7a5a64ffb421ad54fdc5b763a1cfde6ba96276ff Mon Sep 17 00:00:00 2001 From: 0x6273 <0x40@keemail.me> Date: Sun, 28 May 2023 08:44:28 +0200 Subject: [PATCH] Add device linking to emitter and APE (#16805) --- .../EntitySystems/EmitterSystem.cs | 108 +++++++++++------- .../StartSingularityEngineCommand.cs | 19 ++- .../Components/SharedEmitterComponent.cs | 26 +++++ .../en-US/machine-linking/receiver_ports.ftl | 9 ++ .../Prototypes/DeviceLinking/sink_ports.yml | 15 +++ .../Structures/Machines/anomaly_equipment.yml | 17 +++ .../Power/Generation/Singularity/emitter.yml | 10 ++ 7 files changed, 160 insertions(+), 44 deletions(-) diff --git a/Content.Server/Singularity/EntitySystems/EmitterSystem.cs b/Content.Server/Singularity/EntitySystems/EmitterSystem.cs index 72c6be85df..14344091f1 100644 --- a/Content.Server/Singularity/EntitySystems/EmitterSystem.cs +++ b/Content.Server/Singularity/EntitySystems/EmitterSystem.cs @@ -1,10 +1,10 @@ using System.Threading; using Content.Server.Administration.Logs; using Content.Server.Construction; +using Content.Server.DeviceLinking.Events; using Content.Server.Power.Components; using Content.Server.Power.EntitySystems; using Content.Server.Projectiles; -using Content.Server.Storage.Components; using Content.Server.Weapons.Ranged.Systems; using Content.Shared.Database; using Content.Shared.Examine; @@ -50,6 +50,7 @@ namespace Content.Server.Singularity.EntitySystems SubscribeLocalEvent(OnRefreshParts); SubscribeLocalEvent(OnUpgradeExamine); SubscribeLocalEvent(OnAnchorStateChanged); + SubscribeLocalEvent(OnSignalReceived); } private void OnAnchorStateChanged(EntityUid uid, EmitterComponent component, ref AnchorStateChangedEvent args) @@ -57,7 +58,7 @@ namespace Content.Server.Singularity.EntitySystems if (args.Anchored) return; - SwitchOff(component); + SwitchOff(uid, component); } private void OnInteractHand(EntityUid uid, EmitterComponent component, InteractHandEvent args) @@ -65,26 +66,26 @@ namespace Content.Server.Singularity.EntitySystems if (args.Handled) return; - if (EntityManager.TryGetComponent(uid, out LockComponent? lockComp) && lockComp.Locked) + if (TryComp(uid, out LockComponent? lockComp) && lockComp.Locked) { _popup.PopupEntity(Loc.GetString("comp-emitter-access-locked", - ("target", component.Owner)), uid, args.User); + ("target", uid)), uid, args.User); return; } - if (EntityManager.TryGetComponent(component.Owner, out PhysicsComponent? phys) && phys.BodyType == BodyType.Static) + if (TryComp(uid, out PhysicsComponent? phys) && phys.BodyType == BodyType.Static) { if (!component.IsOn) { - SwitchOn(component); + SwitchOn(uid, component); _popup.PopupEntity(Loc.GetString("comp-emitter-turned-on", - ("target", component.Owner)), uid, args.User); + ("target", uid)), uid, args.User); } else { - SwitchOff(component); + SwitchOff(uid, component); _popup.PopupEntity(Loc.GetString("comp-emitter-turned-off", - ("target", component.Owner)), uid, args.User); + ("target", uid)), uid, args.User); } _adminLogger.Add(LogType.Emitter, @@ -95,7 +96,7 @@ namespace Content.Server.Singularity.EntitySystems else { _popup.PopupEntity(Loc.GetString("comp-emitter-not-anchored", - ("target", component.Owner)), uid, args.User); + ("target", uid)), uid, args.User); } } @@ -152,11 +153,11 @@ namespace Content.Server.Singularity.EntitySystems if (args.ReceivedPower < args.DrawRate) { - PowerOff(component); + PowerOff(uid, component); } else { - PowerOn(component); + PowerOn(uid, component); } } @@ -169,11 +170,11 @@ namespace Content.Server.Singularity.EntitySystems if (!args.Powered) { - PowerOff(component); + PowerOff(uid, component); } else { - PowerOn(component); + PowerOn(uid, component); } } @@ -191,33 +192,33 @@ namespace Content.Server.Singularity.EntitySystems args.AddPercentageUpgrade("emitter-component-upgrade-fire-rate", (float) (component.BaseFireInterval.TotalSeconds / component.FireInterval.TotalSeconds)); } - public void SwitchOff(EmitterComponent component) + public void SwitchOff(EntityUid uid, EmitterComponent component) { component.IsOn = false; - if (TryComp(component.Owner, out var powerConsumer)) + if (TryComp(uid, out var powerConsumer)) powerConsumer.DrawRate = 1; // this needs to be not 0 so that the visuals still work. - if (TryComp(component.Owner, out var apcReceiever)) - apcReceiever.Load = 1; - PowerOff(component); - UpdateAppearance(component); + if (TryComp(uid, out var apcReceiver)) + apcReceiver.Load = 1; + PowerOff(uid, component); + UpdateAppearance(uid, component); } - public void SwitchOn(EmitterComponent component) + public void SwitchOn(EntityUid uid, EmitterComponent component) { component.IsOn = true; - if (TryComp(component.Owner, out var powerConsumer)) + if (TryComp(uid, out var powerConsumer)) powerConsumer.DrawRate = component.PowerUseActive; - if (TryComp(component.Owner, out var apcReceiever)) + if (TryComp(uid, out var apcReceiver)) { - apcReceiever.Load = component.PowerUseActive; - PowerOn(component); + apcReceiver.Load = component.PowerUseActive; + PowerOn(uid, component); } // Do not directly PowerOn(). // OnReceivedPowerChanged will get fired due to DrawRate change which will turn it on. - UpdateAppearance(component); + UpdateAppearance(uid, component); } - public void PowerOff(EmitterComponent component) + public void PowerOff(EntityUid uid, EmitterComponent component) { if (!component.IsPowered) { @@ -230,10 +231,10 @@ namespace Content.Server.Singularity.EntitySystems DebugTools.AssertNotNull(component.TimerCancel); component.TimerCancel?.Cancel(); - UpdateAppearance(component); + UpdateAppearance(uid, component); } - public void PowerOn(EmitterComponent component) + public void PowerOn(EntityUid uid, EmitterComponent component) { if (component.IsPowered) { @@ -245,12 +246,12 @@ namespace Content.Server.Singularity.EntitySystems component.FireShotCounter = 0; component.TimerCancel = new CancellationTokenSource(); - Timer.Spawn(component.FireBurstDelayMax, () => ShotTimerCallback(component), component.TimerCancel.Token); + Timer.Spawn(component.FireBurstDelayMax, () => ShotTimerCallback(uid, component), component.TimerCancel.Token); - UpdateAppearance(component); + UpdateAppearance(uid, component); } - private void ShotTimerCallback(EmitterComponent component) + private void ShotTimerCallback(EntityUid uid, EmitterComponent component) { if (component.Deleted) return; @@ -260,7 +261,7 @@ namespace Content.Server.Singularity.EntitySystems DebugTools.Assert(component.IsPowered); DebugTools.Assert(component.IsOn); - Fire(component); + Fire(uid, component); TimeSpan delay; if (component.FireShotCounter < component.FireBurstSize) @@ -278,13 +279,12 @@ namespace Content.Server.Singularity.EntitySystems // Must be set while emitter powered. DebugTools.AssertNotNull(component.TimerCancel); - Timer.Spawn(delay, () => ShotTimerCallback(component), component.TimerCancel!.Token); + Timer.Spawn(delay, () => ShotTimerCallback(uid, component), component.TimerCancel!.Token); } - private void Fire(EmitterComponent component) + private void Fire(EntityUid uid, EmitterComponent component) { - var uid = component.Owner; - if (!TryComp(uid, out var guncomp)) + if (!TryComp(uid, out var gunComponent)) return; var xform = Transform(uid); @@ -293,10 +293,11 @@ namespace Content.Server.Singularity.EntitySystems _projectile.SetShooter(proj, uid); var targetPos = new EntityCoordinates(uid, (0, -1)); - _gun.Shoot(uid, guncomp, ent, xform.Coordinates, targetPos, out _); + + _gun.Shoot(uid, gunComponent, ent, xform.Coordinates, targetPos, out _); } - private void UpdateAppearance(EmitterComponent component) + private void UpdateAppearance(EntityUid uid, EmitterComponent component) { EmitterVisualState state; if (component.IsPowered) @@ -311,7 +312,34 @@ namespace Content.Server.Singularity.EntitySystems { state = EmitterVisualState.Off; } - _appearance.SetData(component.Owner, EmitterVisuals.VisualState, state); + _appearance.SetData(uid, EmitterVisuals.VisualState, state); + } + + private void OnSignalReceived(EntityUid uid, EmitterComponent component, ref SignalReceivedEvent args) + { + if (args.Port == component.OffPort) + { + SwitchOff(uid, component); + } + else if (args.Port == component.OnPort) + { + SwitchOn(uid, component); + } + else if (args.Port == component.TogglePort) + { + if (component.IsOn) + { + SwitchOff(uid, component); + } + else + { + SwitchOn(uid, component); + } + } + else if (component.SetTypePorts.TryGetValue(args.Port, out var boltType)) + { + component.BoltType = boltType; + } } } } diff --git a/Content.Server/Singularity/StartSingularityEngineCommand.cs b/Content.Server/Singularity/StartSingularityEngineCommand.cs index 60befe58a1..c4650a77b3 100644 --- a/Content.Server/Singularity/StartSingularityEngineCommand.cs +++ b/Content.Server/Singularity/StartSingularityEngineCommand.cs @@ -25,14 +25,25 @@ namespace Content.Server.Singularity var entityManager = IoCManager.Resolve(); var entitySystemManager = IoCManager.Resolve(); - foreach (var comp in entityManager.EntityQuery()) + + // Turn on emitters + var emitterQuery = entityManager.EntityQueryEnumerator(); + var emitterSystem = entitySystemManager.GetEntitySystem(); + while (emitterQuery.MoveNext(out var uid, out var emitterComponent)) { - entitySystemManager.GetEntitySystem().SwitchOn(comp); + //FIXME: This turns on ALL emitters, including APEs. It should only turn on the containment field emitters. + emitterSystem.SwitchOn(uid, emitterComponent); } - foreach (var comp in entityManager.EntityQuery()) + + // Turn on radiation collectors + var radiationCollectorQuery = entityManager.EntityQueryEnumerator(); + var radiationCollectorSystem = entitySystemManager.GetEntitySystem(); + while (radiationCollectorQuery.MoveNext(out var uid, out var radiationCollectorComponent)) { - entitySystemManager.GetEntitySystem().SetCollectorEnabled(comp.Owner, true, null, comp); + radiationCollectorSystem.SetCollectorEnabled(uid, enabled: true, user: null, radiationCollectorComponent); } + + // Setup PA foreach (var comp in entityManager.EntityQuery()) { comp.RescanParts(); diff --git a/Content.Shared/Singularity/Components/SharedEmitterComponent.cs b/Content.Shared/Singularity/Components/SharedEmitterComponent.cs index d931f87d6f..b27e9967ff 100644 --- a/Content.Shared/Singularity/Components/SharedEmitterComponent.cs +++ b/Content.Shared/Singularity/Components/SharedEmitterComponent.cs @@ -1,10 +1,12 @@ using System.Threading; using Content.Shared.Construction.Prototypes; +using Content.Shared.DeviceLinking; using Robust.Shared.GameStates; using Robust.Shared.Prototypes; using Robust.Shared.Serialization; using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype; using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype.List; +using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype.Dictionary; namespace Content.Shared.Singularity.Components; @@ -107,6 +109,30 @@ public sealed class EmitterComponent : Component /// [DataField("underpoweredState")] public string? UnderpoweredState = "underpowered"; + + /// + /// Signal port that turns on the emitter. + /// + [DataField("onPort", customTypeSerializer: typeof(PrototypeIdSerializer))] + public string OnPort = "On"; + + /// + /// Signal port that turns off the emitter. + /// + [DataField("offPort", customTypeSerializer: typeof(PrototypeIdSerializer))] + public string OffPort = "Off"; + + /// + /// Signal port that toggles the emitter on or off. + /// + [DataField("togglePort", customTypeSerializer: typeof(PrototypeIdSerializer))] + public string TogglePort = "Toggle"; + + /// + /// Map of signal ports to entity prototype IDs of the entity that will be fired. + /// + [DataField("setTypePorts", customTypeSerializer: typeof(PrototypeIdDictionarySerializer))] + public Dictionary SetTypePorts = new(); } [NetSerializable, Serializable] diff --git a/Resources/Locale/en-US/machine-linking/receiver_ports.ftl b/Resources/Locale/en-US/machine-linking/receiver_ports.ftl index 723a733b31..b5becc5f5d 100644 --- a/Resources/Locale/en-US/machine-linking/receiver_ports.ftl +++ b/Resources/Locale/en-US/machine-linking/receiver_ports.ftl @@ -60,3 +60,12 @@ signal-port-description-artifact-analyzer-sender = Analysis console signal sende signal-port-name-artifact-analyzer-receiver = Pad signal-port-description-artifact-analyzer-receiver = Artifact analyzer signal receiver + +signal-port-name-set-particle-delta = Set particle type: delta +signal-port-description-set-particle-delta = Sets the type of particle this device emits to delta. + +signal-port-name-set-particle-epsilon = Set particle type: epsilon +signal-port-description-set-particle-epsilon = Sets the type of particle this device emits to epsilon. + +signal-port-name-set-particle-zeta = Set particle type: zeta +signal-port-description-set-particle-zeta = Sets the type of particle this device emits to zeta. diff --git a/Resources/Prototypes/DeviceLinking/sink_ports.yml b/Resources/Prototypes/DeviceLinking/sink_ports.yml index b5cd96404e..8a52ebbc0d 100644 --- a/Resources/Prototypes/DeviceLinking/sink_ports.yml +++ b/Resources/Prototypes/DeviceLinking/sink_ports.yml @@ -97,3 +97,18 @@ id: B2 name: "Input B2" description: "Input B2" + +- type: sinkPort + id: SetParticleDelta + name: signal-port-name-set-particle-delta + description: signal-port-description-set-particle-delta + +- type: sinkPort + id: SetParticleEpsilon + name: signal-port-name-set-particle-epsilon + description: signal-port-description-set-particle-epsilon + +- type: sinkPort + id: SetParticleZeta + name: signal-port-name-set-particle-zeta + description: signal-port-description-set-particle-zeta diff --git a/Resources/Prototypes/Entities/Structures/Machines/anomaly_equipment.yml b/Resources/Prototypes/Entities/Structures/Machines/anomaly_equipment.yml index eafa82d1ea..cf220589aa 100644 --- a/Resources/Prototypes/Entities/Structures/Machines/anomaly_equipment.yml +++ b/Resources/Prototypes/Entities/Structures/Machines/anomaly_equipment.yml @@ -151,6 +151,10 @@ - AnomalousParticleDelta - AnomalousParticleEpsilon - AnomalousParticleZeta + setTypePorts: + SetParticleDelta: AnomalousParticleDelta + SetParticleEpsilon: AnomalousParticleEpsilon + SetParticleZeta: AnomalousParticleZeta fireBurstSize: 1 baseFireBurstDelayMin: 2 baseFireBurstDelayMax: 6 @@ -179,6 +183,19 @@ enum.PowerDeviceVisualLayers.Powered: True: { visible: true } False: { visible: false } + - type: DeviceNetwork + deviceNetId: Wireless + receiveFrequencyId: BasicDevice + - type: WirelessNetworkConnection + range: 200 + - type: DeviceLinkSink + ports: + - On + - Off + - Toggle + - SetParticleDelta + - SetParticleEpsilon + - SetParticleZeta - type: entity id: MachineAnomalyGenerator diff --git a/Resources/Prototypes/Entities/Structures/Power/Generation/Singularity/emitter.yml b/Resources/Prototypes/Entities/Structures/Power/Generation/Singularity/emitter.yml index 2a6b5f5449..cec4f98317 100644 --- a/Resources/Prototypes/Entities/Structures/Power/Generation/Singularity/emitter.yml +++ b/Resources/Prototypes/Entities/Structures/Power/Generation/Singularity/emitter.yml @@ -90,3 +90,13 @@ board: EmitterCircuitboard - type: GuideHelp guides: [ Singularity, Power ] + - type: DeviceNetwork + deviceNetId: Wireless + receiveFrequencyId: BasicDevice + - type: WirelessNetworkConnection + range: 200 + - type: DeviceLinkSink + ports: + - On + - Off + - Toggle