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.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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
path: "/Textures/Shaders/cataracts.swsl"
|
||||
|
||||
- type: shader
|
||||
id: NightVision
|
||||
kind: source
|
||||
path: "/Textures/Shaders/White/nightvision.swsl"
|
||||
|
||||
- type: shader
|
||||
id: SaturationScale
|
||||
kind: source
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
- type: entity
|
||||
parent: ClothingEyesNightVisionGoggles
|
||||
id: ClothingEyesNightVisionGogglesSyndie
|
||||
suffix: "Хамелеон"
|
||||
components:
|
||||
- type: ChameleonClothing
|
||||
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