AtmosDevices can optionally process in space. (#4405)

Refactors some misc atmos things, too.
This commit is contained in:
Vera Aguilera Puerto
2021-08-02 13:59:41 +02:00
committed by GitHub
parent e42acf2401
commit 009087863f
14 changed files with 176 additions and 120 deletions

View File

@@ -47,7 +47,7 @@ namespace Content.Server.Atmos.Commands
return; return;
} }
if (grid.HasComponent<IGridAtmosphereComponent>()) if (grid.HasComponent<IAtmosphereComponent>())
{ {
shell.WriteLine("Grid already has an atmosphere."); shell.WriteLine("Grid already has an atmosphere.");
return; return;

View File

@@ -47,7 +47,7 @@ namespace Content.Server.Atmos.Commands
return; return;
} }
if (grid.HasComponent<IGridAtmosphereComponent>()) if (grid.HasComponent<IAtmosphereComponent>())
{ {
shell.WriteLine("Grid already has an atmosphere."); shell.WriteLine("Grid already has an atmosphere.");
return; return;

View File

@@ -16,9 +16,9 @@ namespace Content.Server.Atmos.Components
/// <summary> /// <summary>
/// This is our SSAir equivalent. /// This is our SSAir equivalent.
/// </summary> /// </summary>
[ComponentReference(typeof(IGridAtmosphereComponent))] [ComponentReference(typeof(IAtmosphereComponent))]
[RegisterComponent, Serializable] [RegisterComponent, Serializable]
public class GridAtmosphereComponent : Component, IGridAtmosphereComponent, ISerializationHooks public class GridAtmosphereComponent : Component, IAtmosphereComponent, ISerializationHooks
{ {
public override string Name => "GridAtmosphere"; public override string Name => "GridAtmosphere";
public virtual bool Simulated => true; public virtual bool Simulated => true;

View File

@@ -2,7 +2,7 @@
namespace Content.Server.Atmos.Components namespace Content.Server.Atmos.Components
{ {
public interface IGridAtmosphereComponent : IComponent public interface IAtmosphereComponent : IComponent
{ {
/// <summary> /// <summary>
/// Whether this atmosphere is simulated or not. /// Whether this atmosphere is simulated or not.

View File

@@ -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;
}
}

View File

@@ -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";
}
}

View File

@@ -8,10 +8,9 @@ using Robust.Shared.Maths;
namespace Content.Server.Atmos.Components namespace Content.Server.Atmos.Components
{ {
[RegisterComponent] [RegisterComponent]
[ComponentReference(typeof(IGridAtmosphereComponent))] [ComponentReference(typeof(IAtmosphereComponent))]
[ComponentReference(typeof(GridAtmosphereComponent))]
[Serializable] [Serializable]
public class UnsimulatedGridAtmosphereComponent : GridAtmosphereComponent, IGridAtmosphereComponent public class UnsimulatedGridAtmosphereComponent : GridAtmosphereComponent
{ {
public override string Name => "UnsimulatedGridAtmosphere"; public override string Name => "UnsimulatedGridAtmosphere";

View File

@@ -117,6 +117,10 @@ namespace Content.Server.Atmos.EntitySystems
/// <returns>All tile mixtures in a grid.</returns> /// <returns>All tile mixtures in a grid.</returns>
public IEnumerable<GasMixture> GetAllTileMixtures(GridId grid, bool invalidate = false) public IEnumerable<GasMixture> 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)) if (!_mapManager.TryGetGrid(grid, out var mapGrid))
return Enumerable.Empty<GasMixture>(); return Enumerable.Empty<GasMixture>();
@@ -678,6 +682,10 @@ namespace Content.Server.Atmos.EntitySystems
/// <returns>The tile mixture, or null</returns> /// <returns>The tile mixture, or null</returns>
public GasMixture? GetTileMixture(GridId grid, Vector2i tile, bool invalidate = false) 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)) if (!_mapManager.TryGetGrid(grid, out var mapGrid))
return null; return null;
@@ -686,7 +694,7 @@ namespace Content.Server.Atmos.EntitySystems
return GetTileMixture(gridAtmosphere, tile, invalidate); 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. // Always return a new space gas mixture in this case.
return GasMixture.SpaceGas; return GasMixture.SpaceGas;
@@ -967,6 +975,10 @@ namespace Content.Server.Atmos.EntitySystems
/// <returns>All adjacent tile gas mixtures to the tile in question</returns> /// <returns>All adjacent tile gas mixtures to the tile in question</returns>
public IEnumerable<GasMixture> GetAdjacentTileMixtures(GridId grid, Vector2i tile, bool includeBlocked = false, bool invalidate = false) public IEnumerable<GasMixture> 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)) if (!_mapManager.TryGetGrid(grid, out var mapGrid))
return Enumerable.Empty<GasMixture>(); return Enumerable.Empty<GasMixture>();

View File

@@ -14,6 +14,7 @@ namespace Content.Server.Atmos.EntitySystems
{ {
[Dependency] private readonly IGameTiming _gameTiming = default!; [Dependency] private readonly IGameTiming _gameTiming = default!;
private readonly AtmosDeviceUpdateEvent _updateEvent = new();
private readonly Stopwatch _simulationStopwatch = new(); private readonly Stopwatch _simulationStopwatch = new();
/// <summary> /// <summary>
@@ -204,11 +205,10 @@ namespace Content.Server.Atmos.EntitySystems
atmosphere.CurrentRunAtmosDevices = new Queue<AtmosDeviceComponent>(atmosphere.AtmosDevices); atmosphere.CurrentRunAtmosDevices = new Queue<AtmosDeviceComponent>(atmosphere.AtmosDevices);
var time = _gameTiming.CurTime; var time = _gameTiming.CurTime;
var updateEvent = new AtmosDeviceUpdateEvent();
var number = 0; var number = 0;
while (atmosphere.CurrentRunAtmosDevices.TryDequeue(out var device)) while (atmosphere.CurrentRunAtmosDevices.TryDequeue(out var device))
{ {
EntityManager.EventBus.RaiseLocalEvent(device.Owner.Uid, updateEvent, false); RaiseLocalEvent(device.Owner.Uid, _updateEvent, false);
device.LastProcess = time; device.LastProcess = time;
if (number++ < LagCheckIterations) continue; if (number++ < LagCheckIterations) continue;
@@ -241,7 +241,7 @@ namespace Content.Server.Atmos.EntitySystems
{ {
var atmosphere = _currentRunAtmosphere[_currentRunAtmosphereIndex]; var atmosphere = _currentRunAtmosphere[_currentRunAtmosphereIndex];
if (atmosphere.Paused || atmosphere.LifeStage >= ComponentLifeStage.Stopping) if (atmosphere.Paused || !atmosphere.Simulated || atmosphere.LifeStage >= ComponentLifeStage.Stopping)
continue; continue;
atmosphere.Timer += frameTime; atmosphere.Timer += frameTime;

View File

@@ -29,7 +29,6 @@ namespace Content.Server.Atmos.EntitySystems
#region Events #region Events
// Map events. // Map events.
_mapManager.MapCreated += OnMapCreated;
_mapManager.TileChanged += OnTileChanged; _mapManager.TileChanged += OnTileChanged;
#endregion #endregion
@@ -39,7 +38,6 @@ namespace Content.Server.Atmos.EntitySystems
{ {
base.Shutdown(); base.Shutdown();
_mapManager.MapCreated -= OnMapCreated;
_mapManager.TileChanged -= OnTileChanged; _mapManager.TileChanged -= OnTileChanged;
} }
@@ -57,17 +55,6 @@ namespace Content.Server.Atmos.EntitySystems
InvalidateTile(eventArgs.NewTile.GridIndex, eventArgs.NewTile.GridIndices); 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<IGridAtmosphereComponent>())
map.AddComponent<SpaceGridAtmosphereComponent>();
}
public override void Update(float frameTime) public override void Update(float frameTime)
{ {
base.Update(frameTime); base.Update(frameTime);

View File

@@ -8,7 +8,7 @@ using Robust.Shared.ViewVariables;
namespace Content.Server.Atmos.Piping.Components namespace Content.Server.Atmos.Piping.Components
{ {
/// <summary> /// <summary>
/// Adds itself to a <see cref="IGridAtmosphereComponent"/> to be updated by. /// Adds itself to a <see cref="IAtmosphereComponent"/> to be updated by.
/// </summary> /// </summary>
[RegisterComponent] [RegisterComponent]
public class AtmosDeviceComponent : Component public class AtmosDeviceComponent : Component
@@ -22,6 +22,19 @@ namespace Content.Server.Atmos.Piping.Components
[DataField("requireAnchored")] [DataField("requireAnchored")]
public bool RequireAnchored { get; private set; } = true; public bool RequireAnchored { get; private set; } = true;
/// <summary>
/// Whether this device will join an entity system to process when not in a grid.
/// </summary>
[ViewVariables]
[DataField("joinSystem")]
public bool JoinSystem { get; } = false;
/// <summary>
/// Whether we have joined an entity system to process.
/// </summary>
[ViewVariables]
public bool JoinedSystem { get; set; } = false;
[ViewVariables] [ViewVariables]
public TimeSpan LastProcess { get; set; } = TimeSpan.Zero; public TimeSpan LastProcess { get; set; } = TimeSpan.Zero;

View File

@@ -1,10 +1,10 @@
using System; using System;
using System.Collections.Generic;
using Content.Server.Atmos.EntitySystems; using Content.Server.Atmos.EntitySystems;
using Content.Server.Atmos.Piping.Components; using Content.Server.Atmos.Piping.Components;
using JetBrains.Annotations; using JetBrains.Annotations;
using Robust.Shared.GameObjects; using Robust.Shared.GameObjects;
using Robust.Shared.IoC; using Robust.Shared.IoC;
using Robust.Shared.Physics;
using Robust.Shared.Timing; using Robust.Shared.Timing;
namespace Content.Server.Atmos.Piping.EntitySystems namespace Content.Server.Atmos.Piping.EntitySystems
@@ -12,9 +12,14 @@ namespace Content.Server.Atmos.Piping.EntitySystems
[UsedImplicitly] [UsedImplicitly]
public class AtmosDeviceSystem : EntitySystem public class AtmosDeviceSystem : EntitySystem
{ {
[Dependency] private IGameTiming _gameTiming = default!; [Dependency] private readonly IGameTiming _gameTiming = default!;
[Dependency] private readonly AtmosphereSystem _atmosphereSystem = default!; [Dependency] private readonly AtmosphereSystem _atmosphereSystem = default!;
private readonly AtmosDeviceUpdateEvent _updateEvent = new();
private float _timer = 0f;
private readonly HashSet<AtmosDeviceComponent> _joinedDevices = new();
public override void Initialize() public override void Initialize()
{ {
base.Initialize(); base.Initialize();
@@ -33,11 +38,24 @@ namespace Content.Server.Atmos.Piping.EntitySystems
public void JoinAtmosphere(AtmosDeviceComponent component) public void JoinAtmosphere(AtmosDeviceComponent component)
{ {
if (!CanJoinAtmosphere(component)) if (!CanJoinAtmosphere(component))
{
return; 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)) if (!_atmosphereSystem.AddAtmosDevice(component))
{
if (component.JoinSystem)
{
_joinedDevices.Add(component);
component.JoinedSystem = true;
}
else
{
return; return;
}
}
component.LastProcess = _gameTiming.CurTime; component.LastProcess = _gameTiming.CurTime;
@@ -46,8 +64,19 @@ namespace Content.Server.Atmos.Piping.EntitySystems
public void LeaveAtmosphere(AtmosDeviceComponent component) 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; return;
}
if (component.JoinedSystem)
{
_joinedDevices.Remove(component);
component.JoinedSystem = false;
}
component.LastProcess = TimeSpan.Zero; component.LastProcess = TimeSpan.Zero;
RaiseLocalEvent(component.Owner.Uid, new AtmosDeviceDisabledEvent(), false); RaiseLocalEvent(component.Owner.Uid, new AtmosDeviceDisabledEvent(), false);
@@ -85,5 +114,22 @@ namespace Content.Server.Atmos.Piping.EntitySystems
{ {
RejoinAtmosphere(component); 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;
}
}
} }
} }

View File

@@ -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

View File

@@ -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 - type: entity
parent: GasCanister parent: GasCanister
id: StorageCanister id: StorageCanister