-
Notifications
You must be signed in to change notification settings - Fork 32
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge remote-tracking branch 'origin/master'
- Loading branch information
Showing
33 changed files
with
2,222 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,127 @@ | ||
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 = pos.Position;//Vector2.Transform(pos.Position, invMatrix); | ||
// 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)); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
using Content.Shared._Backmen.StationAI; | ||
using Content.Shared._Backmen.StationAI.Components; | ||
using Content.Shared._Backmen.StationAI.Systems; | ||
using Content.Shared.Ghost; | ||
using Content.Shared.Silicons.Borgs.Components; | ||
using Content.Shared.StatusIcon; | ||
using Content.Shared.StatusIcon.Components; | ||
using Robust.Client.Player; | ||
using Robust.Shared.Prototypes; | ||
|
||
namespace Content.Client._Backmen.StationAI; | ||
|
||
public sealed class AiEnemySystem : SharedAiEnemySystem | ||
{ | ||
[Dependency] private readonly IPlayerManager _player = default!; | ||
[Dependency] private readonly IPrototypeManager _prototype = default!; | ||
|
||
public override void Initialize() | ||
{ | ||
base.Initialize(); | ||
|
||
SubscribeLocalEvent<AIEnemyNTComponent, GetStatusIconsEvent>(GetIcon); | ||
} | ||
|
||
protected override void ToggleEnemy(EntityUid u, EntityUid target) | ||
{ | ||
//noop | ||
} | ||
|
||
[ValidatePrototypeId<StatusIconPrototype>] | ||
private const string AiEnemyStatus = "AiIconEnemyTarget"; | ||
private void GetIcon(Entity<AIEnemyNTComponent> target, ref GetStatusIconsEvent args) | ||
{ | ||
var ent = _player.LocalSession?.AttachedEntity ?? EntityUid.Invalid; | ||
|
||
if (!EntityQuery.HasComponent(ent)) | ||
{ | ||
return; | ||
} | ||
args.StatusIcons.Add(_prototype.Index<StatusIconPrototype>(AiEnemyStatus)); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,99 @@ | ||
using System.Linq; | ||
using Content.Client.Power; | ||
using Content.Shared._Backmen.StationAI; | ||
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!; | ||
private EntityQuery<AIEyeComponent> _aiEye; | ||
|
||
public override void Initialize() | ||
{ | ||
base.Initialize(); | ||
|
||
SubscribeLocalEvent<StationAIComponent, AfterAutoHandleStateEvent>(OnUpdate); | ||
|
||
_aiEye = GetEntityQuery<AIEyeComponent>(); | ||
} | ||
|
||
protected override void OnAppearanceChange(EntityUid uid, StationAIComponent component, ref AppearanceChangeEvent args) | ||
{ | ||
if (_aiEye.HasComp(uid)) | ||
{ | ||
base.OnAppearanceChange(uid, component, ref args); | ||
return; | ||
} | ||
|
||
UpdateAppearance(uid, component, args.Component, args.Sprite); | ||
} | ||
|
||
private void OnUpdate(Entity<StationAIComponent> ent, ref AfterAutoHandleStateEvent args) | ||
{ | ||
if (_aiEye.HasComp(ent)) | ||
{ | ||
return; | ||
} | ||
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; | ||
} | ||
|
||
var spriteComponent = (SpriteComponent) _serialization.CreateCopy(spriteProtoComponent, notNullableOverride: true); | ||
|
||
var layers = ent.Comp.Layers[ent.Comp.SelectedLayer]; | ||
|
||
foreach (var layer in layers) | ||
{ | ||
spriteComponent.AddLayer(layer); | ||
} | ||
|
||
AddComp(ent, spriteComponent, true); | ||
|
||
UpdateAppearance(ent, ent, sprite: spriteComponent); | ||
} | ||
|
||
private void UpdateAppearance(EntityUid id, StationAIComponent sign, AppearanceComponent? appearance = null, | ||
SpriteComponent? sprite = null) | ||
{ | ||
if (!Resolve(id, ref appearance, ref sprite)) | ||
return; | ||
|
||
if (_aiEye.HasComp(id)) | ||
{ | ||
return; | ||
} | ||
|
||
AppearanceSystem.TryGetData<bool>(id, PowerDeviceVisuals.Powered, out var powered, appearance); | ||
AppearanceSystem.TryGetData<bool>(id, AiVisuals.Dead, out var dead, appearance); | ||
AppearanceSystem.TryGetData<bool>(id, AiVisuals.InEye, out var inEye, appearance); | ||
|
||
if (sprite.LayerMapTryGet(AiVisualLayers.NotInEye, out var eyeLayer)) | ||
{ | ||
sprite.LayerSetVisible(eyeLayer, powered && !inEye && !dead); | ||
} | ||
|
||
if (sprite.LayerMapTryGet(AiVisualLayers.Dead, out var deadLayer)) | ||
{ | ||
sprite.LayerSetVisible(deadLayer, powered && dead); | ||
} | ||
|
||
if (sprite.LayerMapTryGet(PowerDeviceVisualLayers.Powered, out var poweredLayer)) | ||
{ | ||
sprite.LayerSetVisible(poweredLayer, powered && !dead); | ||
} | ||
} | ||
} |
Oops, something went wrong.