Skip to content

Commit

Permalink
Merge branch 'master' into Something
Browse files Browse the repository at this point in the history
  • Loading branch information
Vonsant authored Dec 9, 2024
2 parents e4c3f77 + e1a05f2 commit 5cba045
Show file tree
Hide file tree
Showing 62 changed files with 1,220 additions and 19 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<BoxContainer xmlns="https://spacestation14.io"
xmlns:cartridges="clr-namespace:Content.Client._CorvaxNext.CartridgeLoader.Cartridges"
xmlns:customControls="clr-namespace:Content.Client.Administration.UI.CustomControls"
HorizontalExpand="True"
VerticalExpand="True"
Margin="5">
<!-- All labels populated in constructor -->
<BoxContainer Orientation="Horizontal" HorizontalAlignment="Left">
<BoxContainer Orientation="Vertical">
<Label Name="Status"/>
<Label Text="{Loc 'criminal-records-console-reason'}"/>
</BoxContainer>
<customControls:VSeparator StyleClasses="LowDivider" Margin="8 0"/>
<BoxContainer Orientation="Vertical">
<Label Name="Title"/>
<Label Name="Reason"/>
</BoxContainer>
</BoxContainer>
</BoxContainer>
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
using Content.Shared.CartridgeLoader.Cartridges;
using Robust.Client.AutoGenerated;
using Robust.Client.UserInterface;
using Robust.Client.UserInterface.Controls;
using Robust.Client.UserInterface.XAML;

namespace Content.Client._CorvaxNext.CartridgeLoader.Cartridges;

