2022-12-27 11:01:36 -06:00
using Content.Server.Administration.Logs ;
2022-06-11 18:54:41 -07:00
using Content.Server.Audio ;
2021-11-02 01:12:55 +01:00
using Content.Server.Power.Components ;
2022-12-27 11:01:36 -06:00
using Content.Shared.Database ;
2021-11-02 01:12:55 +01:00
using Content.Shared.Gravity ;
using Content.Shared.Interaction ;
using Robust.Server.GameObjects ;
2022-12-27 11:01:36 -06:00
using Robust.Server.Player ;
using Robust.Shared.Players ;
2023-08-15 03:23:40 +03:00
using Content.Server.Construction ;
2021-11-02 01:12:55 +01:00
2022-12-18 16:03:23 +11:00
namespace Content.Server.Gravity
2021-11-02 01:12:55 +01:00
{
public sealed class GravityGeneratorSystem : EntitySystem
{
2022-12-27 11:01:36 -06:00
[Dependency] private readonly IAdminLogManager _adminLogger = default ! ;
2021-11-02 01:12:55 +01:00
[Dependency] private readonly AmbientSoundSystem _ambientSoundSystem = default ! ;
[Dependency] private readonly GravitySystem _gravitySystem = default ! ;
2022-12-18 16:03:23 +11:00
[Dependency] private readonly SharedAppearanceSystem _appearance = default ! ;
[Dependency] private readonly UserInterfaceSystem _uiSystem = default ! ;
2021-11-02 01:12:55 +01:00
public override void Initialize ( )
{
base . Initialize ( ) ;
2022-12-18 16:03:23 +11:00
SubscribeLocalEvent < GravityGeneratorComponent , ComponentInit > ( OnCompInit ) ;
2022-05-25 13:17:56 -07:00
SubscribeLocalEvent < GravityGeneratorComponent , ComponentShutdown > ( OnComponentShutdown ) ;
2022-07-08 06:30:02 +12:00
SubscribeLocalEvent < GravityGeneratorComponent , EntParentChangedMessage > ( OnParentChanged ) ; // Or just anchor changed?
2021-11-02 01:12:55 +01:00
SubscribeLocalEvent < GravityGeneratorComponent , InteractHandEvent > ( OnInteractHand ) ;
2023-08-15 03:23:40 +03:00
SubscribeLocalEvent < GravityGeneratorComponent , RefreshPartsEvent > ( OnRefreshParts ) ;
2021-11-02 01:12:55 +01:00
SubscribeLocalEvent < GravityGeneratorComponent , SharedGravityGeneratorComponent . SwitchGeneratorMessage > (
OnSwitchGenerator ) ;
}
2022-07-08 06:30:02 +12:00
private void OnParentChanged ( EntityUid uid , GravityGeneratorComponent component , ref EntParentChangedMessage args )
{
if ( component . GravityActive & & TryComp ( args . OldParent , out GravityComponent ? gravity ) )
2022-12-18 16:03:23 +11:00
{
_gravitySystem . RefreshGravity ( args . OldParent . Value , gravity ) ;
}
2022-07-08 06:30:02 +12:00
}
2022-05-25 13:17:56 -07:00
private void OnComponentShutdown ( EntityUid uid , GravityGeneratorComponent component , ComponentShutdown args )
{
2022-12-18 16:03:23 +11:00
if ( component . GravityActive & &
TryComp < TransformComponent > ( uid , out var xform ) & &
TryComp ( xform . ParentUid , out GravityComponent ? gravity ) )
{
component . GravityActive = false ;
_gravitySystem . RefreshGravity ( xform . ParentUid , gravity ) ;
}
2022-05-25 13:17:56 -07:00
}
2021-11-02 01:12:55 +01:00
public override void Update ( float frameTime )
{
base . Update ( frameTime ) ;
foreach ( var ( gravGen , powerReceiver ) in EntityManager
. EntityQuery < GravityGeneratorComponent , ApcPowerReceiverComponent > ( ) )
{
if ( ! gravGen . Intact )
2022-12-18 16:03:23 +11:00
continue ;
2021-11-02 01:12:55 +01:00
// Calculate charge rate based on power state and such.
// Negative charge rate means discharging.
float chargeRate ;
if ( gravGen . SwitchedOn )
{
if ( powerReceiver . Powered )
{
chargeRate = gravGen . ChargeRate ;
}
else
{
// Scale discharge rate such that if we're at 25% active power we discharge at 75% rate.
var receiving = powerReceiver . PowerReceived ;
var mainSystemPower = Math . Max ( 0 , receiving - gravGen . IdlePowerUse ) ;
var ratio = 1 - mainSystemPower / ( gravGen . ActivePowerUse - gravGen . IdlePowerUse ) ;
chargeRate = - ( ratio * gravGen . ChargeRate ) ;
}
}
else
{
chargeRate = - gravGen . ChargeRate ;
}
2022-12-18 16:03:23 +11:00
var active = gravGen . GravityActive ;
2021-11-02 01:12:55 +01:00
var lastCharge = gravGen . Charge ;
2023-08-15 03:23:40 +03:00
gravGen . Charge = Math . Clamp ( gravGen . Charge + frameTime * chargeRate , 0 , gravGen . MaxCharge ) ;
2021-11-02 01:12:55 +01:00
if ( chargeRate > 0 )
{
// Charging.
2023-08-15 03:23:40 +03:00
if ( MathHelper . CloseTo ( gravGen . Charge , gravGen . MaxCharge ) & & ! gravGen . GravityActive )
2021-11-02 01:12:55 +01:00
{
gravGen . GravityActive = true ;
}
}
else
{
// Discharging
if ( MathHelper . CloseTo ( gravGen . Charge , 0 ) & & gravGen . GravityActive )
{
gravGen . GravityActive = false ;
}
}
var updateUI = gravGen . NeedUIUpdate ;
if ( ! MathHelper . CloseTo ( lastCharge , gravGen . Charge ) )
{
UpdateState ( gravGen , powerReceiver ) ;
updateUI = true ;
}
if ( updateUI )
UpdateUI ( gravGen , powerReceiver , chargeRate ) ;
2022-12-18 16:03:23 +11:00
if ( active ! = gravGen . GravityActive & &
TryComp < TransformComponent > ( gravGen . Owner , out var xform ) & &
TryComp < GravityComponent > ( xform . ParentUid , out var gravity ) )
2021-11-02 01:12:55 +01:00
{
2022-12-18 16:03:23 +11:00
// Force it on in the faster path.
if ( gravGen . GravityActive )
{
_gravitySystem . EnableGravity ( xform . ParentUid , gravity ) ;
}
else
{
_gravitySystem . RefreshGravity ( xform . ParentUid , gravity ) ;
}
2021-11-02 01:12:55 +01:00
}
}
}
2022-12-27 11:01:36 -06:00
private void SetSwitchedOn ( EntityUid uid , GravityGeneratorComponent component , bool on ,
ApcPowerReceiverComponent ? powerReceiver = null , ICommonSession ? session = null )
2021-11-02 01:12:55 +01:00
{
if ( ! Resolve ( uid , ref powerReceiver ) )
return ;
2022-12-27 11:01:36 -06:00
if ( session is { AttachedEntity : { } } )
_adminLogger . Add ( LogType . Action , on ? LogImpact . Medium : LogImpact . High , $"{ToPrettyString(session.AttachedEntity.Value):player} set ${ToPrettyString(uid):target} to {(on ? " on " : " off ")}" ) ;
2021-11-02 01:12:55 +01:00
component . SwitchedOn = on ;
UpdatePowerState ( component , powerReceiver ) ;
component . NeedUIUpdate = true ;
}
private static void UpdatePowerState (
GravityGeneratorComponent component ,
ApcPowerReceiverComponent powerReceiver )
{
powerReceiver . Load = component . SwitchedOn ? component . ActivePowerUse : component . IdlePowerUse ;
}
private void UpdateUI (
GravityGeneratorComponent component ,
ApcPowerReceiverComponent powerReceiver ,
float chargeRate )
{
2021-12-03 15:53:09 +01:00
if ( ! _uiSystem . IsUiOpen ( component . Owner , SharedGravityGeneratorComponent . GravityGeneratorUiKey . Key ) )
2021-11-02 01:12:55 +01:00
return ;
2023-08-15 03:23:40 +03:00
var chargeTarget = chargeRate < 0 ? 0 : component . MaxCharge ;
2021-11-02 01:12:55 +01:00
short chargeEta ;
var atTarget = false ;
if ( MathHelper . CloseTo ( component . Charge , chargeTarget ) )
{
chargeEta = short . MinValue ; // N/A
atTarget = true ;
}
else
{
var diff = chargeTarget - component . Charge ;
chargeEta = ( short ) Math . Abs ( diff / chargeRate ) ;
}
var status = chargeRate switch
{
> 0 when atTarget = > GravityGeneratorPowerStatus . FullyCharged ,
< 0 when atTarget = > GravityGeneratorPowerStatus . Off ,
> 0 = > GravityGeneratorPowerStatus . Charging ,
< 0 = > GravityGeneratorPowerStatus . Discharging ,
_ = > throw new ArgumentOutOfRangeException ( )
} ;
var state = new SharedGravityGeneratorComponent . GeneratorState (
component . SwitchedOn ,
( byte ) ( component . Charge * 255 ) ,
status ,
( short ) Math . Round ( powerReceiver . PowerReceived ) ,
( short ) Math . Round ( powerReceiver . Load ) ,
chargeEta
) ;
_uiSystem . TrySetUiState (
2021-12-03 15:53:09 +01:00
component . Owner ,
2021-11-02 01:12:55 +01:00
SharedGravityGeneratorComponent . GravityGeneratorUiKey . Key ,
state ) ;
component . NeedUIUpdate = false ;
}
2022-12-18 16:03:23 +11:00
private void OnCompInit ( EntityUid uid , GravityGeneratorComponent component , ComponentInit args )
2021-11-02 01:12:55 +01:00
{
ApcPowerReceiverComponent ? powerReceiver = null ;
if ( ! Resolve ( uid , ref powerReceiver , false ) )
return ;
UpdatePowerState ( component , powerReceiver ) ;
UpdateState ( component , powerReceiver ) ;
}
private void OnInteractHand ( EntityUid uid , GravityGeneratorComponent component , InteractHandEvent args )
{
2021-12-03 15:53:09 +01:00
if ( ! EntityManager . TryGetComponent ( args . User , out ActorComponent ? actor ) )
2021-11-02 01:12:55 +01:00
return ;
ApcPowerReceiverComponent ? powerReceiver = default ! ;
if ( ! Resolve ( uid , ref powerReceiver ) )
return ;
// Do not allow opening UI if broken or unpowered.
if ( ! component . Intact | | powerReceiver . PowerReceived < component . IdlePowerUse )
return ;
_uiSystem . TryOpen ( uid , SharedGravityGeneratorComponent . GravityGeneratorUiKey . Key , actor . PlayerSession ) ;
component . NeedUIUpdate = true ;
}
public void UpdateState ( GravityGeneratorComponent grav , ApcPowerReceiverComponent powerReceiver )
{
2021-12-05 18:09:01 +01:00
var uid = grav . Owner ;
2021-11-02 01:12:55 +01:00
var appearance = EntityManager . GetComponentOrNull < AppearanceComponent > ( uid ) ;
2022-12-18 16:03:23 +11:00
_appearance . SetData ( uid , GravityGeneratorVisuals . Charge , grav . Charge , appearance ) ;
2021-11-02 01:12:55 +01:00
if ( EntityManager . TryGetComponent ( uid , out PointLightComponent ? pointLight ) )
{
pointLight . Enabled = grav . Charge > 0 ;
pointLight . Radius = MathHelper . Lerp ( grav . LightRadiusMin , grav . LightRadiusMax , grav . Charge ) ;
}
if ( ! grav . Intact )
{
2022-12-18 16:03:23 +11:00
MakeBroken ( uid , grav , appearance ) ;
2021-11-02 01:12:55 +01:00
}
else if ( powerReceiver . PowerReceived < grav . IdlePowerUse )
{
2022-12-18 16:03:23 +11:00
MakeUnpowered ( uid , grav , appearance ) ;
2021-11-02 01:12:55 +01:00
}
else if ( ! grav . SwitchedOn )
{
2022-12-18 16:03:23 +11:00
MakeOff ( uid , grav , appearance ) ;
2021-11-02 01:12:55 +01:00
}
else
{
2022-12-18 16:03:23 +11:00
MakeOn ( uid , grav , appearance ) ;
2021-11-02 01:12:55 +01:00
}
}
2023-08-15 03:23:40 +03:00
private void OnRefreshParts ( EntityUid uid , GravityGeneratorComponent component , RefreshPartsEvent args )
{
var maxChargeMultipler = args . PartRatings [ component . MachinePartMaxChargeMultiplier ] ;
component . MaxCharge = maxChargeMultipler * 1 ;
}
2022-12-18 16:03:23 +11:00
private void MakeBroken ( EntityUid uid , GravityGeneratorComponent component , AppearanceComponent ? appearance )
2021-11-02 01:12:55 +01:00
{
2021-12-03 15:53:09 +01:00
_ambientSoundSystem . SetAmbience ( component . Owner , false ) ;
2021-11-02 01:12:55 +01:00
2022-12-18 16:03:23 +11:00
_appearance . SetData ( uid , GravityGeneratorVisuals . State , GravityGeneratorStatus . Broken ) ;
2021-11-02 01:12:55 +01:00
}
2022-12-18 16:03:23 +11:00
private void MakeUnpowered ( EntityUid uid , GravityGeneratorComponent component , AppearanceComponent ? appearance )
2021-11-02 01:12:55 +01:00
{
2021-12-03 15:53:09 +01:00
_ambientSoundSystem . SetAmbience ( component . Owner , false ) ;
2021-11-02 01:12:55 +01:00
2022-12-18 16:03:23 +11:00
_appearance . SetData ( uid , GravityGeneratorVisuals . State , GravityGeneratorStatus . Unpowered , appearance ) ;
2021-11-02 01:12:55 +01:00
}
2022-12-18 16:03:23 +11:00
private void MakeOff ( EntityUid uid , GravityGeneratorComponent component , AppearanceComponent ? appearance )
2021-11-02 01:12:55 +01:00
{
2021-12-03 15:53:09 +01:00
_ambientSoundSystem . SetAmbience ( component . Owner , false ) ;
2021-11-02 01:12:55 +01:00
2022-12-18 16:03:23 +11:00
_appearance . SetData ( uid , GravityGeneratorVisuals . State , GravityGeneratorStatus . Off , appearance ) ;
2021-11-02 01:12:55 +01:00
}
2022-12-18 16:03:23 +11:00
private void MakeOn ( EntityUid uid , GravityGeneratorComponent component , AppearanceComponent ? appearance )
2021-11-02 01:12:55 +01:00
{
2021-12-03 15:53:09 +01:00
_ambientSoundSystem . SetAmbience ( component . Owner , true ) ;
2021-11-02 01:12:55 +01:00
2022-12-18 16:03:23 +11:00
_appearance . SetData ( uid , GravityGeneratorVisuals . State , GravityGeneratorStatus . On , appearance ) ;
2021-11-02 01:12:55 +01:00
}
private void OnSwitchGenerator (
EntityUid uid ,
GravityGeneratorComponent component ,
SharedGravityGeneratorComponent . SwitchGeneratorMessage args )
{
2022-12-27 11:01:36 -06:00
SetSwitchedOn ( uid , component , args . On , session : args . Session ) ;
2021-11-02 01:12:55 +01:00
}
}
}