Skip to content

Commit

Permalink
SAIv3-1 (#481)
Browse files Browse the repository at this point in the history
* SAIv3-1

* fix (SAIv3-1)
  • Loading branch information
Rxup authored Feb 21, 2024
1 parent 03e23f1 commit a4346ea
Show file tree
Hide file tree
Showing 8 changed files with 349 additions and 26 deletions.
125 changes: 125 additions & 0 deletions Content.Client/Backmen/StationAI/AiCamOverlay.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
using System.Numerics;
using Content.Client.Parallax;
using Content.Client.Weather;
using Content.Shared.Backmen.StationAI;
using Robust.Client.GameObjects;
using Robust.Client.Graphics;
using Robust.Client.Player;
using Robust.Shared.Enums;
using Robust.Shared.Map;
using Robust.Shared.Prototypes;
using Robust.Shared.Timing;
using Robust.Shared.Utility;

namespace Content.Client.Backmen.StationAI;

public sealed class AiCamOverlay : Overlay
{
[Dependency] private readonly IClyde _clyde = default!;
[Dependency] private readonly IEntityManager _entManager = default!;
[Dependency] private readonly IGameTiming _timing = default!;
[Dependency] private readonly IMapManager _mapManager = default!;
[Dependency] private readonly IPrototypeManager _protoManager = default!;
[Dependency] private readonly IPlayerManager _player = default!;

private readonly ParallaxSystem _parallax;
private readonly SharedTransformSystem _transform;
private readonly SpriteSystem _sprite;
private readonly StationAiSystem _aiSystem;


public override OverlaySpace Space => OverlaySpace.WorldSpace;

private IRenderTexture? _blep;

private readonly ShaderInstance _shader;

public AiCamOverlay(ParallaxSystem parallax, SharedTransformSystem transform, SpriteSystem sprite, StationAiSystem aiSystem)
{
ZIndex = ParallaxSystem.ParallaxZIndex + 1;
_parallax = parallax;
_transform = transform;
_sprite = sprite;
_aiSystem = aiSystem;
IoCManager.InjectDependencies(this);
_shader = _protoManager.Index<ShaderPrototype>("WorldGradientCircle").InstanceUnique();
}

protected override void Draw(in OverlayDrawArgs args)
{
var playerUid = _player.LocalSession?.AttachedEntity;
if (playerUid is not { Valid: true })
return;

if (!_entManager.TryGetComponent<AIEyeComponent>(playerUid, out var eyeComponent))
{
return;
}

var invMatrix = args.Viewport.GetWorldToLocalMatrix();

if (_blep?.Texture.Size != args.Viewport.Size)
{
_blep?.Dispose();
_blep = _clyde.CreateRenderTarget(args.Viewport.Size, new RenderTargetFormatParameters(RenderTargetColorFormat.Rgba8Srgb), name: "aicam-stencil");
}

if (eyeComponent.Camera != null)
{
DrawRestrictedRange(args, eyeComponent, invMatrix);
}

args.WorldHandle.UseShader(null);
args.WorldHandle.SetTransform(Matrix3.Identity);
}

private void DrawRestrictedRange(in OverlayDrawArgs args, AIEyeComponent eyeComponent, Matrix3 invMatrix)
{
var pos = _transform.GetMapCoordinates(eyeComponent.Camera!.Value);

var worldHandle = args.WorldHandle;
var renderScale = args.Viewport.RenderScale.X;
// TODO: This won't handle non-standard zooms so uhh yeah, not sure how to structure it on the shader side.
var zoom = args.Viewport.Eye?.Zoom ?? Vector2.One;
var length = zoom.X;
var bufferRange = MathF.Min(10f, SharedStationAISystem.CameraEyeRange);

var pixelCenter = invMatrix.Transform(pos.Position);
// Something something offset?
var vertical = args.Viewport.Size.Y;

var pixelMaxRange = SharedStationAISystem.CameraEyeRange * renderScale / length * EyeManager.PixelsPerMeter;
var pixelBufferRange = bufferRange * renderScale / length * EyeManager.PixelsPerMeter;
var pixelMinRange = pixelMaxRange - pixelBufferRange;

_shader.SetParameter("position", new Vector2(pixelCenter.X, vertical - pixelCenter.Y));
_shader.SetParameter("maxRange", pixelMaxRange);
_shader.SetParameter("minRange", pixelMinRange);
_shader.SetParameter("bufferRange", pixelBufferRange);
_shader.SetParameter("gradient", 0.80f);

var worldAABB = args.WorldAABB;
var worldBounds = args.WorldBounds;
var position = args.Viewport.Eye?.Position.Position ?? Vector2.Zero;
var localAABB = invMatrix.TransformBox(worldAABB);

// Cut out the irrelevant bits via stencil
// This is why we don't just use parallax; we might want specific tiles to get drawn over
// particularly for planet maps or stations.
worldHandle.RenderInRenderTarget(_blep!, () =>
{
worldHandle.UseShader(_shader);
worldHandle.DrawRect(localAABB, Color.White);
}, Color.Transparent);

worldHandle.SetTransform(Matrix3.Identity);
worldHandle.UseShader(_protoManager.Index<ShaderPrototype>("StencilMask").Instance());
worldHandle.DrawTextureRect(_blep!.Texture, worldBounds);
var curTime = _timing.RealTime;
var sprite = _sprite.GetFrame(new SpriteSpecifier.Texture(new ResPath("/Textures/Parallaxes/aicam.png")), curTime);

// Draw the fog
worldHandle.UseShader(_protoManager.Index<ShaderPrototype>("StencilDraw").Instance());
_parallax.DrawParallax(worldHandle, worldAABB, sprite, curTime, position, new Vector2(0.5f, 0f));
}
}
23 changes: 15 additions & 8 deletions Content.Client/Backmen/StationAI/AiVisualizerSystem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,16 @@
using Content.Shared.Backmen.StationAI.UI;
using Content.Shared.Power;
using Robust.Client.GameObjects;
using Robust.Shared.Prototypes;
using Robust.Shared.Serialization.Manager;

namespace Content.Client.Backmen.StationAI;

public sealed class AiVisualizerSystem : VisualizerSystem<StationAIComponent>
{
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
[Dependency] private readonly ISerializationManager _serialization = default!;

public override void Initialize()
{
base.Initialize();
Expand All @@ -33,26 +38,28 @@ private void OnUpdate(Entity<StationAIComponent> ent, ref AfterAutoHandleStateEv
{
return;
}
if (!TryComp<SpriteComponent>(ent, out var spriteComponent))
if (
!ent.Comp.Layers.ContainsKey(ent.Comp.SelectedLayer) ||
!TryComp<MetaDataComponent>(ent, out var metaDataComponent) ||
metaDataComponent.EntityPrototype == null ||
!_prototypeManager.TryIndex<EntityPrototype>(metaDataComponent.EntityPrototype.ID, out var proto) ||
!proto.TryGetComponent<SpriteComponent>(out var spriteProtoComponent)
)
{
return;
}

if (!ent.Comp.Layers.ContainsKey(ent.Comp.SelectedLayer))
return;
var spriteComponent = (SpriteComponent) _serialization.CreateCopy(spriteProtoComponent, notNullableOverride: true);

var layers = ent.Comp.Layers[ent.Comp.SelectedLayer];

var countLayers = spriteComponent.AllLayers.Count();

if (countLayers > 1)
return; // невкурсе как обновить слоя

foreach (var layer in layers)
{
spriteComponent.AddLayer(layer);
}

EntityManager.AddComponent(ent, spriteComponent, true);

UpdateAppearance(ent, ent, sprite: spriteComponent);
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,23 +1,62 @@
using System.Linq;
using Content.Client.Backmen.CartridgeLoader.Cartridges;
using Content.Client.Backmen.StationAI.UI;
using Content.Client.Parallax;
using Content.Client.Storage.Components;
using Content.Client.UserInterface.Fragments;
using Content.Shared.Backmen.StationAI;
using Content.Shared.Backmen.StationAI.UI;
using Content.Shared.Interaction.Events;
using Content.Shared.Item;
using Robust.Client.GameObjects;
using Robust.Client.Graphics;
using Robust.Client.Player;
using Robust.Client.UserInterface;

namespace Content.Client.Backmen.StationAI;

public sealed class StationAISystem : EntitySystem
public sealed class StationAiSystem : SharedStationAISystem
{
[Dependency] private readonly IPlayerManager _player = default!;
[Dependency] private readonly IOverlayManager _overlay = default!;
private AiCamOverlay _aiCamOverlay = default!;

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

_aiCamOverlay = new(
EntityManager.System<ParallaxSystem>(),
EntityManager.System<TransformSystem>(),
EntityManager.System<SpriteSystem>(),
this);

SubscribeLocalEvent<StationAIComponent, InteractionAttemptEvent>(CanInteraction);
SubscribeLocalEvent<AIEyeComponent, AfterAutoHandleStateEvent>(OnCamUpdate);

_player.LocalPlayerAttached += PlayerOnLocalPlayerAttached;
_player.LocalPlayerDetached += PlayerOnLocalPlayerDetached;
}

private void PlayerOnLocalPlayerDetached(EntityUid obj)
{
if (_overlay.HasOverlay<AiCamOverlay>())
_overlay.RemoveOverlay<AiCamOverlay>();
}

private void PlayerOnLocalPlayerAttached(EntityUid obj)
{
if (!HasComp<AIEyeComponent>(obj))
return;
_overlay.AddOverlay(_aiCamOverlay);
}

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

_player.LocalPlayerAttached -= PlayerOnLocalPlayerAttached;
_player.LocalPlayerDetached -= PlayerOnLocalPlayerDetached;
}

private void OnCamUpdate(Entity<AIEyeComponent> ent, ref AfterAutoHandleStateEvent args)
Expand Down
30 changes: 19 additions & 11 deletions Content.Server/Backmen/StationAI/AiEyeMover.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,11 @@
using Content.Server.Backmen.StationAI.Systems;
using Content.Server.SurveillanceCamera;
using Content.Shared.Backmen.StationAI;
using Content.Shared.Tag;
using Robust.Server.GameObjects;
using Robust.Shared.CPUJob.JobQueues;
using Robust.Shared.Map;
using Robust.Shared.Map.Components;
using Robust.Shared.Timing;

namespace Content.Server.Backmen.StationAI;
Expand All @@ -15,21 +18,17 @@ public sealed class AiEyeMover : Job<object>
private readonly EntityLookupSystem _lookup;
private readonly SharedTransformSystem _transform;
private readonly EntityManager _entityManager;
private readonly MapSystem _map;
private readonly TagSystem _tag;

public AiEyeMover(EntityManager entityManager, AICameraSystem cameraSystem, EntityLookupSystem lookup, SharedTransformSystem transform, double maxTime, CancellationToken cancellation = default) : base(maxTime, cancellation)
{
_cameraSystem = cameraSystem;
_lookup = lookup;
_transform = transform;
_entityManager = entityManager;
}

public AiEyeMover(EntityManager entityManager, AICameraSystem cameraSystem, EntityLookupSystem lookup, SharedTransformSystem transform, double maxTime, IStopwatch stopwatch, CancellationToken cancellation = default) : base(maxTime, stopwatch, cancellation)
public AiEyeMover(EntityManager entityManager, AICameraSystem cameraSystem, EntityLookupSystem lookup, SharedTransformSystem transform, MapSystem map, TagSystem tag, double maxTime, CancellationToken cancellation = default) : base(maxTime, cancellation)
{
_cameraSystem = cameraSystem;
_lookup = lookup;
_transform = transform;
_entityManager = entityManager;
_map = map;
_tag = tag;
}

public Entity<AIEyeComponent> Eye { get; set; }
Expand All @@ -52,7 +51,10 @@ public AiEyeMover(EntityManager entityManager, AICameraSystem cameraSystem, Enti

var gridUid = NewPosition.GetGridUid(_entityManager);

if (gridUid == null || _transform.GetMoverCoordinates(core).GetGridUid(_entityManager) != gridUid)
if (
gridUid == null ||
_transform.GetMoverCoordinates(core).GetGridUid(_entityManager) != gridUid ||
!_entityManager.TryGetComponent<MapGridComponent>(gridUid, out var grid))
{
_entityManager.QueueDeleteEntity(Eye);
return null;
Expand All @@ -64,8 +66,14 @@ public AiEyeMover(EntityManager entityManager, AICameraSystem cameraSystem, Enti

var mapPos = NewPosition.ToMap(_entityManager, _transform);

foreach (var uid in _map.GetAnchoredEntities(gridUid.Value, grid, NewPosition))
{
if (_tag.HasAnyTag(uid, "Wall","Window"))
return null;
}

await WaitAsyncTask(Task.Run(() =>
_lookup.GetEntitiesInRange(mapPos, AICameraSystem.CameraEyeRange, _cameraComponents, LookupFlags.Sensors)));
_lookup.GetEntitiesInRange(mapPos, SharedStationAISystem.CameraEyeRange, _cameraComponents, LookupFlags.Sensors)));

_cameraSystem.HandleMove(Eye, _cameraComponents);
}
Expand Down
11 changes: 7 additions & 4 deletions Content.Server/Backmen/StationAI/Systems/AICameraSystem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
using Content.Shared.Backmen.StationAI;
using Content.Shared.Eye.Blinding.Components;
using Content.Shared.Popups;
using Content.Shared.Tag;
using Content.Shared.Traits.Assorted;
using Content.Shared.Weapons.Ranged;
using Content.Shared.Weapons.Ranged.Components;
Expand All @@ -26,9 +27,11 @@ public sealed class AICameraSystem : EntitySystem
[Dependency] private readonly PopupSystem _popup = default!;
[Dependency] private readonly GunSystem _gun = default!;
[Dependency] private readonly SharedAudioSystem _audio = default!;
[Dependency] private readonly MapSystem _map = default!;
[Dependency] private readonly TagSystem _tag = default!;



public const float CameraEyeRange = 10f;
private const double MoverJobTime = 0.005;
private readonly JobQueue _moveJobQueue = new(MoverJobTime);

Expand Down Expand Up @@ -127,7 +130,7 @@ private void OnEyeMove(Entity<AIEyeComponent> ent, ref MoveEvent args)

ent.Comp.IsProcessingMoveEvent = true;

var job = new AiEyeMover(EntityManager, this, _lookup, _transform, MoverJobTime)
var job = new AiEyeMover(EntityManager, this, _lookup, _transform, _map, _tag, MoverJobTime)
{
Eye = ent,
//OldPosition = args.OldPosition,
Expand All @@ -142,7 +145,7 @@ public bool IsCameraActive(Entity<AIEyeComponent> eye)
if (!eye.Comp.Camera.HasValue)
return false;

return _interaction.InRangeUnobstructed(eye.Comp.Camera.Value, eye, CameraEyeRange);
return _interaction.InRangeUnobstructed(eye.Comp.Camera.Value, eye, SharedStationAISystem.CameraEyeRange);
}

public void RemoveActiveCamera(Entity<AIEyeComponent> eye)
Expand Down Expand Up @@ -197,7 +200,7 @@ public void HandleMove(Entity<AIEyeComponent> eye, HashSet<Entity<SurveillanceCa
if(!cameraComponent.Comp.Active)
continue;

if(!_interaction.InRangeUnobstructed(cameraComponent, eye, CameraEyeRange))
if(!_interaction.InRangeUnobstructed(cameraComponent, eye, SharedStationAISystem.CameraEyeRange))
continue;

RemCompDeferred<TemporaryBlindnessComponent>(eye);
Expand Down
Loading

0 comments on commit a4346ea

Please sign in to comment.