[GenerateTypedNameReferences]
public sealed partial class SecWatchEntryControl : BoxContainer
{
public SecWatchEntryControl(SecWatchEntry entry)
{
RobustXamlLoader.Load(this);

Status.Text = Loc.GetString($"criminal-records-status-{entry.Status.ToString().ToLower()}");
Title.Text = Loc.GetString("sec-watch-entry", ("name", entry.Name), ("job", entry.Job));

Reason.Text = entry.Reason ?? Loc.GetString("sec-watch-no-reason");
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
using Content.Client.UserInterface.Fragments;
using Content.Shared.CartridgeLoader;
using Content.Shared.CartridgeLoader.Cartridges;
using Robust.Client.UserInterface;

namespace Content.Client._CorvaxNext.CartridgeLoader.Cartridges;

public sealed partial class SecWatchUi : UIFragment
{
private SecWatchUiFragment? _fragment;

public override Control GetUIFragmentRoot()
{
return _fragment!;
}

public override void Setup(BoundUserInterface ui, EntityUid? owner)
{
_fragment = new SecWatchUiFragment();
}

public override void UpdateState(BoundUserInterfaceState state)
{
if (state is SecWatchUiState cast)
_fragment?.UpdateState(cast);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<cartridges:SecWatchUiFragment xmlns="https://spacestation14.io"
xmlns:cartridges="clr-namespace:Content.Client._CorvaxNext.CartridgeLoader.Cartridges"
Margin="5"
VerticalExpand="True">
<BoxContainer Orientation="Vertical" HorizontalExpand="True" VerticalExpand="True">
<Label Text="{Loc 'sec-watch-title'}" HorizontalExpand="True" HorizontalAlignment="Center"/>
<Label Name="NoEntries" Text="{Loc 'sec-watch-no-entries'}" HorizontalExpand="True" HorizontalAlignment="Center" Visible="False"/>
<ScrollContainer HorizontalExpand="True" VerticalExpand="True">
<!-- Populated when state received -->
<BoxContainer Name="Entries" Orientation="Vertical" VerticalAlignment="Top"/>
</ScrollContainer>
</BoxContainer>
</cartridges:SecWatchUiFragment>
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
using Content.Shared.CartridgeLoader.Cartridges;
using Robust.Client.AutoGenerated;
using Robust.Client.UserInterface.Controls;
using Robust.Client.UserInterface.XAML;

namespace Content.Client._CorvaxNext.CartridgeLoader.Cartridges;

[GenerateTypedNameReferences]
public sealed partial class SecWatchUiFragment : BoxContainer
{
public SecWatchUiFragment()
{
RobustXamlLoader.Load(this);
}

public void UpdateState(SecWatchUiState state)
{
NoEntries.Visible = state.Entries.Count == 0;
Entries.RemoveAllChildren();
foreach (var entry in state.Entries)
{
Entries.AddChild(new SecWatchEntryControl(entry));
}
}
}
47 changes: 47 additions & 0 deletions Content.Client/_CorvaxNext/Overlays/BaseSwitchableOverlay.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
using Content.Shared._CorvaxNext.Overlays;
using Robust.Client.Graphics;
using Robust.Client.Player;
using Robust.Shared.Enums;
using Robust.Shared.Prototypes;
using System.Numerics;

namespace Content.Client._CorvaxNext.Overlays;

public class BaseSwitchableOverlay<TComp> : Overlay
where TComp : SwitchableOverlayComponent
{
[Dependency] private readonly IPrototypeManager _prototype = default!;
[Dependency] private readonly IPlayerManager _player = default!;
[Dependency] private readonly IEntityManager _entity = default!;

public override bool RequestScreenTexture => true;
public override OverlaySpace Space => OverlaySpace.WorldSpace;
private readonly ShaderInstance _shader;

public BaseSwitchableOverlay()
{
IoCManager.InjectDependencies(this);
_shader = _prototype.Index<ShaderPrototype>("NightVision").Instance().Duplicate();
}

protected override void Draw(in OverlayDrawArgs args)
{
if (ScreenTexture is null
|| _player.LocalEntity is null
|| !_entity.TryGetComponent<TComp>(_player.LocalEntity.Value, out var component)
|| !component.IsActive)
return;

_shader.SetParameter("SCREEN_TEXTURE", ScreenTexture);
_shader.SetParameter("tint", component.Tint);
_shader.SetParameter("luminance_threshold", component.Strength);
_shader.SetParameter("noise_amount", component.Noise);

var worldHandle = args.WorldHandle;

worldHandle.SetTransform(Matrix3x2.Identity);
worldHandle.UseShader(_shader);
worldHandle.DrawRect(args.WorldBounds, component.Color);
worldHandle.UseShader(null);
}
}
85 changes: 85 additions & 0 deletions Content.Client/_CorvaxNext/Overlays/NightVisionSystem.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
using Content.Shared._CorvaxNext.Overlays;
using Content.Shared.GameTicking;
using Robust.Client.Graphics;
using Robust.Client.Player;
using Robust.Shared.Player;

namespace Content.Client._CorvaxNext.Overlays;

public sealed class NightVisionSystem : SwitchableOverlaySystem<NightVisionComponent, ToggleNightVisionEvent>
{
[Dependency] private readonly IPlayerManager _player = default!;
[Dependency] private readonly IOverlayManager _overlayMan = default!;
[Dependency] private readonly ILightManager _lightManager = default!;

private BaseSwitchableOverlay<NightVisionComponent> _overlay = default!;

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

SubscribeLocalEvent<NightVisionComponent, PlayerAttachedEvent>(OnPlayerAttached);
SubscribeLocalEvent<NightVisionComponent, PlayerDetachedEvent>(OnPlayerDetached);
SubscribeLocalEvent<RoundRestartCleanupEvent>(OnRestart);

_overlay = new BaseSwitchableOverlay<NightVisionComponent>();
}

private void OnPlayerAttached(EntityUid uid, NightVisionComponent component, PlayerAttachedEvent args)
{
if (!component.IsActive)
return;

UpdateVision(args.Player, component.IsActive);
}

private void OnPlayerDetached(EntityUid uid, NightVisionComponent component, PlayerDetachedEvent args)
{
UpdateVision(args.Player, false);
}

private void OnRestart(RoundRestartCleanupEvent ev)
{
_overlayMan.RemoveOverlay(_overlay);
_lightManager.DrawLighting = true;
}

protected override void UpdateVision(EntityUid uid, bool active)
{
if (_player.LocalSession?.AttachedEntity != uid)
return;

UpdateOverlay(active);
UpdateNightVision(active);
}

private void UpdateVision(ICommonSession player, bool active)
{
if (_player.LocalSession != player)
return;

UpdateOverlay(active);
UpdateNightVision(active);
}

private void UpdateNightVision(bool active)
{
_lightManager.DrawLighting = !active;
}

private void UpdateOverlay(bool active)
{
if (_player.LocalEntity == null)
{
_overlayMan.RemoveOverlay(_overlay);
return;
}

active |= TryComp<NightVisionComponent>(_player.LocalEntity.Value, out var component) && component.IsActive;

if (active)
_overlayMan.AddOverlay(_overlay);
else
_overlayMan.RemoveOverlay(_overlay);
}
}
130 changes: 130 additions & 0 deletions Content.Client/_CorvaxNext/Overlays/ThermalVisionOverlay.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
using System.Linq;
using System.Numerics;
using Content.Client.Stealth;
using Content.Shared._CorvaxNext.Overlays;
using Content.Shared.Body.Components;
using Content.Shared.Stealth.Components;
using Robust.Client.GameObjects;
using Robust.Client.Graphics;
using Robust.Client.Player;
using Robust.Shared.Enums;
using Robust.Shared.Map;

namespace Content.Client._CorvaxNext.Overlays;

public sealed class ThermalVisionOverlay : Overlay
{
[Dependency] private readonly IEntityManager _entity = default!;
[Dependency] private readonly IPlayerManager _players = default!;

private readonly TransformSystem _transform;
private readonly OccluderSystem _occluder;
private readonly StealthSystem _stealth;
private readonly ContainerSystem _container;

public override bool RequestScreenTexture => true;
public override OverlaySpace Space => OverlaySpace.WorldSpace;

private readonly List<ThermalVisionRenderEntry> _entries = [];

public ThermalVisionOverlay()
{
IoCManager.InjectDependencies(this);

_container = _entity.System<ContainerSystem>();
_transform = _entity.System<TransformSystem>();
_occluder = _entity.System<OccluderSystem>();
_stealth = _entity.System<StealthSystem>();

ZIndex = -1;
}

protected override void Draw(in OverlayDrawArgs args)
{
if (ScreenTexture is null
|| _players.LocalEntity is null
|| !_entity.TryGetComponent<ThermalVisionComponent>(_players.LocalEntity.Value, out var component)
|| !component.IsActive)
return;

var worldHandle = args.WorldHandle;
var eye = args.Viewport.Eye;

if (eye is null)
return;

var mapId = eye.Position.MapId;
var eyeRot = eye.Rotation;

_entries.Clear();
var entities = _entity.EntityQueryEnumerator<BodyComponent, SpriteComponent, TransformComponent>();
while (entities.MoveNext(out var uid, out var body, out var sprite, out var xform))
{
if (!CanSee(uid, sprite, body))
continue;

var entity = uid;

if (_container.TryGetOuterContainer(uid, xform, out var container))
{
var owner = container.Owner;
if (_entity.TryGetComponent<SpriteComponent>(owner, out var ownerSprite)
&& _entity.TryGetComponent<TransformComponent>(owner, out var ownerXform))
{
entity = owner;
sprite = ownerSprite;
xform = ownerXform;
}
}

if (_entries.Any(e => e.Ent.Item1 == entity))
continue;

_entries.Add(new ThermalVisionRenderEntry((entity, sprite, xform, body), mapId, eyeRot));
}

foreach (var entry in _entries)
{
Render(entry.Ent, entry.Map, worldHandle, entry.EyeRot);
}

worldHandle.SetTransform(Matrix3x2.Identity);
}

private void Render(Entity<SpriteComponent, TransformComponent, BodyComponent> ent,
MapId? map,
DrawingHandleWorld handle,
Angle eyeRot)
{
var (uid, sprite, xform, body) = ent;
if (xform.MapID != map || HasOccluders(uid) || !CanSee(uid, sprite, body))
return;

var position = _transform.GetWorldPosition(xform);
var rotation = _transform.GetWorldRotation(xform);

sprite.Render(handle, eyeRot, rotation, position: position);
}

private bool CanSee(EntityUid uid, SpriteComponent sprite, BodyComponent body)
{
return sprite.Visible
&& !_entity.HasComponent<ThermalInvisibilityComponent>(uid)
&& (!_entity.TryGetComponent(uid, out StealthComponent? stealth)
|| _stealth.GetVisibility(uid, stealth) > 0.5f);
}

private bool HasOccluders(EntityUid uid)
{
var mapCoordinates = _transform.GetMapCoordinates(uid);
var occluders = _occluder.QueryAabb(mapCoordinates.MapId,
Box2.CenteredAround(mapCoordinates.Position, new Vector2(0.3f, 0.3f)));

return occluders.Any(o => o.Component.Enabled);
}
}

public record struct ThermalVisionRenderEntry(
(EntityUid, SpriteComponent, TransformComponent, BodyComponent) Ent,
MapId? Map,
Angle EyeRot);
Loading

0 comments on commit 5cba045

Please sign in to comment.