From 009087863f4a418e032178d96981460d95906e41 Mon Sep 17 00:00:00 2001 From: Vera Aguilera Puerto <6766154+Zumorica@users.noreply.github.com> Date: Mon, 2 Aug 2021 13:59:41 +0200 Subject: [PATCH] AtmosDevices can optionally process in space. (#4405) Refactors some misc atmos things, too. --- .../Atmos/Commands/AddAtmosCommand.cs | 2 +- .../Commands/AddUnsimulatedAtmosCommand.cs | 2 +- .../Components/GridAtmosphereComponent.cs | 4 +- ...reComponent.cs => IAtmosphereComponent.cs} | 2 +- .../Components/SpaceAtmosphereComponent.cs | 13 ++++ .../SpaceGridAtmosphereComponent.cs | 16 ---- .../UnsimulatedGridAtmosphereComponent.cs | 5 +- .../EntitySystems/AtmosphereSystem.Grid.cs | 16 +++- .../AtmosphereSystem.Processing.cs | 6 +- .../Atmos/EntitySystems/AtmosphereSystem.cs | 13 ---- .../Piping/Components/AtmosDeviceComponent.cs | 15 +++- .../Piping/EntitySystems/AtmosDeviceSystem.cs | 56 ++++++++++++-- .../Structures/Storage/Canisters/base.yml | 72 ------------------ .../Storage/Canisters/gas_canisters.yml | 74 +++++++++++++++++++ 14 files changed, 176 insertions(+), 120 deletions(-) rename Content.Server/Atmos/Components/{IGridAtmosphereComponent.cs => IAtmosphereComponent.cs} (79%) create mode 100644 Content.Server/Atmos/Components/SpaceAtmosphereComponent.cs delete mode 100644 Content.Server/Atmos/Components/SpaceGridAtmosphereComponent.cs delete mode 100644 Resources/Prototypes/Entities/Structures/Storage/Canisters/base.yml diff --git a/Content.Server/Atmos/Commands/AddAtmosCommand.cs b/Content.Server/Atmos/Commands/AddAtmosCommand.cs index 4759998b1a..69c85997f5 100644 --- a/Content.Server/Atmos/Commands/AddAtmosCommand.cs +++ b/Content.Server/Atmos/Commands/AddAtmosCommand.cs @@ -47,7 +47,7 @@ namespace Content.Server.Atmos.Commands return; } - if (grid.HasComponent()) + if (grid.HasComponent()) { shell.WriteLine("Grid already has an atmosphere."); return; diff --git a/Content.Server/Atmos/Commands/AddUnsimulatedAtmosCommand.cs b/Content.Server/Atmos/Commands/AddUnsimulatedAtmosCommand.cs index 67541a5361..5fb659cc59 100644 --- a/Content.Server/Atmos/Commands/AddUnsimulatedAtmosCommand.cs +++ b/Content.Server/Atmos/Commands/AddUnsimulatedAtmosCommand.cs @@ -47,7 +47,7 @@ namespace Content.Server.Atmos.Commands return; } - if (grid.HasComponent()) + if (grid.HasComponent()) { shell.WriteLine("Grid already has an atmosphere."); return; diff --git a/Content.Server/Atmos/Components/GridAtmosphereComponent.cs b/Content.Server/Atmos/Components/GridAtmosphereComponent.cs index 53670f8d05..fedac5c2dd 100644 --- a/Content.Server/Atmos/Components/GridAtmosphereComponent.cs +++ b/Content.Server/Atmos/Components/GridAtmosphereComponent.cs @@ -16,9 +16,9 @@ namespace Content.Server.Atmos.Components /// /// This is our SSAir equivalent. /// - [ComponentReference(typeof(IGridAtmosphereComponent))] + [ComponentReference(typeof(IAtmosphereComponent))] [RegisterComponent, Serializable] - public class GridAtmosphereComponent : Component, IGridAtmosphereComponent, ISerializationHooks + public class GridAtmosphereComponent : Component, IAtmosphereComponent, ISerializationHooks { public override string Name => "GridAtmosphere"; public virtual bool Simulated => true; diff --git a/Content.Server/Atmos/Components/IGridAtmosphereComponent.cs b/Content.Server/Atmos/Components/IAtmosphereComponent.cs similarity index 79% rename from Content.Server/Atmos/Components/IGridAtmosphereComponent.cs rename to Content.Server/Atmos/Components/IAtmosphereComponent.cs index 11b953b2fa..8e9bfb8abb 100644 --- a/Content.Server/Atmos/Components/IGridAtmosphereComponent.cs +++ b/Content.Server/Atmos/Components/IAtmosphereComponent.cs @@ -2,7 +2,7 @@ namespace Content.Server.Atmos.Components { - public interface IGridAtmosphereComponent : IComponent + public interface IAtmosphereComponent : IComponent { /// /// Whether this atmosphere is simulated or not. diff --git a/Content.Server/Atmos/Components/SpaceAtmosphereComponent.cs b/Content.Server/Atmos/Components/SpaceAtmosphereComponent.cs new file mode 100644 index 0000000000..3d42d24762 --- /dev/null +++ b/Content.Server/Atmos/Components/SpaceAtmosphereComponent.cs @@ -0,0 +1,13 @@ +using Robust.Shared.GameObjects; + +namespace Content.Server.Atmos.Components +{ + [RegisterComponent] + [ComponentReference(typeof(IAtmosphereComponent))] + public class SpaceAtmosphereComponent : Component, IAtmosphereComponent + { + public override string Name => "SpaceAtmosphere"; + + public bool Simulated => false; + } +} diff --git a/Content.Server/Atmos/Components/SpaceGridAtmosphereComponent.cs b/Content.Server/Atmos/Components/SpaceGridAtmosphereComponent.cs deleted file mode 100644 index 6fa75f774d..0000000000 --- a/Content.Server/Atmos/Components/SpaceGridAtmosphereComponent.cs +++ /dev/null @@ -1,16 +0,0 @@ -using System.Collections.Generic; -using System.Linq; -using Content.Shared.Atmos; -using Robust.Shared.GameObjects; -using Robust.Shared.Map; -using Robust.Shared.Maths; - -namespace Content.Server.Atmos.Components -{ - [RegisterComponent] - [ComponentReference(typeof(IGridAtmosphereComponent))] - public class SpaceGridAtmosphereComponent : UnsimulatedGridAtmosphereComponent - { - public override string Name => "SpaceGridAtmosphere"; - } -} diff --git a/Content.Server/Atmos/Components/UnsimulatedGridAtmosphereComponent.cs b/Content.Server/Atmos/Components/UnsimulatedGridAtmosphereComponent.cs index 806164e6c1..a01d98c1da 100644 --- a/Content.Server/Atmos/Components/UnsimulatedGridAtmosphereComponent.cs +++ b/Content.Server/Atmos/Components/UnsimulatedGridAtmosphereComponent.cs @@ -8,10 +8,9 @@ using Robust.Shared.Maths; namespace Content.Server.Atmos.Components { [RegisterComponent] - [ComponentReference(typeof(IGridAtmosphereComponent))] - [ComponentReference(typeof(GridAtmosphereComponent))] + [ComponentReference(typeof(IAtmosphereComponent))] [Serializable] - public class UnsimulatedGridAtmosphereComponent : GridAtmosphereComponent, IGridAtmosphereComponent + public class UnsimulatedGridAtmosphereComponent : GridAtmosphereComponent { public override string Name => "UnsimulatedGridAtmosphere"; diff --git a/Content.Server/Atmos/EntitySystems/AtmosphereSystem.Grid.cs b/Content.Server/Atmos/EntitySystems/AtmosphereSystem.Grid.cs index 661b5b169f..9f09ce4e41 100644 --- a/Content.Server/Atmos/EntitySystems/AtmosphereSystem.Grid.cs +++ b/Content.Server/Atmos/EntitySystems/AtmosphereSystem.Grid.cs @@ -117,6 +117,10 @@ namespace Content.Server.Atmos.EntitySystems /// All tile mixtures in a grid. public IEnumerable GetAllTileMixtures(GridId grid, bool invalidate = false) { + // Return an array with a single space gas mixture for invalid grids. + if (!grid.IsValid()) + return new []{ GasMixture.SpaceGas }; + if (!_mapManager.TryGetGrid(grid, out var mapGrid)) return Enumerable.Empty(); @@ -678,6 +682,10 @@ namespace Content.Server.Atmos.EntitySystems /// The tile mixture, or null public GasMixture? GetTileMixture(GridId grid, Vector2i tile, bool invalidate = false) { + // Always return space gas mixtures for invalid grids (grid 0) + if (!grid.IsValid()) + return GasMixture.SpaceGas; + if (!_mapManager.TryGetGrid(grid, out var mapGrid)) return null; @@ -686,7 +694,7 @@ namespace Content.Server.Atmos.EntitySystems return GetTileMixture(gridAtmosphere, tile, invalidate); } - if (ComponentManager.TryGetComponent(mapGrid.GridEntityId, out SpaceGridAtmosphereComponent? spaceAtmosphere)) + if (ComponentManager.TryGetComponent(mapGrid.GridEntityId, out SpaceAtmosphereComponent? _)) { // Always return a new space gas mixture in this case. return GasMixture.SpaceGas; @@ -967,6 +975,10 @@ namespace Content.Server.Atmos.EntitySystems /// All adjacent tile gas mixtures to the tile in question public IEnumerable GetAdjacentTileMixtures(GridId grid, Vector2i tile, bool includeBlocked = false, bool invalidate = false) { + // For invalid grids, return an array with a single space gas mixture in it. + if (!grid.IsValid()) + return new []{ GasMixture.SpaceGas }; + if (!_mapManager.TryGetGrid(grid, out var mapGrid)) return Enumerable.Empty(); @@ -1374,7 +1386,7 @@ namespace Content.Server.Atmos.EntitySystems return false; if (ComponentManager.TryGetComponent(mapGrid.GridEntityId, out GridAtmosphereComponent? gridAtmosphere) - && gridAtmosphere.AtmosDevices.Contains(atmosDevice)) + && gridAtmosphere.AtmosDevices.Contains(atmosDevice)) { atmosDevice.JoinedGrid = null; gridAtmosphere.AtmosDevices.Remove(atmosDevice); diff --git a/Content.Server/Atmos/EntitySystems/AtmosphereSystem.Processing.cs b/Content.Server/Atmos/EntitySystems/AtmosphereSystem.Processing.cs index db87ed7c10..e02f81e0ca 100644 --- a/Content.Server/Atmos/EntitySystems/AtmosphereSystem.Processing.cs +++ b/Content.Server/Atmos/EntitySystems/AtmosphereSystem.Processing.cs @@ -14,6 +14,7 @@ namespace Content.Server.Atmos.EntitySystems { [Dependency] private readonly IGameTiming _gameTiming = default!; + private readonly AtmosDeviceUpdateEvent _updateEvent = new(); private readonly Stopwatch _simulationStopwatch = new(); /// @@ -204,11 +205,10 @@ namespace Content.Server.Atmos.EntitySystems atmosphere.CurrentRunAtmosDevices = new Queue(atmosphere.AtmosDevices); var time = _gameTiming.CurTime; - var updateEvent = new AtmosDeviceUpdateEvent(); var number = 0; while (atmosphere.CurrentRunAtmosDevices.TryDequeue(out var device)) { - EntityManager.EventBus.RaiseLocalEvent(device.Owner.Uid, updateEvent, false); + RaiseLocalEvent(device.Owner.Uid, _updateEvent, false); device.LastProcess = time; if (number++ < LagCheckIterations) continue; @@ -241,7 +241,7 @@ namespace Content.Server.Atmos.EntitySystems { var atmosphere = _currentRunAtmosphere[_currentRunAtmosphereIndex]; - if (atmosphere.Paused || atmosphere.LifeStage >= ComponentLifeStage.Stopping) + if (atmosphere.Paused || !atmosphere.Simulated || atmosphere.LifeStage >= ComponentLifeStage.Stopping) continue; atmosphere.Timer += frameTime; diff --git a/Content.Server/Atmos/EntitySystems/AtmosphereSystem.cs b/Content.Server/Atmos/EntitySystems/AtmosphereSystem.cs index 910ae05a51..8588417ad2 100644 --- a/Content.Server/Atmos/EntitySystems/AtmosphereSystem.cs +++ b/Content.Server/Atmos/EntitySystems/AtmosphereSystem.cs @@ -29,7 +29,6 @@ namespace Content.Server.Atmos.EntitySystems #region Events // Map events. - _mapManager.MapCreated += OnMapCreated; _mapManager.TileChanged += OnTileChanged; #endregion @@ -39,7 +38,6 @@ namespace Content.Server.Atmos.EntitySystems { base.Shutdown(); - _mapManager.MapCreated -= OnMapCreated; _mapManager.TileChanged -= OnTileChanged; } @@ -57,17 +55,6 @@ namespace Content.Server.Atmos.EntitySystems InvalidateTile(eventArgs.NewTile.GridIndex, eventArgs.NewTile.GridIndices); } - private void OnMapCreated(object? sender, MapEventArgs e) - { - if (e.Map == MapId.Nullspace) - return; - - var map = _mapManager.GetMapEntity(e.Map); - - if (!map.HasComponent()) - map.AddComponent(); - } - public override void Update(float frameTime) { base.Update(frameTime); diff --git a/Content.Server/Atmos/Piping/Components/AtmosDeviceComponent.cs b/Content.Server/Atmos/Piping/Components/AtmosDeviceComponent.cs index 9b535e7e01..00c36df4e0 100644 --- a/Content.Server/Atmos/Piping/Components/AtmosDeviceComponent.cs +++ b/Content.Server/Atmos/Piping/Components/AtmosDeviceComponent.cs @@ -8,7 +8,7 @@ using Robust.Shared.ViewVariables; namespace Content.Server.Atmos.Piping.Components { /// - /// Adds itself to a to be updated by. + /// Adds itself to a to be updated by. /// [RegisterComponent] public class AtmosDeviceComponent : Component @@ -22,6 +22,19 @@ namespace Content.Server.Atmos.Piping.Components [DataField("requireAnchored")] public bool RequireAnchored { get; private set; } = true; + /// + /// Whether this device will join an entity system to process when not in a grid. + /// + [ViewVariables] + [DataField("joinSystem")] + public bool JoinSystem { get; } = false; + + /// + /// Whether we have joined an entity system to process. + /// + [ViewVariables] + public bool JoinedSystem { get; set; } = false; + [ViewVariables] public TimeSpan LastProcess { get; set; } = TimeSpan.Zero; diff --git a/Content.Server/Atmos/Piping/EntitySystems/AtmosDeviceSystem.cs b/Content.Server/Atmos/Piping/EntitySystems/AtmosDeviceSystem.cs index 166a4d07b8..12d98e8ff2 100644 --- a/Content.Server/Atmos/Piping/EntitySystems/AtmosDeviceSystem.cs +++ b/Content.Server/Atmos/Piping/EntitySystems/AtmosDeviceSystem.cs @@ -1,10 +1,10 @@ using System; +using System.Collections.Generic; using Content.Server.Atmos.EntitySystems; using Content.Server.Atmos.Piping.Components; using JetBrains.Annotations; using Robust.Shared.GameObjects; using Robust.Shared.IoC; -using Robust.Shared.Physics; using Robust.Shared.Timing; namespace Content.Server.Atmos.Piping.EntitySystems @@ -12,9 +12,14 @@ namespace Content.Server.Atmos.Piping.EntitySystems [UsedImplicitly] public class AtmosDeviceSystem : EntitySystem { - [Dependency] private IGameTiming _gameTiming = default!; + [Dependency] private readonly IGameTiming _gameTiming = default!; [Dependency] private readonly AtmosphereSystem _atmosphereSystem = default!; + private readonly AtmosDeviceUpdateEvent _updateEvent = new(); + + private float _timer = 0f; + private readonly HashSet _joinedDevices = new(); + public override void Initialize() { base.Initialize(); @@ -33,11 +38,24 @@ namespace Content.Server.Atmos.Piping.EntitySystems public void JoinAtmosphere(AtmosDeviceComponent component) { if (!CanJoinAtmosphere(component)) + { return; + } - // We try to add the device to a valid atmosphere. + // We try to add the device to a valid atmosphere, and if we can't, try to add it to the entity system. if (!_atmosphereSystem.AddAtmosDevice(component)) - return; + { + if (component.JoinSystem) + { + _joinedDevices.Add(component); + component.JoinedSystem = true; + } + else + { + return; + } + } + component.LastProcess = _gameTiming.CurTime; @@ -46,8 +64,19 @@ namespace Content.Server.Atmos.Piping.EntitySystems public void LeaveAtmosphere(AtmosDeviceComponent component) { - if (!_atmosphereSystem.RemoveAtmosDevice(component)) + // Try to remove the component from an atmosphere, and if not + if (component.JoinedGrid != null && !_atmosphereSystem.RemoveAtmosDevice(component)) + { + // The grid might have been removed but not us... This usually shouldn't happen. + component.JoinedGrid = null; return; + } + + if (component.JoinedSystem) + { + _joinedDevices.Remove(component); + component.JoinedSystem = false; + } component.LastProcess = TimeSpan.Zero; RaiseLocalEvent(component.Owner.Uid, new AtmosDeviceDisabledEvent(), false); @@ -85,5 +114,22 @@ namespace Content.Server.Atmos.Piping.EntitySystems { RejoinAtmosphere(component); } + + public override void Update(float frameTime) + { + _timer += frameTime; + + if (_timer < _atmosphereSystem.AtmosTime) + return; + + _timer -= _atmosphereSystem.AtmosTime; + + var time = _gameTiming.CurTime; + foreach (var device in _joinedDevices) + { + RaiseLocalEvent(device.Owner.Uid, _updateEvent, false); + device.LastProcess = time; + } + } } } diff --git a/Resources/Prototypes/Entities/Structures/Storage/Canisters/base.yml b/Resources/Prototypes/Entities/Structures/Storage/Canisters/base.yml deleted file mode 100644 index 2be102cc95..0000000000 --- a/Resources/Prototypes/Entities/Structures/Storage/Canisters/base.yml +++ /dev/null @@ -1,72 +0,0 @@ -- type: entity - abstract: true - id: GasCanister - name: gas canister - description: A canister that can contain any type of gas. It can be attached to connector ports using a wrench. - parent: BaseStructureDynamic - components: - - type: InteractionOutline - - type: Sprite - netsync: false - sprite: Structures/Storage/canister.rsi - state: grey - - type: Appearance - visuals: - - type: GasPortableVisualizer - stateConnected: can-connector - - type: GasCanisterVisualizer - insertedTankState: can-open - pressureStates: - - can-o0 - - can-o1 - - can-o2 - - can-o3 - - type: UserInterface - interfaces: - - key: enum.GasCanisterUiKey.Key - type: GasCanisterBoundUserInterface - - type: Destructible - thresholds: - - trigger: - !type:DamageTrigger - damage: 300 - behaviors: - - !type:PlaySoundBehavior - sound: /Audio/Effects/metalbreak.ogg - - !type:SpawnEntitiesBehavior - spawn: - GasCanisterBrokenBase: - min: 1 - max: 1 - - !type:DoActsBehavior - acts: [ "Destruction" ] - - type: Damageable - resistances: metallicResistances - - type: Physics - bodyType: Dynamic - fixtures: - - shape: - !type:PhysShapeAabb - bounds: "-0.25,-0.25,0.25,0.25" - mass: 25 - mask: - - MobImpassable - layer: - - Opaque - - MobImpassable - - SmallImpassable - - VaultImpassable - - type: AtmosDevice - requireAnchored: false - - type: ContainerContainer - containers: - GasCanisterTankHolder: !type:ContainerSlot {} - - type: NodeContainer - nodes: - port: - !type:PortablePipeNode - nodeGroupID: Pipe - rotationsEnabled: false - volume: 1 - - type: GasPortable - - type: GasCanister diff --git a/Resources/Prototypes/Entities/Structures/Storage/Canisters/gas_canisters.yml b/Resources/Prototypes/Entities/Structures/Storage/Canisters/gas_canisters.yml index 7144edd6f1..45a3e65145 100644 --- a/Resources/Prototypes/Entities/Structures/Storage/Canisters/gas_canisters.yml +++ b/Resources/Prototypes/Entities/Structures/Storage/Canisters/gas_canisters.yml @@ -1,3 +1,77 @@ +- type: entity + abstract: true + id: GasCanister + name: gas canister + description: A canister that can contain any type of gas. It can be attached to connector ports using a wrench. + parent: BaseStructureDynamic + components: + - type: InteractionOutline + - type: Sprite + netsync: false + sprite: Structures/Storage/canister.rsi + state: grey + - type: Appearance + visuals: + - type: GasPortableVisualizer + stateConnected: can-connector + - type: GasCanisterVisualizer + insertedTankState: can-open + pressureStates: + - can-o0 + - can-o1 + - can-o2 + - can-o3 + - type: UserInterface + interfaces: + - key: enum.GasCanisterUiKey.Key + type: GasCanisterBoundUserInterface + - type: Destructible + thresholds: + - trigger: + !type:DamageTrigger + damage: 300 + behaviors: + - !type:PlaySoundBehavior + sound: /Audio/Effects/metalbreak.ogg + - !type:SpawnEntitiesBehavior + spawn: + GasCanisterBrokenBase: + min: 1 + max: 1 + - !type:DoActsBehavior + acts: [ "Destruction" ] + - type: Damageable + resistances: metallicResistances + - type: Physics + bodyType: Dynamic + fixtures: + - shape: + !type:PhysShapeAabb + bounds: "-0.25,-0.25,0.25,0.25" + mass: 25 + mask: + - MobImpassable + layer: + - Opaque + - MobImpassable + - SmallImpassable + - VaultImpassable + - type: AtmosDevice + requireAnchored: false + joinSystem: true + - type: ContainerContainer + containers: + GasCanisterTankHolder: !type:ContainerSlot {} + - type: NodeContainer + nodes: + port: + !type:PortablePipeNode + nodeGroupID: Pipe + rotationsEnabled: false + volume: 1 + - type: GasPortable + - type: GasCanister + - type: entity parent: GasCanister id: StorageCanister