Skip to content

Commit

Permalink
Рабочие термальные очки
Browse files Browse the repository at this point in the history
  • Loading branch information
VigersRay committed Feb 10, 2025
1 parent 6feef16 commit dce3d63
Show file tree
Hide file tree
Showing 11 changed files with 347 additions and 1 deletion.
61 changes: 61 additions & 0 deletions Content.Client/_Sunrise/ThermalVision/ThermalVisionOverlay.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
using Content.Shared._Sunrise.ThermalVision;
using Robust.Client.GameObjects;
using Robust.Client.Graphics;
using Robust.Client.Player;
using Robust.Shared.Enums;
using Robust.Shared.Prototypes;

namespace Content.Client._Sunrise.ThermalVision;

public sealed class ThermalVisionOverlay : Overlay
{
[Dependency] private readonly IEntityManager _entityManager = default!;
[Dependency] private readonly IPlayerManager _playerManager = default!;
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
private readonly TransformSystem _transform;
public override bool RequestScreenTexture => true;
public override OverlaySpace Space => OverlaySpace.WorldSpace;
private readonly ShaderInstance _screenShader;
public ThermalVisionOverlay()
{
IoCManager.InjectDependencies(this);
_screenShader = _prototypeManager.Index<ShaderPrototype>("ThermalVisionScreenShader").InstanceUnique();
_transform = _entityManager.System<TransformSystem>();
ZIndex = 10000;
}

protected override bool BeforeDraw(in OverlayDrawArgs args)
{
if (!_entityManager.TryGetComponent(_playerManager.LocalSession?.AttachedEntity, out EyeComponent? eyeComp))
return false;

if (args.Viewport.Eye != eyeComp.Eye)
return false;

var playerEntity = _playerManager.LocalSession?.AttachedEntity;

if (playerEntity == null)
return false;

if (!_entityManager.TryGetComponent<ThermalVisionComponent>(playerEntity, out var blurComp))
return false;

return true;
}

protected override void Draw(in OverlayDrawArgs args)
{
if (ScreenTexture == null)
return;

var worldHandle = args.WorldHandle;
var viewport = args.WorldBounds;
var eyeRotation = args.Viewport.Eye?.Rotation ?? Angle.Zero;

_screenShader.SetParameter("SCREEN_TEXTURE", ScreenTexture);

worldHandle.UseShader(_screenShader);
worldHandle.DrawRect(viewport, Color.White);
worldHandle.UseShader(null);
}
}
83 changes: 83 additions & 0 deletions Content.Client/_Sunrise/ThermalVision/ThermalVisionSystem.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
using Content.Shared._Sunrise.ThermalVision;
using Content.Shared.Eye.Blinding.Components;
using Robust.Client.GameObjects;
using Robust.Client.Graphics;
using Robust.Client.Player;
using Robust.Shared.Player;
using Robust.Shared.Prototypes;

namespace Content.Client._Sunrise.ThermalVision;

public sealed class ThermalVisionSystem : EntitySystem
{
[Dependency] private readonly IPlayerManager _player = default!;
[Dependency] private readonly IOverlayManager _overlayMan = default!;
[Dependency] private readonly TransformSystem _xformSys = default!;
private ThroughWallsVisionOverlay _throughWallsOverlay = default!;
private ThermalVisionOverlay _overlay = default!;

private EntityUid? _effect = null;
private readonly EntProtoId _effectPrototype = "EffectThermalVision";

public override void Initialize()
{
base.Initialize();

SubscribeLocalEvent<ThermalVisionComponent, ComponentInit>(OnVisionInit);
SubscribeLocalEvent<ThermalVisionComponent, ComponentShutdown>(OnVisionShutdown);

SubscribeLocalEvent<ThermalVisionComponent, LocalPlayerAttachedEvent>(OnPlayerAttached);
SubscribeLocalEvent<ThermalVisionComponent, LocalPlayerDetachedEvent>(OnPlayerDetached);

_throughWallsOverlay = new();
_overlay = new();
}

private void OnPlayerAttached(Entity<ThermalVisionComponent> ent, ref LocalPlayerAttachedEvent args)
{
if (_effect == null)
AddNightVision(ent.Owner);
else if (HasComp<EyeProtectionComponent>(ent.Owner))
RemoveNightVision();
}

private void OnPlayerDetached(Entity<ThermalVisionComponent> ent, ref LocalPlayerDetachedEvent args)
{
RemoveNightVision();
}

private void OnVisionInit(Entity<ThermalVisionComponent> ent, ref ComponentInit args)
{
if (_player.LocalEntity != ent.Owner)
return;

if (_effect == null)
AddNightVision(ent.Owner);
else if (HasComp<EyeProtectionComponent>(ent.Owner))
RemoveNightVision();
}

private void OnVisionShutdown(Entity<ThermalVisionComponent> ent, ref ComponentShutdown args)
{
if (_player.LocalEntity != ent.Owner) return;

RemoveNightVision();
}

private void AddNightVision(EntityUid uid)
{
if (HasComp<EyeProtectionComponent>(uid)) return;

_overlayMan.AddOverlay(_throughWallsOverlay);
_overlayMan.AddOverlay(_overlay);
_effect = SpawnAttachedTo(_effectPrototype, Transform(uid).Coordinates);
_xformSys.SetParent(_effect.Value, uid);
}
private void RemoveNightVision()
{
_overlayMan.RemoveOverlay(_throughWallsOverlay);
_overlayMan.RemoveOverlay(_overlay);
Del(_effect);
_effect = null;
}
}
71 changes: 71 additions & 0 deletions Content.Client/_Sunrise/ThermalVision/ThroughWallsVisionOverlay.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
using Content.Shared._Sunrise.ThermalVision;
using Content.Shared.Body.Components;
using Robust.Client.GameObjects;
using Robust.Client.Graphics;
using Robust.Client.Player;
using Robust.Shared.Enums;
using Robust.Shared.Prototypes;

