6
2025-08-05 10:00:54 +03:00

129 lines
4.6 KiB
C#

using System.Numerics;
using Content.Shared.Silicons.StationAi;
using Robust.Client.Graphics;
using Robust.Client.Player;
using Robust.Shared.Enums;
using Robust.Shared.Map.Components;
using Robust.Shared.Physics;
using Robust.Shared.Prototypes;
using Robust.Shared.Timing;
namespace Content.Client.Silicons.StationAi;
public sealed class StationAiOverlay : Overlay
{
[Dependency] private readonly IClyde _clyde = default!;
[Dependency] private readonly IEntityManager _entManager = default!;
[Dependency] private readonly IGameTiming _timing = default!;
[Dependency] private readonly IPlayerManager _player = default!;
[Dependency] private readonly IPrototypeManager _proto = default!;
public override OverlaySpace Space => OverlaySpace.WorldSpace;
private readonly HashSet<Vector2i> _visibleTiles = new();
private IRenderTexture? _staticTexture;
private IRenderTexture? _stencilTexture;
private float _updateRate = 1f / 30f;
private float _accumulator;
public StationAiOverlay()
{
IoCManager.InjectDependencies(this);
}
protected override void Draw(in OverlayDrawArgs args)
{
if (_stencilTexture?.Texture.Size != args.Viewport.Size)
{
_staticTexture?.Dispose();
_stencilTexture?.Dispose();
_stencilTexture = _clyde.CreateRenderTarget(args.Viewport.Size, new RenderTargetFormatParameters(RenderTargetColorFormat.Rgba8Srgb), name: "station-ai-stencil");
_staticTexture = _clyde.CreateRenderTarget(args.Viewport.Size,
new RenderTargetFormatParameters(RenderTargetColorFormat.Rgba8Srgb),
name: "station-ai-static");
}
var worldHandle = args.WorldHandle;
var worldBounds = args.WorldBounds;
var playerEnt = _player.LocalEntity;
_entManager.TryGetComponent(playerEnt, out TransformComponent? playerXform);
var gridUid = playerXform?.GridUid ?? EntityUid.Invalid;
_entManager.TryGetComponent(gridUid, out MapGridComponent? grid);
_entManager.TryGetComponent(gridUid, out BroadphaseComponent? broadphase);
var invMatrix = args.Viewport.GetWorldToLocalMatrix();
_accumulator -= (float) _timing.FrameTime.TotalSeconds;
if (grid != null && broadphase != null)
{
var lookups = _entManager.System<EntityLookupSystem>();
var xforms = _entManager.System<SharedTransformSystem>();
if (_accumulator <= 0f)
{
_accumulator = MathF.Max(0f, _accumulator + _updateRate);
_visibleTiles.Clear();
_entManager.System<StationAiVisionSystem>().GetView((gridUid, broadphase, grid), worldBounds, _visibleTiles);
}
var gridMatrix = xforms.GetWorldMatrix(gridUid);
var matty = Matrix3x2.Multiply(gridMatrix, invMatrix);
// Draw visible tiles to stencil
worldHandle.RenderInRenderTarget(_stencilTexture!, () =>
{
worldHandle.SetTransform(matty);
foreach (var tile in _visibleTiles)
{
var aabb = lookups.GetLocalBounds(tile, grid.TileSize);
worldHandle.DrawRect(aabb, Color.White);
}
},
Color.Transparent);
// Once this is gucci optimise rendering.
worldHandle.RenderInRenderTarget(_staticTexture!,
() =>
{
worldHandle.SetTransform(invMatrix);
var shader = _proto.Index<ShaderPrototype>("CameraStatic").Instance();
worldHandle.UseShader(shader);
worldHandle.DrawRect(worldBounds, Color.White);
},
Color.Black);
}
// Not on a grid
else
{
worldHandle.RenderInRenderTarget(_stencilTexture!, () =>
{
},
Color.Transparent);
worldHandle.RenderInRenderTarget(_staticTexture!,
() =>
{
worldHandle.SetTransform(Matrix3x2.Identity);
worldHandle.DrawRect(worldBounds, Color.Black);
}, Color.Black);
}
// Use the lighting as a mask
worldHandle.UseShader(_proto.Index<ShaderPrototype>("StencilMask").Instance());
worldHandle.DrawTextureRect(_stencilTexture!.Texture, worldBounds);
// Draw the static
worldHandle.UseShader(_proto.Index<ShaderPrototype>("StencilDraw").Instance());
worldHandle.DrawTextureRect(_staticTexture!.Texture, worldBounds);
worldHandle.SetTransform(Matrix3x2.Identity);
worldHandle.UseShader(null);
}
}