2020-08-14 06:52:17 +10:00
using System ;
using System.Collections.Generic ;
using System.Linq ;
2021-02-11 01:13:03 -08:00
using Robust.Client.Graphics ;
2021-03-09 04:33:41 -06:00
using Robust.Shared.Enums ;
2021-02-11 01:13:03 -08:00
using Robust.Shared.GameObjects ;
2020-08-14 06:52:17 +10:00
using Robust.Shared.IoC ;
2021-02-11 01:13:03 -08:00
using Robust.Shared.Map ;
2020-09-13 14:23:52 +02:00
using Robust.Shared.Maths ;
2021-12-01 20:21:17 +00:00
using Robust.Shared.Prototypes ;
2021-12-05 18:09:01 +01:00
using Robust.Shared.Timing ;
2020-08-14 06:52:17 +10:00
namespace Content.Client.StationEvents
{
2022-02-16 00:23:23 -07:00
public sealed class RadiationPulseOverlay : Overlay
2020-08-14 06:52:17 +10:00
{
2021-09-28 13:35:29 +02:00
[Dependency] private readonly IEntityManager _entityManager = default ! ;
2021-12-01 20:21:17 +00:00
[Dependency] private readonly IPrototypeManager _prototypeManager = default ! ;
2020-08-14 06:52:17 +10:00
[Dependency] private readonly IGameTiming _gameTiming = default ! ;
2020-09-21 01:49:40 +02:00
2021-12-01 20:21:17 +00:00
private const float MaxDist = 15.0f ;
2020-08-14 06:52:17 +10:00
2021-12-01 20:21:17 +00:00
public override OverlaySpace Space = > OverlaySpace . WorldSpace ;
public override bool RequestScreenTexture = > true ;
2020-08-14 06:52:17 +10:00
2021-12-01 20:21:17 +00:00
private TimeSpan _lastTick = default ;
2020-09-21 01:49:40 +02:00
2021-12-01 20:21:17 +00:00
private readonly ShaderInstance _baseShader ;
private readonly Dictionary < EntityUid , ( ShaderInstance shd , RadiationShaderInstance instance ) > _pulses = new ( ) ;
2020-08-14 06:52:17 +10:00
2021-03-09 04:33:41 -06:00
public RadiationPulseOverlay ( )
2020-08-14 06:52:17 +10:00
{
IoCManager . InjectDependencies ( this ) ;
2021-12-01 20:21:17 +00:00
_baseShader = _prototypeManager . Index < ShaderPrototype > ( "Radiation" ) . Instance ( ) . Duplicate ( ) ;
2020-08-14 06:52:17 +10:00
}
2021-12-01 20:21:17 +00:00
protected override void Draw ( in OverlayDrawArgs args )
2020-08-14 06:52:17 +10:00
{
2021-12-01 20:21:17 +00:00
RadiationQuery ( args . Viewport . Eye ) ;
2020-09-21 01:49:40 +02:00
2021-12-01 20:21:17 +00:00
if ( _pulses . Count = = 0 )
return ;
2020-08-14 06:52:17 +10:00
2021-12-01 20:21:17 +00:00
if ( ScreenTexture = = null )
return ;
2020-08-14 06:52:17 +10:00
2021-12-01 20:21:17 +00:00
var worldHandle = args . WorldHandle ;
var viewport = args . Viewport ;
2020-08-14 06:52:17 +10:00
2021-12-01 20:21:17 +00:00
foreach ( ( var shd , var instance ) in _pulses . Values )
2020-08-14 06:52:17 +10:00
{
2021-12-01 20:21:17 +00:00
// To be clear, this needs to use "inside-viewport" pixels.
// In other words, specifically NOT IViewportControl.WorldToScreen (which uses outer coordinates).
var tempCoords = viewport . WorldToLocal ( instance . CurrentMapCoords ) ;
tempCoords . Y = viewport . Size . Y - tempCoords . Y ;
shd ? . SetParameter ( "renderScale" , viewport . RenderScale ) ;
shd ? . SetParameter ( "positionInput" , tempCoords ) ;
shd ? . SetParameter ( "range" , instance . Range ) ;
var life = ( _lastTick - instance . Start ) / ( instance . End - instance . Start ) ;
shd ? . SetParameter ( "life" , ( float ) life ) ;
// There's probably a very good reason not to do this.
// Oh well!
shd ? . SetParameter ( "SCREEN_TEXTURE" , viewport . RenderTarget . Texture ) ;
worldHandle . UseShader ( shd ) ;
worldHandle . DrawRect ( Box2 . CenteredAround ( instance . CurrentMapCoords , new Vector2 ( instance . Range , instance . Range ) * 2f ) , Color . White ) ;
2020-08-14 06:52:17 +10:00
}
}
2021-12-01 20:21:17 +00:00
//Queries all pulses on the map and either adds or removes them from the list of rendered pulses based on whether they should be drawn (in range? on the same z-level/map? pulse entity still exists?)
private void RadiationQuery ( IEye ? currentEye )
2020-08-14 06:52:17 +10:00
{
2021-12-01 20:21:17 +00:00
if ( currentEye = = null )
2020-08-14 06:52:17 +10:00
{
2021-12-01 20:21:17 +00:00
_pulses . Clear ( ) ;
return ;
2020-08-14 06:52:17 +10:00
}
2020-09-21 01:49:40 +02:00
2021-12-01 20:21:17 +00:00
_lastTick = _gameTiming . CurTime ;
2020-09-21 01:49:40 +02:00
2021-12-01 20:21:17 +00:00
var currentEyeLoc = currentEye . Position ;
2020-08-14 06:52:17 +10:00
2021-12-01 20:21:17 +00:00
var pulses = _entityManager . EntityQuery < RadiationPulseComponent > ( ) ;
foreach ( var pulse in pulses ) //Add all pulses that are not added yet but qualify
2020-08-14 06:52:17 +10:00
{
2021-12-06 00:52:58 +01:00
var pulseEntity = pulse . Owner ;
2020-08-14 06:52:17 +10:00
2021-12-03 15:53:09 +01:00
if ( ! _pulses . Keys . Contains ( pulseEntity ) & & PulseQualifies ( pulseEntity , currentEyeLoc ) )
2021-12-01 20:21:17 +00:00
{
_pulses . Add (
2021-12-03 15:53:09 +01:00
pulseEntity ,
2021-12-01 20:21:17 +00:00
(
_baseShader . Duplicate ( ) ,
new RadiationShaderInstance (
2021-12-05 18:09:01 +01:00
_entityManager . GetComponent < TransformComponent > ( pulseEntity ) . MapPosition . Position ,
2021-12-01 20:21:17 +00:00
pulse . Range ,
pulse . StartTime ,
pulse . EndTime
)
)
) ;
}
2021-11-27 22:53:43 -08:00
}
2021-12-01 20:21:17 +00:00
var activeShaderIds = _pulses . Keys ;
2021-12-05 18:09:01 +01:00
foreach ( var pulseEntity in activeShaderIds ) //Remove all pulses that are added and no longer qualify
2020-08-14 06:52:17 +10:00
{
2021-12-05 18:09:01 +01:00
if ( _entityManager . EntityExists ( pulseEntity ) & &
2021-12-01 20:21:17 +00:00
PulseQualifies ( pulseEntity , currentEyeLoc ) & &
2021-12-05 18:09:01 +01:00
_entityManager . TryGetComponent < RadiationPulseComponent ? > ( pulseEntity , out var pulse ) )
2020-08-14 06:52:17 +10:00
{
2021-12-05 18:09:01 +01:00
var shaderInstance = _pulses [ pulseEntity ] ;
shaderInstance . instance . CurrentMapCoords = _entityManager . GetComponent < TransformComponent > ( pulseEntity ) . MapPosition . Position ;
2021-12-01 20:21:17 +00:00
shaderInstance . instance . Range = pulse . Range ;
} else {
2021-12-05 18:09:01 +01:00
_pulses [ pulseEntity ] . shd . Dispose ( ) ;
_pulses . Remove ( pulseEntity ) ;
2020-08-14 06:52:17 +10:00
}
}
2021-12-01 20:21:17 +00:00
}
2021-12-05 18:09:01 +01:00
private bool PulseQualifies ( EntityUid pulseEntity , MapCoordinates currentEyeLoc )
2021-12-01 20:21:17 +00:00
{
2021-12-05 18:09:01 +01:00
return _entityManager . GetComponent < TransformComponent > ( pulseEntity ) . MapID = = currentEyeLoc . MapId & & _entityManager . GetComponent < TransformComponent > ( pulseEntity ) . Coordinates . InRange ( _entityManager , EntityCoordinates . FromMap ( _entityManager , _entityManager . GetComponent < TransformComponent > ( pulseEntity ) . ParentUid , currentEyeLoc ) , MaxDist ) ;
2020-08-14 06:52:17 +10:00
}
2021-12-01 20:21:17 +00:00
private sealed record RadiationShaderInstance ( Vector2 CurrentMapCoords , float Range , TimeSpan Start , TimeSpan End )
{
public Vector2 CurrentMapCoords = CurrentMapCoords ;
public float Range = Range ;
public TimeSpan Start = Start ;
public TimeSpan End = End ;
} ;
2020-08-14 06:52:17 +10:00
}
2020-09-21 01:49:40 +02:00
}
2021-12-01 20:21:17 +00:00