namespace Content.Client._Sunrise.ThermalVision;

public sealed class ThroughWallsVisionOverlay : Overlay
{
[Dependency] private readonly IEntityManager _entityManager = default!;
[Dependency] private readonly IPlayerManager _playerManager = default!;
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
private readonly ContainerSystem _containerSystem;
private readonly TransformSystem _transform;
private readonly ShaderInstance _shader;

public override bool RequestScreenTexture => true;
public override OverlaySpace Space => OverlaySpace.WorldSpace;
public ThroughWallsVisionOverlay()
{
IoCManager.InjectDependencies(this);
_transform = _entityManager.System<TransformSystem>();
_containerSystem = _entityManager.System<ContainerSystem>();

_shader = _prototypeManager.Index<ShaderPrototype>("BrightnessShader").InstanceUnique();
}

protected override bool BeforeDraw(in OverlayDrawArgs args)
{
if (!_entityManager.TryGetComponent(_playerManager.LocalSession?.AttachedEntity, out EyeComponent? eyeComp))
return false;

if (args.Viewport.Eye != eyeComp.Eye)
return false;

var playerEntity = _playerManager.LocalSession?.AttachedEntity;

if (playerEntity == null)
return false;

if (!_entityManager.TryGetComponent<ThermalVisionComponent>(playerEntity, out var blurComp))
return false;

return true;
}

protected override void Draw(in OverlayDrawArgs args)
{
if (ScreenTexture == null)
return;

var worldHandle = args.WorldHandle;
var viewport = args.WorldBounds;
var eyeRotation = args.Viewport.Eye?.Rotation ?? Angle.Zero;

worldHandle.UseShader(_shader);
var query = _entityManager.EntityQueryEnumerator<BodyComponent, MetaDataComponent, SpriteComponent, TransformComponent>();
while (query.MoveNext(out var uid, out _, out var meta, out var sprite, out var xform))
{
if (xform.MapID != args.MapId || _containerSystem.IsEntityInContainer(uid, meta)) continue;
var (position, rotation) = _transform.GetWorldPositionRotation(xform);

sprite.Render(worldHandle, eyeRotation, rotation, null, position);
}

worldHandle.UseShader(null);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
using Robust.Shared.GameStates;

namespace Content.Shared._Sunrise.ThermalVision;

[RegisterComponent]
[NetworkedComponent]
public sealed partial class ThermalVisionComponent : Component
{
}
11 changes: 11 additions & 0 deletions Resources/Changelog/ChangelogSunrise.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12015,3 +12015,14 @@
type: Fix
id: 827
time: '2025-02-10T01:32:35.194700+00:00'
- author: VigersRay
changes:
- message: "\u0422\u0435\u0440\u043C\u0430\u043B\u044C\u043D\u044B\u0435 \u043E\u0447\
\u043A\u0438 \u0442\u0435\u043F\u0435\u0440\u044C \u0440\u0430\u0431\u043E\u0442\
\u0430\u044E\u0442 \u0438 \u043F\u043E\u0437\u0432\u043E\u043B\u044F\u044E\u0442\
\ \u0432\u0438\u0434\u0435\u0442\u044C \u0441\u0443\u0449\u0435\u0441\u0442\u0432\
\ \u0437\u0430 \u0441\u0442\u0435\u043D\u0430\u043C\u0438 \u0430 \u0442\u0430\
\u043A \u0436\u0435 \u043D\u0435\u0432\u0438\u0434\u0438\u043C\u043E\u043A."
type: Tweak
id: 828
time: '2025-02-10T04:43:25.594250+00:00'
11 changes: 10 additions & 1 deletion Resources/Prototypes/Entities/Clothing/Eyes/glasses.yml
Original file line number Diff line number Diff line change
Expand Up @@ -223,7 +223,7 @@

#Make a scanner category when these actually function and we get the trayson
- type: entity
parent: ClothingEyesBase
parent: [ClothingEyesBase, BaseToggleClothing]
id: ClothingEyesGlassesThermal
name: optical thermal scanner
description: Thermals in the shape of glasses.
Expand All @@ -239,6 +239,15 @@
- type: GroupExamine
- type: IdentityBlocker
coverage: EYES
# Sunrise-Start
- type: ToggleClothing
action: ActionToggleThermalVision
disableOnUnequip: true
- type: ComponentToggler
parent: true
components:
- type: ThermalVision
# Sunrise-End

- type: entity
parent: ClothingEyesBase
Expand Down
9 changes: 9 additions & 0 deletions Resources/Prototypes/_Sunrise/Actions/thermal.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
- type: entity
id: ActionToggleThermalVision
name: toggle thermal vision
description: Toggle thermal vision on or off.
components:
- type: InstantAction
useDelay: 5
priority: -9
event: !type:ToggleActionEvent
15 changes: 15 additions & 0 deletions Resources/Prototypes/_Sunrise/Shaders/sharders.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,18 @@
id: NoMirageStealth
kind: source
path: "/Textures/_Sunrise/Shaders/no_mirage_stealth.swsl"

- type: shader
id: ThermalVisionScreenShader
kind: source
path: "/Textures/_Sunrise/Shaders/thermal_screen.swsl"
params:
ThermalBoost: 1.5
ThermalIntensity: 1

- type: shader
id: BrightnessShader
kind: source
path: "/Textures/_Sunrise/Shaders/brightness.swsl"
params:
brightness: 1.5
10 changes: 10 additions & 0 deletions Resources/Prototypes/_Sunrise/ThermalVision/light.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
- type: entity
id: EffectThermalVision
categories: [ HideSpawnMenu ]
name: thermal vision
components:
- type: PointLight
color: "#FFE4D6"
energy: 1.8
radius: 20
softness: 20
8 changes: 8 additions & 0 deletions Resources/Textures/_Sunrise/Shaders/brightness.swsl
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
uniform highp float brightness;

void fragment() {
highp vec4 col = zTexture(UV);
col.rgb *= brightness;
COLOR = col;
lightSample = vec3(1.0);
}
60 changes: 60 additions & 0 deletions Resources/Textures/_Sunrise/Shaders/thermal_screen.swsl
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
uniform sampler2D SCREEN_TEXTURE;

uniform highp float ThermalBoost;
uniform highp float ThermalIntensity;

const highp vec3 cBlack = vec3(0.00, 0.00, 0.00);
const highp vec3 cBlue = vec3(0.00, 0.00, 0.65);
const highp vec3 cGreen = vec3(0.00, 0.65, 0.00);
const highp vec3 cYellow = vec3(0.65, 0.65, 0.00);
const highp vec3 cRed = vec3(0.65, 0.00, 0.00);
const highp vec3 cWhite = vec3(0.65, 0.65, 0.65);

highp vec3 getThermalColor(in highp float t)
{
// 0.0..0.2: black -> blue
// 0.2..0.4: blue -> green
// 0.4..0.6: green -> yellow
// 0.6..0.8: yellow-> red
// 0.8..1.0: red -> white

if (t < 0.2)
{
highp float alpha = t / 0.2;
return mix(cBlack, cBlue, alpha);
}
else if (t < 0.4)
{
highp float alpha = (t - 0.2) / 0.2;
return mix(cBlue, cGreen, alpha);
}
else if (t < 0.6)
{
highp float alpha = (t - 0.4) / 0.2;
return mix(cGreen, cYellow, alpha);
}
else if (t < 0.8)
{
highp float alpha = (t - 0.6) / 0.2;
return mix(cYellow, cRed, alpha);
}
else
{
highp float alpha = (t - 0.8) / 0.2;
return mix(cRed, cWhite, alpha);
}
}

void fragment()
{
COLOR = zTextureSpec(SCREEN_TEXTURE, Pos);

highp float lum = dot(COLOR.rgb, vec3(0.299, 0.587, 0.114));

lum *= ThermalBoost;
lum = clamp(lum, 0.0, 1.0);

highp vec3 thermalColor = getThermalColor(lum);

COLOR.rgb = mix(COLOR.rgb, thermalColor, ThermalIntensity);
}

0 comments on commit dce3d63

Please sign in to comment.