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;
}
if (grid.HasComponent<IGridAtmosphereComponent>())
if (grid.HasComponent<IAtmosphereComponent>())
{
shell.WriteLine("Grid already has an atmosphere.");
return;

View File

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

View File

@@ -16,9 +16,9 @@ namespace Content.Server.Atmos.Components
/// <summary>
/// This is our SSAir equivalent.
/// </summary>
[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;

View File

@@ -2,7 +2,7 @@
namespace Content.Server.Atmos.Components
{
public interface IGridAtmosphereComponent : IComponent
public interface IAtmosphereComponent : IComponent
{
/// <summary>
/// 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
{
[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";

View File

@@ -117,6 +117,10 @@ namespace Content.Server.Atmos.EntitySystems
/// <returns>All tile mixtures in a grid.</returns>
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))
return Enumerable.Empty<GasMixture>();
@@ -678,6 +682,10 @@ namespace Content.Server.Atmos.EntitySystems
/// <returns>The tile mixture, or null</returns>
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
/// <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)
{
// 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<GasMixture>();
@@ -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);

View File

@@ -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();
/// <summary>
@@ -204,11 +205,10 @@ namespace Content.Server.Atmos.EntitySystems
atmosphere.CurrentRunAtmosDevices = new Queue<AtmosDeviceComponent>(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;

View File

@@ -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<IGridAtmosphereComponent>())
map.AddComponent<SpaceGridAtmosphereComponent>();
}
public override void Update(float frameTime)
{
base.Update(frameTime);

View File

@@ -8,7 +8,7 @@ using Robust.Shared.ViewVariables;
namespace Content.Server.Atmos.Piping.Components
{
/// <summary>
/// Adds itself to a <see cref="IGridAtmosphereComponent"/> to be updated by.
/// Adds itself to a <see cref="IAtmosphereComponent"/> to be updated by.
/// </summary>
[RegisterComponent]
public class AtmosDeviceComponent : Component
@@ -22,6 +22,19 @@ namespace Content.Server.Atmos.Piping.Components
[DataField("requireAnchored")]
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]
public TimeSpan LastProcess { get; set; } = TimeSpan.Zero;

View File

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

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