2021-06-19 13:25:05 +02:00
using System ;
2021-11-23 22:08:17 -06:00
using Content.Server.Administration.Logs ;
2021-06-19 13:25:05 +02:00
using Content.Server.Atmos.Components ;
2021-06-23 11:35:30 +02:00
using Content.Server.Atmos.EntitySystems ;
2021-06-19 13:25:05 +02:00
using Content.Server.Atmos.Piping.Components ;
2021-06-23 12:02:28 +02:00
using Content.Server.Atmos.Piping.Unary.Components ;
2021-06-19 13:25:05 +02:00
using Content.Server.Hands.Components ;
using Content.Server.NodeContainer ;
2021-07-12 10:00:50 +02:00
using Content.Server.NodeContainer.NodeGroups ;
2021-07-04 18:11:52 +02:00
using Content.Server.NodeContainer.Nodes ;
2021-06-19 13:25:05 +02:00
using Content.Shared.ActionBlocker ;
using Content.Shared.Atmos ;
using Content.Shared.Atmos.Piping.Binary.Components ;
2021-11-28 14:56:53 +01:00
using Content.Shared.Database ;
2021-06-19 13:25:05 +02:00
using Content.Shared.Interaction ;
using Content.Shared.Interaction.Helpers ;
using JetBrains.Annotations ;
using Robust.Server.GameObjects ;
using Robust.Shared.Containers ;
using Robust.Shared.GameObjects ;
2021-07-26 12:58:17 +02:00
using Robust.Shared.IoC ;
2021-06-19 13:25:05 +02:00
using Robust.Shared.Maths ;
2021-09-19 09:32:38 +02:00
using Robust.Shared.Players ;
2021-06-19 13:25:05 +02:00
2021-06-23 12:02:28 +02:00
namespace Content.Server.Atmos.Piping.Unary.EntitySystems
2021-06-19 13:25:05 +02:00
{
[UsedImplicitly]
2022-02-15 17:06:52 +13:00
public sealed class GasCanisterSystem : EntitySystem
2021-06-19 13:25:05 +02:00
{
2021-09-19 09:32:38 +02:00
[Dependency] private readonly UserInterfaceSystem _userInterfaceSystem = default ! ;
2021-07-26 12:58:17 +02:00
[Dependency] private readonly AtmosphereSystem _atmosphereSystem = default ! ;
2021-11-23 22:08:17 -06:00
[Dependency] private readonly AdminLogSystem _adminLogSystem = default ! ;
2021-07-26 12:58:17 +02:00
2021-06-19 13:25:05 +02:00
public override void Initialize ( )
{
base . Initialize ( ) ;
SubscribeLocalEvent < GasCanisterComponent , ComponentStartup > ( OnCanisterStartup ) ;
SubscribeLocalEvent < GasCanisterComponent , AtmosDeviceUpdateEvent > ( OnCanisterUpdated ) ;
SubscribeLocalEvent < GasCanisterComponent , ActivateInWorldEvent > ( OnCanisterActivate ) ;
SubscribeLocalEvent < GasCanisterComponent , InteractHandEvent > ( OnCanisterInteractHand ) ;
SubscribeLocalEvent < GasCanisterComponent , InteractUsingEvent > ( OnCanisterInteractUsing ) ;
SubscribeLocalEvent < GasCanisterComponent , EntInsertedIntoContainerMessage > ( OnCanisterContainerInserted ) ;
SubscribeLocalEvent < GasCanisterComponent , EntRemovedFromContainerMessage > ( OnCanisterContainerRemoved ) ;
2021-09-19 09:32:38 +02:00
// Bound UI subscriptions
SubscribeLocalEvent < GasCanisterComponent , GasCanisterHoldingTankEjectMessage > ( OnHoldingTankEjectMessage ) ;
SubscribeLocalEvent < GasCanisterComponent , GasCanisterChangeReleasePressureMessage > ( OnCanisterChangeReleasePressure ) ;
SubscribeLocalEvent < GasCanisterComponent , GasCanisterChangeReleaseValveMessage > ( OnCanisterChangeReleaseValve ) ;
2021-11-05 19:19:12 -05:00
}
/// <summary>
/// Completely dumps the content of the canister into the world.
/// </summary>
2021-11-08 12:37:32 +01:00
public void PurgeContents ( EntityUid uid , GasCanisterComponent ? canister = null , TransformComponent ? transform = null )
2021-11-05 19:19:12 -05:00
{
2021-11-09 13:00:08 +01:00
if ( ! Resolve ( uid , ref canister , ref transform ) )
return ;
2021-11-05 19:19:12 -05:00
var environment = _atmosphereSystem . GetTileMixture ( transform . Coordinates , true ) ;
if ( environment is not null )
_atmosphereSystem . Merge ( environment , canister . Air ) ;
2021-12-14 00:22:58 +13:00
_adminLogSystem . Add ( LogType . CanisterPurged , LogImpact . Medium , $"Canister {ToPrettyString(uid):canister} purged its contents of {canister.Air:gas} into the environment." ) ;
2021-11-05 19:19:12 -05:00
canister . Air . Clear ( ) ;
2021-06-19 13:25:05 +02:00
}
private void OnCanisterStartup ( EntityUid uid , GasCanisterComponent canister , ComponentStartup args )
{
2021-06-23 12:02:28 +02:00
// Ensure container manager.
2021-11-09 13:00:08 +01:00
var containerManager = EntityManager . EnsureComponent < ContainerManagerComponent > ( uid ) ;
2021-06-23 12:02:28 +02:00
// Ensure container.
if ( ! containerManager . TryGetContainer ( canister . ContainerName , out _ ) )
{
containerManager . MakeContainer < ContainerSlot > ( canister . ContainerName ) ;
}
2021-06-19 13:25:05 +02:00
}
2021-09-21 14:25:58 +02:00
private void DirtyUI ( EntityUid uid ,
GasCanisterComponent ? canister = null , NodeContainerComponent ? nodeContainer = null ,
2021-09-26 13:01:10 +02:00
ContainerManagerComponent ? containerManager = null )
2021-06-19 13:25:05 +02:00
{
2021-09-26 13:01:10 +02:00
if ( ! Resolve ( uid , ref canister , ref nodeContainer , ref containerManager ) )
2021-06-19 13:25:05 +02:00
return ;
2021-09-21 14:25:58 +02:00
var portStatus = false ;
2021-06-19 13:25:05 +02:00
string? tankLabel = null ;
var tankPressure = 0f ;
2021-09-21 14:25:58 +02:00
if ( nodeContainer . TryGetNode ( canister . PortName , out PipeNode ? portNode ) & & portNode . NodeGroup ? . Nodes . Count > 1 )
portStatus = true ;
if ( containerManager . TryGetContainer ( canister . ContainerName , out var tankContainer )
2021-07-12 10:00:50 +02:00
& & tankContainer . ContainedEntities . Count > 0 )
2021-06-19 13:25:05 +02:00
{
2021-12-05 18:09:01 +01:00
var tank = tankContainer . ContainedEntities [ 0 ] ;
2021-11-09 13:00:08 +01:00
var tankComponent = EntityManager . GetComponent < GasTankComponent > ( tank ) ;
tankLabel = EntityManager . GetComponent < MetaDataComponent > ( tank ) . EntityName ;
2021-06-23 12:02:28 +02:00
tankPressure = tankComponent . Air . Pressure ;
2021-06-19 13:25:05 +02:00
}
2021-09-21 14:25:58 +02:00
_userInterfaceSystem . TrySetUiState ( uid , GasCanisterUiKey . Key ,
2021-12-05 18:09:01 +01:00
new GasCanisterBoundUserInterfaceState ( EntityManager . GetComponent < MetaDataComponent > ( canister . Owner ) . EntityName ,
2021-09-21 14:25:58 +02:00
canister . Air . Pressure , portStatus , tankLabel , tankPressure , canister . ReleasePressure ,
canister . ReleaseValve , canister . MinReleasePressure , canister . MaxReleasePressure ) ) ;
2021-06-19 13:25:05 +02:00
}
2021-09-19 09:32:38 +02:00
private void OnHoldingTankEjectMessage ( EntityUid uid , GasCanisterComponent canister , GasCanisterHoldingTankEjectMessage args )
2021-06-19 13:25:05 +02:00
{
2021-09-28 13:35:29 +02:00
if ( ! EntityManager . TryGetComponent ( uid , out ContainerManagerComponent ? containerManager )
2021-09-19 09:32:38 +02:00
| | ! containerManager . TryGetContainer ( canister . ContainerName , out var container ) )
2021-06-19 13:25:05 +02:00
return ;
2021-09-19 09:32:38 +02:00
if ( container . ContainedEntities . Count = = 0 )
return ;
2021-06-19 13:25:05 +02:00
2021-12-14 00:22:58 +13:00
_adminLogSystem . Add ( LogType . CanisterTankEjected , LogImpact . Medium , $"Player {ToPrettyString(args.Session.AttachedEntity.GetValueOrDefault()):player} ejected tank {ToPrettyString(container.ContainedEntities[0]):tank} from {ToPrettyString(uid):canister}" ) ;
2021-09-19 09:32:38 +02:00
container . Remove ( container . ContainedEntities [ 0 ] ) ;
}
2021-06-19 13:25:05 +02:00
2021-09-19 09:32:38 +02:00
private void OnCanisterChangeReleasePressure ( EntityUid uid , GasCanisterComponent canister , GasCanisterChangeReleasePressureMessage args )
{
var pressure = Math . Clamp ( args . Pressure , canister . MinReleasePressure , canister . MaxReleasePressure ) ;
2021-06-19 13:25:05 +02:00
2021-12-14 00:22:58 +13:00
_adminLogSystem . Add ( LogType . CanisterPressure , LogImpact . Medium , $"{ToPrettyString(args.Session.AttachedEntity.GetValueOrDefault()):player} set the release pressure on {ToPrettyString(uid):canister} to {args.Pressure}" ) ;
2021-11-23 22:08:17 -06:00
2021-09-19 09:32:38 +02:00
canister . ReleasePressure = pressure ;
2021-09-21 14:25:58 +02:00
DirtyUI ( uid , canister ) ;
2021-09-19 09:32:38 +02:00
}
private void OnCanisterChangeReleaseValve ( EntityUid uid , GasCanisterComponent canister , GasCanisterChangeReleaseValveMessage args )
{
2021-11-24 16:52:31 -06:00
var impact = LogImpact . High ;
if ( EntityManager . TryGetComponent ( uid , out ContainerManagerComponent containerManager )
& & containerManager . TryGetContainer ( canister . ContainerName , out var container ) )
impact = container . ContainedEntities . Count ! = 0 ? LogImpact . Medium : LogImpact . High ;
2021-12-14 00:22:58 +13:00
_adminLogSystem . Add ( LogType . CanisterValve , impact , $"{ToPrettyString(args.Session.AttachedEntity.GetValueOrDefault()):player} set the valve on {ToPrettyString(uid):canister} to {args.Valve:valveState}" ) ;
2021-11-23 22:08:17 -06:00
2021-09-19 09:32:38 +02:00
canister . ReleaseValve = args . Valve ;
2021-09-21 14:25:58 +02:00
DirtyUI ( uid , canister ) ;
2021-06-19 13:25:05 +02:00
}
private void OnCanisterUpdated ( EntityUid uid , GasCanisterComponent canister , AtmosDeviceUpdateEvent args )
{
2021-09-28 13:35:29 +02:00
if ( ! EntityManager . TryGetComponent ( uid , out NodeContainerComponent ? nodeContainer )
| | ! EntityManager . TryGetComponent ( uid , out AppearanceComponent ? appearance ) )
2021-06-19 13:25:05 +02:00
return ;
2021-07-12 10:00:50 +02:00
if ( ! nodeContainer . TryGetNode ( canister . PortName , out PortablePipeNode ? portNode ) )
2021-06-19 13:25:05 +02:00
return ;
2021-07-26 12:58:17 +02:00
_atmosphereSystem . React ( canister . Air , portNode ) ;
2021-07-12 10:00:50 +02:00
if ( portNode . NodeGroup is PipeNet { NodeCount : > 1 } net )
{
var buffer = new GasMixture ( net . Air . Volume + canister . Air . Volume ) ;
2021-07-26 12:58:17 +02:00
_atmosphereSystem . Merge ( buffer , net . Air ) ;
_atmosphereSystem . Merge ( buffer , canister . Air ) ;
2021-07-12 10:00:50 +02:00
net . Air . Clear ( ) ;
2021-07-26 12:58:17 +02:00
_atmosphereSystem . Merge ( net . Air , buffer ) ;
2021-07-12 10:00:50 +02:00
net . Air . Multiply ( net . Air . Volume / buffer . Volume ) ;
canister . Air . Clear ( ) ;
2021-07-26 12:58:17 +02:00
_atmosphereSystem . Merge ( canister . Air , buffer ) ;
2021-07-12 10:00:50 +02:00
canister . Air . Multiply ( canister . Air . Volume / buffer . Volume ) ;
}
2021-09-21 14:25:58 +02:00
ContainerManagerComponent ? containerManager = null ;
2021-06-23 12:02:28 +02:00
// Release valve is open, release gas.
if ( canister . ReleaseValve )
{
2021-09-28 13:35:29 +02:00
if ( ! EntityManager . TryGetComponent ( uid , out containerManager )
2021-06-23 12:02:28 +02:00
| | ! containerManager . TryGetContainer ( canister . ContainerName , out var container ) )
return ;
if ( container . ContainedEntities . Count > 0 )
{
2021-12-05 18:09:01 +01:00
var gasTank = EntityManager . GetComponent < GasTankComponent > ( container . ContainedEntities [ 0 ] ) ;
2021-07-26 12:58:17 +02:00
_atmosphereSystem . ReleaseGasTo ( canister . Air , gasTank . Air , canister . ReleasePressure ) ;
2021-06-23 12:02:28 +02:00
}
else
{
2021-12-05 18:09:01 +01:00
var environment = _atmosphereSystem . GetTileMixture ( EntityManager . GetComponent < TransformComponent > ( canister . Owner ) . Coordinates , true ) ;
2021-07-26 12:58:17 +02:00
_atmosphereSystem . ReleaseGasTo ( canister . Air , environment , canister . ReleasePressure ) ;
2021-06-23 12:02:28 +02:00
}
}
2021-07-12 10:00:50 +02:00
// If last pressure is very close to the current pressure, do nothing.
2021-09-29 20:07:01 +10:00
if ( MathHelper . CloseToPercent ( canister . Air . Pressure , canister . LastPressure ) )
2021-06-19 13:25:05 +02:00
return ;
2022-02-20 08:15:47 +13:00
DirtyUI ( uid , canister , nodeContainer , containerManager ) ;
2021-07-12 10:00:50 +02:00
canister . LastPressure = canister . Air . Pressure ;
2021-06-19 13:25:05 +02:00
2021-07-12 10:00:50 +02:00
if ( canister . Air . Pressure < 10 )
2021-06-19 13:25:05 +02:00
{
appearance . SetData ( GasCanisterVisuals . PressureState , 0 ) ;
}
2021-07-12 10:00:50 +02:00
else if ( canister . Air . Pressure < Atmospherics . OneAtmosphere )
2021-06-19 13:25:05 +02:00
{
appearance . SetData ( GasCanisterVisuals . PressureState , 1 ) ;
}
2021-07-12 10:00:50 +02:00
else if ( canister . Air . Pressure < ( 15 * Atmospherics . OneAtmosphere ) )
2021-06-19 13:25:05 +02:00
{
appearance . SetData ( GasCanisterVisuals . PressureState , 2 ) ;
}
else
{
appearance . SetData ( GasCanisterVisuals . PressureState , 3 ) ;
}
}
private void OnCanisterActivate ( EntityUid uid , GasCanisterComponent component , ActivateInWorldEvent args )
{
2021-12-05 18:09:01 +01:00
if ( ! EntityManager . TryGetComponent ( args . User , out ActorComponent ? actor ) )
2021-06-19 13:25:05 +02:00
return ;
2021-11-09 13:00:08 +01:00
_userInterfaceSystem . GetUiOrNull ( uid , GasCanisterUiKey . Key ) ? . Open ( actor . PlayerSession ) ;
2021-06-19 13:25:05 +02:00
args . Handled = true ;
}
private void OnCanisterInteractHand ( EntityUid uid , GasCanisterComponent component , InteractHandEvent args )
{
2021-12-05 18:09:01 +01:00
if ( ! EntityManager . TryGetComponent ( args . User , out ActorComponent ? actor ) )
2021-06-19 13:25:05 +02:00
return ;
2021-11-09 13:00:08 +01:00
_userInterfaceSystem . GetUiOrNull ( uid , GasCanisterUiKey . Key ) ? . Open ( actor . PlayerSession ) ;
2021-06-19 13:25:05 +02:00
args . Handled = true ;
}
2021-12-05 18:09:01 +01:00
private void OnCanisterInteractUsing ( EntityUid canister , GasCanisterComponent component , InteractUsingEvent args )
2021-06-19 13:25:05 +02:00
{
var container = canister . EnsureContainer < ContainerSlot > ( component . ContainerName ) ;
// Container full.
if ( container . ContainedEntity ! = null )
return ;
// Check the used item is valid...
2021-12-05 18:09:01 +01:00
if ( ! EntityManager . TryGetComponent ( args . Used , out GasTankComponent ? _ ) )
2021-06-19 13:25:05 +02:00
return ;
// Check the user has hands.
2021-12-05 18:09:01 +01:00
if ( ! EntityManager . TryGetComponent ( args . User , out HandsComponent ? hands ) )
2021-06-19 13:25:05 +02:00
return ;
2021-10-25 20:06:12 +13:00
if ( ! hands . Drop ( args . Used , container ) )
2021-06-19 13:25:05 +02:00
return ;
2021-12-14 00:22:58 +13:00
_adminLogSystem . Add ( LogType . CanisterTankInserted , LogImpact . Medium , $"Player {ToPrettyString(args.User):player} inserted tank {ToPrettyString(container.ContainedEntities[0]):tank} into {ToPrettyString(canister):canister}" ) ;
2021-11-24 16:52:31 -06:00
2021-06-19 13:25:05 +02:00
args . Handled = true ;
}
private void OnCanisterContainerInserted ( EntityUid uid , GasCanisterComponent component , EntInsertedIntoContainerMessage args )
{
if ( args . Container . ID ! = component . ContainerName )
return ;
2021-09-21 14:25:58 +02:00
DirtyUI ( uid , component ) ;
2021-06-19 13:25:05 +02:00
2021-09-28 13:35:29 +02:00
if ( ! EntityManager . TryGetComponent ( uid , out AppearanceComponent ? appearance ) )
2021-06-19 13:25:05 +02:00
return ;
appearance . SetData ( GasCanisterVisuals . TankInserted , true ) ;
}
private void OnCanisterContainerRemoved ( EntityUid uid , GasCanisterComponent component , EntRemovedFromContainerMessage args )
{
if ( args . Container . ID ! = component . ContainerName )
return ;
2021-09-21 14:25:58 +02:00
DirtyUI ( uid , component ) ;
2021-06-19 13:25:05 +02:00
2021-09-28 13:35:29 +02:00
if ( ! EntityManager . TryGetComponent ( uid , out AppearanceComponent ? appearance ) )
2021-06-19 13:25:05 +02:00
return ;
appearance . SetData ( GasCanisterVisuals . TankInserted , false ) ;
}
}
}