diff --git a/Content.Client/GameObjects/Components/Atmos/SiphonVisualizer.cs b/Content.Client/GameObjects/Components/Atmos/SiphonVisualizer.cs new file mode 100644 index 0000000000..07a8c04578 --- /dev/null +++ b/Content.Client/GameObjects/Components/Atmos/SiphonVisualizer.cs @@ -0,0 +1,68 @@ +using Content.Shared.GameObjects.Atmos; +using JetBrains.Annotations; +using Robust.Client.GameObjects; +using Robust.Client.Graphics; +using Robust.Client.Interfaces.GameObjects.Components; +using Robust.Client.Interfaces.ResourceManagement; +using Robust.Client.ResourceManagement; +using Robust.Shared.GameObjects.Components.Renderable; +using Robust.Shared.IoC; +using Robust.Shared.Log; +using Robust.Shared.Utility; +using System; +using YamlDotNet.RepresentationModel; + +namespace Content.Client.GameObjects.Components.Atmos +{ + [UsedImplicitly] + public class SiphonVisualizer : AppearanceVisualizer + { + private RSI _siphonRSI; + + public override void LoadData(YamlMappingNode node) + { + base.LoadData(node); + + var rsiString = node.GetNode("siphonRSI").ToString(); + var rsiPath = SharedSpriteComponent.TextureRoot / rsiString; + try + { + var resourceCache = IoCManager.Resolve(); + var resource = resourceCache.GetResource(rsiPath); + _siphonRSI = resource.RSI; + } + catch (Exception e) + { + Logger.ErrorS("go.siphonvisualizer", "Unable to load RSI '{0}'. Trace:\n{1}", rsiPath, e); + } + } + + public override void OnChangeData(AppearanceComponent component) + { + base.OnChangeData(component); + + if (!component.Owner.TryGetComponent(out ISpriteComponent sprite)) + { + return; + } + if (!component.TryGetData(SiphonVisuals.VisualState, out SiphonVisualState siphonVisualState)) + { + return; + } + + var siphonBaseState = "scrub"; + siphonBaseState += siphonVisualState.SiphonEnabled ? "On" : "Off"; + + sprite.LayerMapReserveBlank(Layer.SiphonBase); + var baseSiphonLayer = sprite.LayerMapGet(Layer.SiphonBase); + sprite.LayerSetRSI(baseSiphonLayer, _siphonRSI); + sprite.LayerSetState(baseSiphonLayer, siphonBaseState); + sprite.LayerSetVisible(baseSiphonLayer, true); + } + + private enum Layer + { + SiphonBase, + } + } +} diff --git a/Content.Client/GameObjects/Components/Atmos/VentVisualizer.cs b/Content.Client/GameObjects/Components/Atmos/VentVisualizer.cs new file mode 100644 index 0000000000..a30b2b9f9d --- /dev/null +++ b/Content.Client/GameObjects/Components/Atmos/VentVisualizer.cs @@ -0,0 +1,68 @@ +using Content.Shared.GameObjects.Atmos; +using JetBrains.Annotations; +using Robust.Client.GameObjects; +using Robust.Client.Graphics; +using Robust.Client.Interfaces.GameObjects.Components; +using Robust.Client.Interfaces.ResourceManagement; +using Robust.Client.ResourceManagement; +using Robust.Shared.GameObjects.Components.Renderable; +using Robust.Shared.IoC; +using Robust.Shared.Log; +using Robust.Shared.Utility; +using System; +using YamlDotNet.RepresentationModel; + +namespace Content.Client.GameObjects.Components.Atmos +{ + [UsedImplicitly] + public class VentVisualizer : AppearanceVisualizer + { + private RSI _ventRSI; + + public override void LoadData(YamlMappingNode node) + { + base.LoadData(node); + + var rsiString = node.GetNode("ventRSI").ToString(); + var rsiPath = SharedSpriteComponent.TextureRoot / rsiString; + try + { + var resourceCache = IoCManager.Resolve(); + var resource = resourceCache.GetResource(rsiPath); + _ventRSI = resource.RSI; + } + catch (Exception e) + { + Logger.ErrorS("go.ventvisualizer", "Unable to load RSI '{0}'. Trace:\n{1}", rsiPath, e); + } + } + + public override void OnChangeData(AppearanceComponent component) + { + base.OnChangeData(component); + + if (!component.Owner.TryGetComponent(out ISpriteComponent sprite)) + { + return; + } + if (!component.TryGetData(VentVisuals.VisualState, out VentVisualState ventVisualState)) + { + return; + } + + var ventBaseState = "vent"; + ventBaseState += ventVisualState.VentEnabled ? "On" : "Off"; + + sprite.LayerMapReserveBlank(Layer.VentBase); + var baseVentLayer = sprite.LayerMapGet(Layer.VentBase); + sprite.LayerSetRSI(baseVentLayer, _ventRSI); + sprite.LayerSetState(baseVentLayer, ventBaseState); + sprite.LayerSetVisible(baseVentLayer, true); + } + + private enum Layer + { + VentBase, + } + } +} diff --git a/Content.Server/GameObjects/Components/Atmos/Piping/Scrubbers/BaseSiphonComponent.cs b/Content.Server/GameObjects/Components/Atmos/Piping/Scrubbers/BaseSiphonComponent.cs index da90efdad2..921a7c92be 100644 --- a/Content.Server/GameObjects/Components/Atmos/Piping/Scrubbers/BaseSiphonComponent.cs +++ b/Content.Server/GameObjects/Components/Atmos/Piping/Scrubbers/BaseSiphonComponent.cs @@ -2,6 +2,8 @@ using Content.Server.GameObjects.Components.NodeContainer; using Content.Server.GameObjects.Components.NodeContainer.Nodes; using Content.Server.GameObjects.EntitySystems; +using Content.Shared.GameObjects.Atmos; +using Robust.Server.GameObjects; using Robust.Shared.GameObjects.Systems; using Robust.Shared.Log; using Robust.Shared.ViewVariables; @@ -23,6 +25,20 @@ namespace Content.Server.GameObjects.Components.Atmos.Piping private AtmosphereSystem _atmosSystem; + [ViewVariables(VVAccess.ReadWrite)] + public bool SiphonEnabled + { + get => _siphonEnabled; + set + { + _siphonEnabled = value; + UpdateAppearance(); + } + } + private bool _siphonEnabled = true; + + private AppearanceComponent _appearance; + public override void Initialize() { base.Initialize(); @@ -40,10 +56,15 @@ namespace Content.Server.GameObjects.Components.Atmos.Piping Logger.Error($"{typeof(BaseSiphonComponent)} on entity {Owner.Uid} could not find compatible {nameof(PipeNode)}s on its {nameof(NodeContainerComponent)}."); return; } + Owner.TryGetComponent(out _appearance); + UpdateAppearance(); } public override void Update() { + if (!SiphonEnabled) + return; + var tileAtmos = Owner.Transform.Coordinates.GetTileAtmosphere(_entityManager); if (tileAtmos == null) return; @@ -52,5 +73,10 @@ namespace Content.Server.GameObjects.Components.Atmos.Piping } protected abstract void ScrubGas(GasMixture inletGas, GasMixture outletGas); + + private void UpdateAppearance() + { + _appearance?.SetData(SiphonVisuals.VisualState, new SiphonVisualState(SiphonEnabled)); + } } } diff --git a/Content.Server/GameObjects/Components/Atmos/Piping/Vents/BaseVentComponent.cs b/Content.Server/GameObjects/Components/Atmos/Piping/Vents/BaseVentComponent.cs index a9240c3556..8176cdd315 100644 --- a/Content.Server/GameObjects/Components/Atmos/Piping/Vents/BaseVentComponent.cs +++ b/Content.Server/GameObjects/Components/Atmos/Piping/Vents/BaseVentComponent.cs @@ -2,6 +2,8 @@ using Content.Server.GameObjects.Components.NodeContainer; using Content.Server.GameObjects.Components.NodeContainer.Nodes; using Content.Server.GameObjects.EntitySystems; +using Content.Shared.GameObjects.Atmos; +using Robust.Server.GameObjects; using Robust.Shared.GameObjects.Systems; using Robust.Shared.Log; using Robust.Shared.ViewVariables; @@ -23,6 +25,20 @@ namespace Content.Server.GameObjects.Components.Atmos.Piping private AtmosphereSystem _atmosSystem; + [ViewVariables(VVAccess.ReadWrite)] + public bool VentEnabled + { + get => _ventEnabled; + set + { + _ventEnabled = value; + UpdateAppearance(); + } + } + private bool _ventEnabled = true; + + private AppearanceComponent _appearance; + public override void Initialize() { base.Initialize(); @@ -40,10 +56,15 @@ namespace Content.Server.GameObjects.Components.Atmos.Piping Logger.Error($"{typeof(BaseVentComponent)} on entity {Owner.Uid} could not find compatible {nameof(PipeNode)}s on its {nameof(NodeContainerComponent)}."); return; } + Owner.TryGetComponent(out _appearance); + UpdateAppearance(); } public override void Update() { + if (!VentEnabled) + return; + var tileAtmos = Owner.Transform.Coordinates.GetTileAtmosphere(_entityManager); if (tileAtmos == null) return; @@ -52,5 +73,10 @@ namespace Content.Server.GameObjects.Components.Atmos.Piping } protected abstract void VentGas(GasMixture inletGas, GasMixture outletGas); + + private void UpdateAppearance() + { + _appearance?.SetData(VentVisuals.VisualState, new VentVisualState(VentEnabled)); + } } } diff --git a/Content.Shared/GameObjects/Atmos/SharedSiphonComponent.cs b/Content.Shared/GameObjects/Atmos/SharedSiphonComponent.cs new file mode 100644 index 0000000000..39be0e6ca7 --- /dev/null +++ b/Content.Shared/GameObjects/Atmos/SharedSiphonComponent.cs @@ -0,0 +1,22 @@ +using Robust.Shared.Serialization; +using System; + +namespace Content.Shared.GameObjects.Atmos +{ + [Serializable, NetSerializable] + public enum SiphonVisuals + { + VisualState + } + + [Serializable, NetSerializable] + public class SiphonVisualState + { + public readonly bool SiphonEnabled; + + public SiphonVisualState(bool siphonEnabled) + { + SiphonEnabled = siphonEnabled; + } + } +} diff --git a/Content.Shared/GameObjects/Atmos/SharedVentComponent.cs b/Content.Shared/GameObjects/Atmos/SharedVentComponent.cs new file mode 100644 index 0000000000..03c7d9d320 --- /dev/null +++ b/Content.Shared/GameObjects/Atmos/SharedVentComponent.cs @@ -0,0 +1,22 @@ +using Robust.Shared.Serialization; +using System; + +namespace Content.Shared.GameObjects.Atmos +{ + [Serializable, NetSerializable] + public enum VentVisuals + { + VisualState + } + + [Serializable, NetSerializable] + public class VentVisualState + { + public readonly bool VentEnabled; + + public VentVisualState(bool ventEnabled) + { + VentEnabled = ventEnabled; + } + } +} diff --git a/Resources/Prototypes/Entities/Constructible/Ground/scrubbers.yml b/Resources/Prototypes/Entities/Constructible/Ground/scrubbers.yml index 2372c3e65d..2dc4f1f3e9 100644 --- a/Resources/Prototypes/Entities/Constructible/Ground/scrubbers.yml +++ b/Resources/Prototypes/Entities/Constructible/Ground/scrubbers.yml @@ -12,7 +12,12 @@ - type: Icon texture: Constructible/Power/eightdirwire.png - type: Sprite - texture: Constructible/Power/eightdirwire.png + - type: Appearance + visuals: + - type: PipeVisualizer + pipeRSI: Constructible/Atmos/pipe.rsi + - type: SiphonVisualizer + siphonRSI: Constructible/Atmos/scrubber.rsi - type: Destructible thresholdvalue: 100 diff --git a/Resources/Prototypes/Entities/Constructible/Ground/vents.yml b/Resources/Prototypes/Entities/Constructible/Ground/vents.yml index 2940ec1b08..4c02001688 100644 --- a/Resources/Prototypes/Entities/Constructible/Ground/vents.yml +++ b/Resources/Prototypes/Entities/Constructible/Ground/vents.yml @@ -12,7 +12,12 @@ - type: Icon texture: Constructible/Power/eightdirwire.png - type: Sprite - texture: Constructible/Power/eightdirwire.png + - type: Appearance + visuals: + - type: PipeVisualizer + pipeRSI: Constructible/Atmos/pipe.rsi + - type: VentVisualizer + ventRSI: Constructible/Atmos/vent.rsi - type: Destructible thresholdvalue: 100 diff --git a/Resources/Textures/Constructible/Atmos/scrubber.rsi/meta.json b/Resources/Textures/Constructible/Atmos/scrubber.rsi/meta.json new file mode 100644 index 0000000000..2feeef5cfa --- /dev/null +++ b/Resources/Textures/Constructible/Atmos/scrubber.rsi/meta.json @@ -0,0 +1,48 @@ +{ + "version":1, + "size":{ + "x":32, + "y":32 + }, + "license":"CC-BY-SA-3.0", + "copyright":"Taken from https://github.com/tgstation/tgstation at commit 57cd1d59ca019dd0e7811ac451f295f818e573da", + "states":[ + { + "name":"scrubOff", + "directions":1, + "delays":[ [ 1.0 ] ] + }, + { + "name":"scrubOn", + "directions":1, + "delays":[ + [ + 0.08, + 0.08, + 0.08, + 0.08, + 0.08, + 0.08, + 0.08, + 0.08, + 0.08, + 0.08, + 0.08, + 0.08, + 0.08, + 0.08, + 0.08, + 0.08, + 0.08, + 0.08, + 0.08, + 0.08, + 0.08, + 0.08, + 0.08, + 0.08 + ] + ] + } + ] +} diff --git a/Resources/Textures/Constructible/Atmos/scrubber.rsi/scrubOff.png b/Resources/Textures/Constructible/Atmos/scrubber.rsi/scrubOff.png new file mode 100644 index 0000000000..c4b16c7d0e Binary files /dev/null and b/Resources/Textures/Constructible/Atmos/scrubber.rsi/scrubOff.png differ diff --git a/Resources/Textures/Constructible/Atmos/scrubber.rsi/scrubOn.png b/Resources/Textures/Constructible/Atmos/scrubber.rsi/scrubOn.png new file mode 100644 index 0000000000..06a975cc5a Binary files /dev/null and b/Resources/Textures/Constructible/Atmos/scrubber.rsi/scrubOn.png differ diff --git a/Resources/Textures/Constructible/Atmos/vent.rsi/meta.json b/Resources/Textures/Constructible/Atmos/vent.rsi/meta.json new file mode 100644 index 0000000000..b5dbb04a19 --- /dev/null +++ b/Resources/Textures/Constructible/Atmos/vent.rsi/meta.json @@ -0,0 +1,28 @@ +{ + "version":1, + "size":{ + "x":32, + "y":32 + }, + "license":"CC-BY-SA-3.0", + "copyright":"Taken from https://github.com/tgstation/tgstation at commit 57cd1d59ca019dd0e7811ac451f295f818e573da", + "states":[ + { + "name":"ventOff", + "directions":1, + "delays":[ [ 1.0 ] ] + }, + { + "name":"ventOn", + "directions":1, + "delays":[ + [ + 0.08, + 0.08, + 0.08, + 0.08 + ] + ] + } + ] +} \ No newline at end of file diff --git a/Resources/Textures/Constructible/Atmos/vent.rsi/ventOff.png b/Resources/Textures/Constructible/Atmos/vent.rsi/ventOff.png new file mode 100644 index 0000000000..e8e469dc4b Binary files /dev/null and b/Resources/Textures/Constructible/Atmos/vent.rsi/ventOff.png differ diff --git a/Resources/Textures/Constructible/Atmos/vent.rsi/ventOn.png b/Resources/Textures/Constructible/Atmos/vent.rsi/ventOn.png new file mode 100644 index 0000000000..33d42b8b10 Binary files /dev/null and b/Resources/Textures/Constructible/Atmos/vent.rsi/ventOn.png differ