feat: night vision

This commit is contained in:
Remuchi
2024-01-26 17:36:10 +07:00
parent a085815fc5
commit 27e500a7a9
9 changed files with 199 additions and 33 deletions

View 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);
}
}
}

View 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;
}
}

View File

@@ -8,9 +8,8 @@ using Content.Shared.Examine;
using Content.Shared.MedicalScanner;
using Content.Shared.Verbs;
using Content.Shared.White.Item.Tricorder;
using Robust.Server.GameObjects;
using Robust.Server.Audio;
using Robust.Shared.Audio;
using Robust.Shared.GameStates;
using Robust.Shared.Utility;
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)
{
if (!args.CanAccess || !args.CanInteract || !args.Using.HasValue ||
!HasComp<TricorderComponent>(args.Target))
if (!args.CanAccess || !args.CanInteract || !args.Using.HasValue || !HasComp<TricorderComponent>(args.Target))
{
return;
}
@@ -100,44 +98,41 @@ public sealed class TricorderSystem : SharedTricorderSystem
if (!user.HasValue)
return;
UpdateModeAppearance(user.Value, tricorder);
UpdateModeAppearance(user.Value, tricoderUid, tricorder);
}
private void UpdateModeAppearance(
EntityUid userUid,
TricorderComponent tricorder)
private void UpdateModeAppearance(EntityUid userUid, EntityUid tricoderUid, TricorderComponent tricorder)
{
Dirty(tricorder);
_audioSystem.PlayPvs(tricorder.SoundSwitchMode, userUid, AudioParams.Default.WithVolume(1.5f));
Dirty(tricoderUid, tricorder);
}
private void SetToMultitool(EntityUid uid)
{
var comp = AddComp<NetworkConfiguratorComponent>(uid);
RemComp<GasAnalyzerComponent>(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)
{
RemComp<NetworkConfiguratorComponent>(uid);
AddComp<GasAnalyzerComponent>(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)
@@ -147,15 +142,12 @@ public sealed class TricorderSystem : SharedTricorderSystem
var healthAnalyzerComponent = _componentFactory.GetComponent<HealthAnalyzerComponent>();
healthAnalyzerComponent.ScanningEndSound = new SoundPathSpecifier("/Audio/Items/Medical/healthscanner.ogg");
healthAnalyzerComponent.Owner = uid;
_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;
}
}
}

View File

@@ -23,9 +23,6 @@
<Private>false</Private>
</ProjectReference>
</ItemGroup>
<ItemGroup>
<Folder Include="White\Other" />
</ItemGroup>
<Import Project="..\RobustToolbox\MSBuild\Robust.Properties.targets" />
<Import Project="..\RobustToolbox\MSBuild\Robust.CompNetworkGenerator.targets" />
</Project>

View File

@@ -4,10 +4,8 @@ using Robust.Shared.Serialization;
namespace Content.Shared.White.Item.Tricorder;
[RegisterComponent]
[NetworkedComponent]
[Access(typeof(SharedTricorderSystem))]
public sealed class TricorderComponent : Component
[RegisterComponent, NetworkedComponent, Access(typeof(SharedTricorderSystem))]
public sealed partial class TricorderComponent : Component
{
[DataField("currentState"), ViewVariables(VVAccess.ReadWrite)]
public TricorderMode CurrentMode = TricorderMode.Multitool;
@@ -35,4 +33,4 @@ public enum TricorderMode
Multitool,
GasAnalyzer,
HealthAnalyzer
}
}

View 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");
}

View File

@@ -100,6 +100,11 @@
kind: source
path: "/Textures/Shaders/cataracts.swsl"
- type: shader
id: NightVision
kind: source
path: "/Textures/Shaders/White/nightvision.swsl"
- type: shader
id: SaturationScale
kind: source

View File

@@ -17,6 +17,7 @@
- type: entity
parent: ClothingEyesNightVisionGoggles
id: ClothingEyesNightVisionGogglesSyndie
suffix: "Хамелеон"
components:
- type: ChameleonClothing
slot: [ eyes ]

View 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;
}