From f7e08ec343a6bdc5a4ca727db71cb3c0e4840b37 Mon Sep 17 00:00:00 2001 From: metalgearsloth <31366439+metalgearsloth@users.noreply.github.com> Date: Fri, 23 Aug 2024 15:13:47 +1000 Subject: [PATCH] Station AI overlay (#31335) Split --- .../Silicons/StationAi/StationAiOverlay.cs | 119 ++++ .../Silicons/StationAi/StationAiSystem.cs | 80 +++ .../Systems/Sandbox/SandboxUIController.cs | 20 + .../Sandbox/Windows/SandboxWindow.xaml | 1 + .../StationAi/StationAiOverlayComponent.cs | 9 + .../StationAi/StationAiVisionComponent.cs | 19 + .../StationAi/StationAiVisionSystem.cs | 518 ++++++++++++++++++ .../Locale/en-US/sandbox/sandbox-manager.ftl | 1 + .../Wallmounts/surveillance_camera.yml | 1 + 9 files changed, 768 insertions(+) create mode 100644 Content.Client/Silicons/StationAi/StationAiOverlay.cs create mode 100644 Content.Client/Silicons/StationAi/StationAiSystem.cs create mode 100644 Content.Shared/Silicons/StationAi/StationAiOverlayComponent.cs create mode 100644 Content.Shared/Silicons/StationAi/StationAiVisionComponent.cs create mode 100644 Content.Shared/Silicons/StationAi/StationAiVisionSystem.cs diff --git a/Content.Client/Silicons/StationAi/StationAiOverlay.cs b/Content.Client/Silicons/StationAi/StationAiOverlay.cs new file mode 100644 index 0000000000..efa1b8dbef --- /dev/null +++ b/Content.Client/Silicons/StationAi/StationAiOverlay.cs @@ -0,0 +1,119 @@ +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.Prototypes; + +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 IPlayerManager _player = default!; + [Dependency] private readonly IPrototypeManager _proto = default!; + + public override OverlaySpace Space => OverlaySpace.WorldSpace; + + private readonly HashSet _visibleTiles = new(); + + private IRenderTexture? _staticTexture; + private IRenderTexture? _stencilTexture; + + 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); + + var invMatrix = args.Viewport.GetWorldToLocalMatrix(); + + if (grid != null) + { + // TODO: Pass in attached entity's grid. + // TODO: Credit OD on the moved to code + // TODO: Call the moved-to code here. + + _visibleTiles.Clear(); + var lookups = _entManager.System(); + var xforms = _entManager.System(); + _entManager.System().GetView((gridUid, 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("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("StencilMask").Instance()); + worldHandle.DrawTextureRect(_stencilTexture!.Texture, worldBounds); + + // Draw the static + worldHandle.UseShader(_proto.Index("StencilDraw").Instance()); + worldHandle.DrawTextureRect(_staticTexture!.Texture, worldBounds); + + worldHandle.SetTransform(Matrix3x2.Identity); + worldHandle.UseShader(null); + + } +} diff --git a/Content.Client/Silicons/StationAi/StationAiSystem.cs b/Content.Client/Silicons/StationAi/StationAiSystem.cs new file mode 100644 index 0000000000..2ed0617525 --- /dev/null +++ b/Content.Client/Silicons/StationAi/StationAiSystem.cs @@ -0,0 +1,80 @@ +using Content.Shared.Silicons.StationAi; +using Robust.Client.Graphics; +using Robust.Client.Player; +using Robust.Shared.Player; + +namespace Content.Client.Silicons.StationAi; + +public sealed partial class StationAiSystem : EntitySystem +{ + [Dependency] private readonly IOverlayManager _overlayMgr = default!; + [Dependency] private readonly IPlayerManager _player = default!; + + private StationAiOverlay? _overlay; + + public override void Initialize() + { + base.Initialize(); + // InitializeAirlock(); + // InitializePowerToggle(); + + SubscribeLocalEvent(OnAiAttached); + SubscribeLocalEvent(OnAiDetached); + SubscribeLocalEvent(OnAiOverlayInit); + SubscribeLocalEvent(OnAiOverlayRemove); + } + + private void OnAiOverlayInit(Entity ent, ref ComponentInit args) + { + var attachedEnt = _player.LocalEntity; + + if (attachedEnt != ent.Owner) + return; + + AddOverlay(); + } + + private void OnAiOverlayRemove(Entity ent, ref ComponentRemove args) + { + var attachedEnt = _player.LocalEntity; + + if (attachedEnt != ent.Owner) + return; + + RemoveOverlay(); + } + + private void AddOverlay() + { + if (_overlay != null) + return; + + _overlay = new StationAiOverlay(); + _overlayMgr.AddOverlay(_overlay); + } + + private void RemoveOverlay() + { + if (_overlay == null) + return; + + _overlayMgr.RemoveOverlay(_overlay); + _overlay = null; + } + + private void OnAiAttached(Entity ent, ref LocalPlayerAttachedEvent args) + { + AddOverlay(); + } + + private void OnAiDetached(Entity ent, ref LocalPlayerDetachedEvent args) + { + RemoveOverlay(); + } + + public override void Shutdown() + { + base.Shutdown(); + _overlayMgr.RemoveOverlay(); + } +} diff --git a/Content.Client/UserInterface/Systems/Sandbox/SandboxUIController.cs b/Content.Client/UserInterface/Systems/Sandbox/SandboxUIController.cs index 752c89ca97..58c8a1451b 100644 --- a/Content.Client/UserInterface/Systems/Sandbox/SandboxUIController.cs +++ b/Content.Client/UserInterface/Systems/Sandbox/SandboxUIController.cs @@ -7,14 +7,17 @@ using Content.Client.UserInterface.Controls; using Content.Client.UserInterface.Systems.DecalPlacer; using Content.Client.UserInterface.Systems.Sandbox.Windows; using Content.Shared.Input; +using Content.Shared.Silicons.StationAi; using JetBrains.Annotations; using Robust.Client.Console; using Robust.Client.Debugging; using Robust.Client.Graphics; using Robust.Client.Input; +using Robust.Client.Player; using Robust.Client.UserInterface; using Robust.Client.UserInterface.Controllers; using Robust.Client.UserInterface.Controllers.Implementations; +using Robust.Shared.Console; using Robust.Shared.Input.Binding; using Robust.Shared.Map; using Robust.Shared.Player; @@ -27,10 +30,12 @@ namespace Content.Client.UserInterface.Systems.Sandbox; [UsedImplicitly] public sealed class SandboxUIController : UIController, IOnStateChanged, IOnSystemChanged { + [Dependency] private readonly IConsoleHost _console = default!; [Dependency] private readonly IEyeManager _eye = default!; [Dependency] private readonly IInputManager _input = default!; [Dependency] private readonly ILightManager _light = default!; [Dependency] private readonly IClientAdminManager _admin = default!; + [Dependency] private readonly IPlayerManager _player = default!; [UISystemDependency] private readonly DebugPhysicsSystem _debugPhysics = default!; [UISystemDependency] private readonly MarkerSystem _marker = default!; @@ -116,6 +121,21 @@ public sealed class SandboxUIController : UIController, IOnStateChanged + { + var player = _player.LocalEntity; + + if (player == null) + return; + + var pnent = EntityManager.GetNetEntity(player.Value); + + // Need NetworkedAddComponent but engine PR. + if (args.Button.Pressed) + _console.ExecuteCommand($"addcomp {pnent.Id} StationAiOverlay"); + else + _console.ExecuteCommand($"rmcomp {pnent.Id} StationAiOverlay"); + }; _window.RespawnButton.OnPressed += _ => _sandbox.Respawn(); _window.SpawnTilesButton.OnPressed += _ => TileSpawningController.ToggleWindow(); _window.SpawnEntitiesButton.OnPressed += _ => EntitySpawningController.ToggleWindow(); diff --git a/Content.Client/UserInterface/Systems/Sandbox/Windows/SandboxWindow.xaml b/Content.Client/UserInterface/Systems/Sandbox/Windows/SandboxWindow.xaml index 64367ea27a..05e65cf29c 100644 --- a/Content.Client/UserInterface/Systems/Sandbox/Windows/SandboxWindow.xaml +++ b/Content.Client/UserInterface/Systems/Sandbox/Windows/SandboxWindow.xaml @@ -4,6 +4,7 @@ Title="{Loc sandbox-window-title}" Resizable="False"> +