feat: night vision
This commit is contained in:
50
Content.Client/White/Overlays/NightVisionOverlay.cs
Normal file
50
Content.Client/White/Overlays/NightVisionOverlay.cs
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
using Content.Shared.White.Overlays;
|
||||||
|
using Robust.Client.Graphics;
|
||||||
|
using Robust.Client.Player;
|
||||||
|
using Robust.Shared.Enums;
|
||||||
|
using Robust.Shared.Prototypes;
|
||||||
|
|
||||||
|
namespace Content.Client.White.Overlays
|
||||||
|
{
|
||||||
|
public sealed class NightVisionOverlay : Overlay
|
||||||
|
{
|
||||||
|
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
|
||||||
|
[Dependency] private readonly IPlayerManager _playerManager = default!;
|
||||||
|
[Dependency] private readonly IEntityManager _entityManager = default!;
|
||||||
|
|
||||||
|
public override bool RequestScreenTexture => true;
|
||||||
|
|
||||||
|
public override OverlaySpace Space => OverlaySpace.WorldSpace;
|
||||||
|
|
||||||
|
private readonly ShaderInstance _shader;
|
||||||
|
|
||||||
|
public NightVisionOverlay()
|
||||||
|
{
|
||||||
|
IoCManager.InjectDependencies(this);
|
||||||
|
_shader = _prototypeManager.Index<ShaderPrototype>("NightVision").InstanceUnique();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void Draw(in OverlayDrawArgs args)
|
||||||
|
{
|
||||||
|
if (ScreenTexture == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
var handle = args.WorldHandle;
|
||||||
|
|
||||||
|
if (!_entityManager.TryGetComponent<NightVisionComponent>(_playerManager.LocalSession?.AttachedEntity,
|
||||||
|
out var component))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_shader.SetParameter("SCREEN_TEXTURE", ScreenTexture);
|
||||||
|
_shader.SetParameter("tint", component.Tint);
|
||||||
|
_shader.SetParameter("luminance_threshold", component.Strength);
|
||||||
|
_shader.SetParameter("noise_amount", component.Noise);
|
||||||
|
|
||||||
|
handle.UseShader(_shader);
|
||||||
|
handle.DrawRect(args.WorldBounds, component.Color);
|
||||||
|
handle.UseShader(null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
66
Content.Client/White/Overlays/NightVisionSystem.cs
Normal file
66
Content.Client/White/Overlays/NightVisionSystem.cs
Normal file
@@ -0,0 +1,66 @@
|
|||||||
|
using Content.Shared.GameTicking;
|
||||||
|
using Content.Shared.White.Overlays;
|
||||||
|
using Robust.Client.Graphics;
|
||||||
|
using Robust.Client.Player;
|
||||||
|
using Robust.Shared.Player;
|
||||||
|
|
||||||
|
namespace Content.Client.White.Overlays;
|
||||||
|
|
||||||
|
public sealed class NightVisionSystem : EntitySystem
|
||||||
|
{
|
||||||
|
[Dependency] private readonly IPlayerManager _player = default!;
|
||||||
|
[Dependency] private readonly IOverlayManager _overlayMan = default!;
|
||||||
|
[Dependency] private readonly ILightManager _lightManager = default!;
|
||||||
|
|
||||||
|
private NightVisionOverlay _overlay = default!;
|
||||||
|
|
||||||
|
public override void Initialize()
|
||||||
|
{
|
||||||
|
base.Initialize();
|
||||||
|
|
||||||
|
SubscribeLocalEvent<NightVisionComponent, ComponentInit>(OnInit);
|
||||||
|
SubscribeLocalEvent<NightVisionComponent, ComponentRemove>(OnRemove);
|
||||||
|
|
||||||
|
SubscribeLocalEvent<NightVisionComponent, PlayerAttachedEvent>(OnPlayerAttached);
|
||||||
|
SubscribeLocalEvent<NightVisionComponent, PlayerDetachedEvent>(OnPlayerDetached);
|
||||||
|
SubscribeLocalEvent<RoundRestartCleanupEvent>(OnRestart);
|
||||||
|
|
||||||
|
_overlay = new NightVisionOverlay();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnPlayerAttached(EntityUid uid, NightVisionComponent component, PlayerAttachedEvent args)
|
||||||
|
{
|
||||||
|
_overlayMan.AddOverlay(_overlay);
|
||||||
|
_lightManager.DrawLighting = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnPlayerDetached(EntityUid uid, NightVisionComponent component, PlayerDetachedEvent args)
|
||||||
|
{
|
||||||
|
_overlayMan.RemoveOverlay(_overlay);
|
||||||
|
_lightManager.DrawLighting = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnInit(EntityUid uid, NightVisionComponent component, ComponentInit args)
|
||||||
|
{
|
||||||
|
if (_player.LocalSession?.AttachedEntity != uid)
|
||||||
|
return;
|
||||||
|
|
||||||
|
_overlayMan.AddOverlay(_overlay);
|
||||||
|
_lightManager.DrawLighting = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnRemove(EntityUid uid, NightVisionComponent component, ComponentRemove args)
|
||||||
|
{
|
||||||
|
if (_player.LocalSession?.AttachedEntity != uid)
|
||||||
|
return;
|
||||||
|
|
||||||
|
_overlayMan.RemoveOverlay(_overlay);
|
||||||
|
_lightManager.DrawLighting = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnRestart(RoundRestartCleanupEvent ev)
|
||||||
|
{
|
||||||
|
_overlayMan.RemoveOverlay(_overlay);
|
||||||
|
_lightManager.DrawLighting = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -8,9 +8,8 @@ using Content.Shared.Examine;
|
|||||||
using Content.Shared.MedicalScanner;
|
using Content.Shared.MedicalScanner;
|
||||||
using Content.Shared.Verbs;
|
using Content.Shared.Verbs;
|
||||||
using Content.Shared.White.Item.Tricorder;
|
using Content.Shared.White.Item.Tricorder;
|
||||||
using Robust.Server.GameObjects;
|
using Robust.Server.Audio;
|
||||||
using Robust.Shared.Audio;
|
using Robust.Shared.Audio;
|
||||||
using Robust.Shared.GameStates;
|
|
||||||
using Robust.Shared.Utility;
|
using Robust.Shared.Utility;
|
||||||
|
|
||||||
namespace Content.Server.White.Items.Tricorder;
|
namespace Content.Server.White.Items.Tricorder;
|
||||||
@@ -38,8 +37,7 @@ public sealed class TricorderSystem : SharedTricorderSystem
|
|||||||
|
|
||||||
private void OnAddSwitchModeVerbs(EntityUid uid, TricorderComponent component, GetVerbsEvent<AlternativeVerb> args)
|
private void OnAddSwitchModeVerbs(EntityUid uid, TricorderComponent component, GetVerbsEvent<AlternativeVerb> args)
|
||||||
{
|
{
|
||||||
if (!args.CanAccess || !args.CanInteract || !args.Using.HasValue ||
|
if (!args.CanAccess || !args.CanInteract || !args.Using.HasValue || !HasComp<TricorderComponent>(args.Target))
|
||||||
!HasComp<TricorderComponent>(args.Target))
|
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -100,44 +98,41 @@ public sealed class TricorderSystem : SharedTricorderSystem
|
|||||||
if (!user.HasValue)
|
if (!user.HasValue)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
UpdateModeAppearance(user.Value, tricorder);
|
UpdateModeAppearance(user.Value, tricoderUid, tricorder);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void UpdateModeAppearance(
|
private void UpdateModeAppearance(EntityUid userUid, EntityUid tricoderUid, TricorderComponent tricorder)
|
||||||
EntityUid userUid,
|
|
||||||
TricorderComponent tricorder)
|
|
||||||
{
|
{
|
||||||
Dirty(tricorder);
|
|
||||||
_audioSystem.PlayPvs(tricorder.SoundSwitchMode, userUid, AudioParams.Default.WithVolume(1.5f));
|
_audioSystem.PlayPvs(tricorder.SoundSwitchMode, userUid, AudioParams.Default.WithVolume(1.5f));
|
||||||
|
Dirty(tricoderUid, tricorder);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void SetToMultitool(EntityUid uid)
|
private void SetToMultitool(EntityUid uid)
|
||||||
{
|
{
|
||||||
var comp = AddComp<NetworkConfiguratorComponent>(uid);
|
|
||||||
RemComp<GasAnalyzerComponent>(uid);
|
RemComp<GasAnalyzerComponent>(uid);
|
||||||
RemComp<HealthAnalyzerComponent>(uid);
|
RemComp<HealthAnalyzerComponent>(uid);
|
||||||
Dirty(comp);
|
|
||||||
|
|
||||||
if (!TryComp(uid, out ActivatableUIComponent? ui))
|
var comp = AddComp<NetworkConfiguratorComponent>(uid);
|
||||||
|
if (TryComp(uid, out ActivatableUIComponent? ui))
|
||||||
{
|
{
|
||||||
return;
|
ui.Key = NetworkConfiguratorUiKey.Configure;
|
||||||
}
|
}
|
||||||
|
|
||||||
ui.Key = NetworkConfiguratorUiKey.Configure;
|
Dirty(uid, comp);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void SetToGasAnalyzer(EntityUid uid)
|
private void SetToGasAnalyzer(EntityUid uid)
|
||||||
{
|
{
|
||||||
RemComp<NetworkConfiguratorComponent>(uid);
|
RemComp<NetworkConfiguratorComponent>(uid);
|
||||||
AddComp<GasAnalyzerComponent>(uid);
|
|
||||||
RemComp<HealthAnalyzerComponent>(uid);
|
RemComp<HealthAnalyzerComponent>(uid);
|
||||||
|
|
||||||
if (!TryComp(uid, out ActivatableUIComponent? ui))
|
var comp = AddComp<GasAnalyzerComponent>(uid);
|
||||||
|
if (TryComp(uid, out ActivatableUIComponent? ui))
|
||||||
{
|
{
|
||||||
return;
|
ui.Key = GasAnalyzerComponent.GasAnalyzerUiKey.Key;
|
||||||
}
|
}
|
||||||
|
|
||||||
ui.Key = GasAnalyzerComponent.GasAnalyzerUiKey.Key;
|
Dirty(uid, comp);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void SetToHealthAnalyzer(EntityUid uid)
|
private void SetToHealthAnalyzer(EntityUid uid)
|
||||||
@@ -147,15 +142,12 @@ public sealed class TricorderSystem : SharedTricorderSystem
|
|||||||
|
|
||||||
var healthAnalyzerComponent = _componentFactory.GetComponent<HealthAnalyzerComponent>();
|
var healthAnalyzerComponent = _componentFactory.GetComponent<HealthAnalyzerComponent>();
|
||||||
healthAnalyzerComponent.ScanningEndSound = new SoundPathSpecifier("/Audio/Items/Medical/healthscanner.ogg");
|
healthAnalyzerComponent.ScanningEndSound = new SoundPathSpecifier("/Audio/Items/Medical/healthscanner.ogg");
|
||||||
|
|
||||||
healthAnalyzerComponent.Owner = uid;
|
healthAnalyzerComponent.Owner = uid;
|
||||||
|
|
||||||
_entityManager.AddComponent(uid, healthAnalyzerComponent);
|
_entityManager.AddComponent(uid, healthAnalyzerComponent);
|
||||||
|
if (TryComp(uid, out ActivatableUIComponent? ui))
|
||||||
if (!TryComp(uid, out ActivatableUIComponent? ui))
|
|
||||||
{
|
{
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
ui.Key = HealthAnalyzerUiKey.Key;
|
ui.Key = HealthAnalyzerUiKey.Key;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -23,9 +23,6 @@
|
|||||||
<Private>false</Private>
|
<Private>false</Private>
|
||||||
</ProjectReference>
|
</ProjectReference>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
|
||||||
<Folder Include="White\Other" />
|
|
||||||
</ItemGroup>
|
|
||||||
<Import Project="..\RobustToolbox\MSBuild\Robust.Properties.targets" />
|
<Import Project="..\RobustToolbox\MSBuild\Robust.Properties.targets" />
|
||||||
<Import Project="..\RobustToolbox\MSBuild\Robust.CompNetworkGenerator.targets" />
|
<Import Project="..\RobustToolbox\MSBuild\Robust.CompNetworkGenerator.targets" />
|
||||||
</Project>
|
</Project>
|
||||||
|
|||||||
@@ -4,10 +4,8 @@ using Robust.Shared.Serialization;
|
|||||||
|
|
||||||
namespace Content.Shared.White.Item.Tricorder;
|
namespace Content.Shared.White.Item.Tricorder;
|
||||||
|
|
||||||
[RegisterComponent]
|
[RegisterComponent, NetworkedComponent, Access(typeof(SharedTricorderSystem))]
|
||||||
[NetworkedComponent]
|
public sealed partial class TricorderComponent : Component
|
||||||
[Access(typeof(SharedTricorderSystem))]
|
|
||||||
public sealed class TricorderComponent : Component
|
|
||||||
{
|
{
|
||||||
[DataField("currentState"), ViewVariables(VVAccess.ReadWrite)]
|
[DataField("currentState"), ViewVariables(VVAccess.ReadWrite)]
|
||||||
public TricorderMode CurrentMode = TricorderMode.Multitool;
|
public TricorderMode CurrentMode = TricorderMode.Multitool;
|
||||||
|
|||||||
19
Content.Shared/White/Overlays/NightVisionComponent.cs
Normal file
19
Content.Shared/White/Overlays/NightVisionComponent.cs
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
using Robust.Shared.GameStates;
|
||||||
|
|
||||||
|
namespace Content.Shared.White.Overlays;
|
||||||
|
|
||||||
|
[RegisterComponent, NetworkedComponent, AutoGenerateComponentState]
|
||||||
|
public sealed partial class NightVisionComponent : Component
|
||||||
|
{
|
||||||
|
[DataField("tint"), ViewVariables(VVAccess.ReadWrite), AutoNetworkedField]
|
||||||
|
public Vector3 Tint = new(0.3f, 0.3f, 0.3f);
|
||||||
|
|
||||||
|
[DataField("strength"), ViewVariables(VVAccess.ReadWrite), AutoNetworkedField]
|
||||||
|
public float Strength = 2f;
|
||||||
|
|
||||||
|
[DataField("noise"), ViewVariables(VVAccess.ReadWrite), AutoNetworkedField]
|
||||||
|
public float Noise = 0.5f;
|
||||||
|
|
||||||
|
[DataField("color"), ViewVariables(VVAccess.ReadWrite), AutoNetworkedField]
|
||||||
|
public Color Color = Color.FromHex("#98FB98");
|
||||||
|
}
|
||||||
@@ -100,6 +100,11 @@
|
|||||||
kind: source
|
kind: source
|
||||||
path: "/Textures/Shaders/cataracts.swsl"
|
path: "/Textures/Shaders/cataracts.swsl"
|
||||||
|
|
||||||
|
- type: shader
|
||||||
|
id: NightVision
|
||||||
|
kind: source
|
||||||
|
path: "/Textures/Shaders/White/nightvision.swsl"
|
||||||
|
|
||||||
- type: shader
|
- type: shader
|
||||||
id: SaturationScale
|
id: SaturationScale
|
||||||
kind: source
|
kind: source
|
||||||
|
|||||||
@@ -17,6 +17,7 @@
|
|||||||
- type: entity
|
- type: entity
|
||||||
parent: ClothingEyesNightVisionGoggles
|
parent: ClothingEyesNightVisionGoggles
|
||||||
id: ClothingEyesNightVisionGogglesSyndie
|
id: ClothingEyesNightVisionGogglesSyndie
|
||||||
|
suffix: "Хамелеон"
|
||||||
components:
|
components:
|
||||||
- type: ChameleonClothing
|
- type: ChameleonClothing
|
||||||
slot: [ eyes ]
|
slot: [ eyes ]
|
||||||
|
|||||||
38
Resources/Textures/Shaders/White/nightvision.swsl
Normal file
38
Resources/Textures/Shaders/White/nightvision.swsl
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
light_mode unshaded;
|
||||||
|
|
||||||
|
uniform sampler2D SCREEN_TEXTURE;
|
||||||
|
uniform highp vec3 tint; // Colour of the tint
|
||||||
|
uniform highp float luminance_threshold; // number between 0 and 1
|
||||||
|
uniform highp float noise_amount; // number between 0 and 1
|
||||||
|
|
||||||
|
lowp float rand (lowp vec2 n) {
|
||||||
|
return 0.5 + 0.5 * fract (sin (dot (n.xy, vec2 (12.9898, 78.233)))* 43758.5453);
|
||||||
|
}
|
||||||
|
|
||||||
|
void fragment() {
|
||||||
|
|
||||||
|
highp vec4 color = zTextureSpec(SCREEN_TEXTURE, FRAGCOORD.xy * SCREEN_PIXEL_SIZE);
|
||||||
|
|
||||||
|
// convert color to grayscale using luminance
|
||||||
|
highp float grey = dot(color.rgb, vec3(0.298, 0.5882, 0.1137));
|
||||||
|
|
||||||
|
// calculate local threshold
|
||||||
|
highp float threshold = grey * luminance_threshold;
|
||||||
|
|
||||||
|
// amplify low luminance parts
|
||||||
|
if (grey < threshold) {
|
||||||
|
grey += (threshold - grey) * 0.5;
|
||||||
|
if (grey > 1.0) {
|
||||||
|
grey = 1.0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// apply night vision color tint
|
||||||
|
color.rgb = mix(color.rgb, tint, grey);
|
||||||
|
|
||||||
|
// add some noise for realism
|
||||||
|
lowp float noise = rand(FRAGCOORD.xy + TIME) * noise_amount / 10.0;
|
||||||
|
color.rgb += noise;
|
||||||
|
|
||||||
|
COLOR = color;
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user