Get rid of the OverlayEffectsComponent stuff (#3010)

* Get rid of the OverlayEffectsComponent stuff because it just ended up creating workarounds for it's bugs, without removing any functionality

* Flashes and Flashbangs use the same code now (the Flashable path because it's better)
This commit is contained in:
20kdc
2021-01-24 08:17:45 +00:00
committed by GitHub
parent 329d599107
commit e53ae365a3
21 changed files with 65 additions and 659 deletions

View File

@@ -13,6 +13,7 @@ using Content.Client.StationEvents;
using Content.Client.UserInterface;
using Content.Client.UserInterface.AdminMenu;
using Content.Client.UserInterface.Stylesheets;
using Content.Client.Graphics.Overlays;
using Content.Shared.Actions;
using Content.Shared.GameObjects.Components;
using Content.Shared.GameObjects.Components.Cargo;
@@ -149,7 +150,12 @@ namespace Content.Client
IoCManager.Resolve<IGameHud>().Initialize();
IoCManager.Resolve<IClientNotifyManager>().Initialize();
IoCManager.Resolve<IClientGameTicker>().Initialize();
IoCManager.Resolve<IOverlayManager>().AddOverlay(new ParallaxOverlay());
var overlayMgr = IoCManager.Resolve<IOverlayManager>();
overlayMgr.AddOverlay(new ParallaxOverlay());
overlayMgr.AddOverlay(new GradientCircleMaskOverlay());
overlayMgr.AddOverlay(new CircleMaskOverlay());
overlayMgr.AddOverlay(new FlashOverlay());
overlayMgr.AddOverlay(new RadiationPulseOverlay());
IoCManager.Resolve<IChatManager>().Initialize();
IoCManager.Resolve<ISandboxManager>().Initialize();
IoCManager.Resolve<IClientPreferencesManager>().Initialize();

View File

@@ -1,169 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Content.Shared.GameObjects.Components.Mobs;
using Content.Shared.Interfaces;
using Robust.Client.GameObjects;
using Robust.Client.Graphics.Overlays;
using Robust.Client.Interfaces.Graphics.Overlays;
using Robust.Shared.GameObjects;
using Robust.Shared.Interfaces.GameObjects;
using Robust.Shared.Interfaces.Network;
using Robust.Shared.Interfaces.Reflection;
using Robust.Shared.IoC;
using Robust.Shared.Log;
using Robust.Shared.Players;
using Robust.Shared.ViewVariables;
namespace Content.Client.GameObjects.Components.Mobs
{
/// <summary>
/// A character UI component which shows the current damage state of the mob (living/dead)
/// </summary>
[RegisterComponent]
[ComponentReference(typeof(SharedOverlayEffectsComponent))]
public sealed class ClientOverlayEffectsComponent : SharedOverlayEffectsComponent//, ICharacterUI
{
[Dependency] private readonly IOverlayManager _overlayManager = default!;
[Dependency] private readonly IReflectionManager _reflectionManager = default!;
[Dependency] private readonly IClientNetManager _netManager = default!;
/// <summary>
/// A list of overlay containers representing the current overlays applied
/// </summary>
private List<OverlayContainer> _currentEffects = new();
[ViewVariables(VVAccess.ReadOnly)]
public List<OverlayContainer> ActiveOverlays
{
get => _currentEffects;
set => SetEffects(value);
}
public override void Initialize()
{
base.Initialize();
UpdateOverlays();
}
public override void HandleMessage(ComponentMessage message, IComponent component)
{
switch (message)
{
case PlayerAttachedMsg _:
UpdateOverlays();
break;
case PlayerDetachedMsg _:
ActiveOverlays.ForEach(o => _overlayManager.RemoveOverlay(o.ID));
break;
}
}
public override void HandleNetworkMessage(ComponentMessage message, INetChannel netChannel, ICommonSession session = null)
{
base.HandleNetworkMessage(message, netChannel, session);
if (message is OverlayEffectComponentMessage overlayMessage)
{
SetEffects(overlayMessage.Overlays);
}
}
private void UpdateOverlays()
{
_currentEffects = _overlayManager.AllOverlays
.Where(overlay => Enum.IsDefined(typeof(SharedOverlayID), overlay.ID))
.Select(overlay => new OverlayContainer(overlay.ID))
.ToList();
foreach (var overlayContainer in ActiveOverlays)
{
if (!_overlayManager.HasOverlay(overlayContainer.ID))
{
if (TryCreateOverlay(overlayContainer, out var overlay))
{
_overlayManager.AddOverlay(overlay);
}
}
}
SendNetworkMessage(new ResendOverlaysMessage(), _netManager.ServerChannel);
}
private void SetEffects(List<OverlayContainer> newOverlays)
{
foreach (var container in ActiveOverlays.ToArray())
{
if (!newOverlays.Contains(container))
{
RemoveOverlay(container);
}
}
foreach (var container in newOverlays)
{
if (!ActiveOverlays.Contains(container))
{
AddOverlay(container);
}
else
{
UpdateOverlayConfiguration(container, _overlayManager.GetOverlay(container.ID));
}
}
_currentEffects = newOverlays;
}
private void RemoveOverlay(OverlayContainer container)
{
ActiveOverlays.Remove(container);
_overlayManager.RemoveOverlay(container.ID);
}
private void AddOverlay(OverlayContainer container)
{
if (_overlayManager.HasOverlay(container.ID))
{
return;
}
ActiveOverlays.Add(container);
if (TryCreateOverlay(container, out var overlay))
{
_overlayManager.AddOverlay(overlay);
}
else
{
Logger.ErrorS("overlay", $"Could not add overlay {container.ID}");
}
}
private void UpdateOverlayConfiguration(OverlayContainer container, Overlay overlay)
{
if (overlay is IConfigurableOverlay configurable)
{
foreach (var param in container.Parameters)
{
configurable.Configure(param);
}
}
}
private bool TryCreateOverlay(OverlayContainer container, out Overlay overlay)
{
var overlayTypes = _reflectionManager.GetAllChildren<Overlay>();
var overlayType = overlayTypes.FirstOrDefault(t => t.Name == container.ID);
if (overlayType != null)
{
overlay = IoCManager.Resolve<IDynamicTypeFactory>().CreateInstance<Overlay>(overlayType);
UpdateOverlayConfiguration(container, overlay);
return true;
}
overlay = default;
return false;
}
}
}

View File

@@ -1,5 +1,6 @@
using System;
using System.Threading;
using Content.Client.Graphics.Overlays;
using Content.Shared.GameObjects.Components.Weapons;
using Robust.Client.Graphics.Drawing;
using Robust.Client.Graphics.Overlays;
@@ -19,10 +20,8 @@ namespace Content.Client.GameObjects.Components.Weapons
[RegisterComponent]
public sealed class FlashableComponent : SharedFlashableComponent
{
private CancellationTokenSource _cancelToken;
private TimeSpan _startTime;
private double _duration;
private FlashOverlay _overlay;
public override void HandleComponentState(ComponentState curState, ComponentState nextState)
{
@@ -57,94 +56,15 @@ namespace Content.Client.GameObjects.Components.Weapons
if (currentTime > newEndTime)
{
DisableOverlay();
return;
}
_startTime = newState.Time;
_duration = newState.Duration;
EnableOverlay(newEndTime - currentTime);
}
private void EnableOverlay(double duration)
{
// If the timer gets reset
if (_overlay != null)
{
_overlay.Duration = _duration;
_overlay.StartTime = _startTime;
_cancelToken.Cancel();
}
else
{
var overlayManager = IoCManager.Resolve<IOverlayManager>();
_overlay = new FlashOverlay(_duration);
overlayManager.AddOverlay(_overlay);
}
_cancelToken = new CancellationTokenSource();
Owner.SpawnTimer((int) duration * 1000, DisableOverlay, _cancelToken.Token);
}
private void DisableOverlay()
{
if (_overlay == null)
{
return;
}
var overlayManager = IoCManager.Resolve<IOverlayManager>();
overlayManager.RemoveOverlay(_overlay.ID);
_overlay = null;
_cancelToken.Cancel();
_cancelToken = null;
}
}
public sealed class FlashOverlay : Overlay
{
public override OverlaySpace Space => OverlaySpace.ScreenSpace;
private readonly IGameTiming _timer;
private readonly IClyde _displayManager;
public TimeSpan StartTime { get; set; }
public double Duration { get; set; }
public FlashOverlay(double duration) : base(nameof(FlashOverlay))
{
_timer = IoCManager.Resolve<IGameTiming>();
_displayManager = IoCManager.Resolve<IClyde>();
StartTime = _timer.CurTime;
Duration = duration;
}
protected override void Draw(DrawingHandleBase handle, OverlaySpace currentSpace)
{
var elapsedTime = (_timer.CurTime - StartTime).TotalSeconds;
if (elapsedTime > Duration)
{
return;
}
var screenHandle = (DrawingHandleScreen) handle;
screenHandle.DrawRect(
new UIBox2(0.0f, 0.0f, _displayManager.ScreenSize.X, _displayManager.ScreenSize.Y),
Color.White.WithAlpha(GetAlpha(elapsedTime / Duration))
);
}
private float GetAlpha(double ratio)
{
// Ideally you just want a smooth slope to finish it so it's not jarring at the end
// By all means put in a better curve
const float slope = -9.0f;
const float exponent = 0.1f;
const float yOffset = 9.0f;
const float xOffset = 0.0f;
// Overkill but easy to adjust if you want to mess around with the design
var result = (float) MathHelper.Clamp(slope * (float) Math.Pow(ratio - xOffset, exponent) + yOffset, 0.0, 1.0);
DebugTools.Assert(!float.IsNaN(result));
return result;
var overlay = overlayManager.GetOverlay<FlashOverlay>(nameof(FlashOverlay));
overlay.ReceiveFlash(_duration);
}
}
}

View File

@@ -3,6 +3,7 @@ using Robust.Client.Graphics.Drawing;
using Robust.Client.Graphics.Overlays;
using Robust.Client.Graphics.Shaders;
using Robust.Client.Interfaces.Graphics.ClientEye;
using Robust.Client.Player;
using Robust.Shared.IoC;
using Robust.Shared.Maths;
using Robust.Shared.Prototypes;
@@ -13,11 +14,12 @@ namespace Content.Client.Graphics.Overlays
{
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
[Dependency] private readonly IEyeManager _eyeManager = default!;
[Dependency] private readonly IPlayerManager _playerManager = default!;
public override OverlaySpace Space => OverlaySpace.WorldSpace;
private readonly ShaderInstance _shader;
public CircleMaskOverlay() : base(nameof(SharedOverlayID.CircleMaskOverlay))
public CircleMaskOverlay() : base(nameof(CircleMaskOverlay))
{
IoCManager.InjectDependencies(this);
_shader = _prototypeManager.Index<ShaderPrototype>("CircleMask").Instance();
@@ -25,6 +27,8 @@ namespace Content.Client.Graphics.Overlays
protected override void Draw(DrawingHandleBase handle, OverlaySpace currentSpace)
{
if (!GradientCircleMaskOverlay.LocalPlayerHasState(_playerManager, false, true))
return;
handle.UseShader(_shader);
var worldHandle = (DrawingHandleWorld)handle;
var viewport = _eyeManager.GetWorldViewport();

View File

@@ -1,5 +1,6 @@
using Content.Shared.GameObjects.Components.Mobs;
using Content.Shared.Interfaces;
using Content.Shared.Network.NetMessages;
using Robust.Client.Graphics;
using Robust.Client.Graphics.Drawing;
using Robust.Client.Graphics.Overlays;
@@ -14,7 +15,7 @@ using SixLabors.ImageSharp.PixelFormats;
namespace Content.Client.Graphics.Overlays
{
public class FlashOverlay : Overlay, IConfigurableOverlay
public class FlashOverlay : Overlay
{
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
[Dependency] private readonly IClyde _displayManager = default!;
@@ -22,27 +23,33 @@ namespace Content.Client.Graphics.Overlays
public override OverlaySpace Space => OverlaySpace.ScreenSpace;
private readonly ShaderInstance _shader;
private readonly double _startTime;
private int _lastsFor = 5000;
private double _startTime = -1;
private double _lastsFor = 1;
private Texture _screenshotTexture;
public FlashOverlay() : base(nameof(SharedOverlayID.FlashOverlay))
public FlashOverlay() : base(nameof(FlashOverlay))
{
IoCManager.InjectDependencies(this);
_shader = _prototypeManager.Index<ShaderPrototype>("FlashedEffect").Instance().Duplicate();
}
_startTime = _gameTiming.CurTime.TotalMilliseconds;
public void ReceiveFlash(double duration)
{
_displayManager.Screenshot(ScreenshotType.BeforeUI, image =>
{
var rgba32Image = image.CloneAs<Rgba32>(Configuration.Default);
_screenshotTexture = _displayManager.LoadTextureFromImage(rgba32Image);
});
_startTime = _gameTiming.CurTime.TotalSeconds;
_lastsFor = duration;
}
protected override void Draw(DrawingHandleBase handle, OverlaySpace currentSpace)
{
var percentComplete = (float) ((_gameTiming.CurTime.TotalSeconds - _startTime) / _lastsFor);
if (percentComplete >= 1.0f)
return;
handle.UseShader(_shader);
var percentComplete = (float) ((_gameTiming.CurTime.TotalMilliseconds - _startTime) / _lastsFor);
_shader?.SetParameter("percentComplete", percentComplete);
var screenSpaceHandle = handle as DrawingHandleScreen;
@@ -60,13 +67,5 @@ namespace Content.Client.Graphics.Overlays
_screenshotTexture = null;
}
public void Configure(OverlayParameter parameters)
{
if (parameters is TimedOverlayParameter timedParams)
{
_lastsFor = timedParams.Length;
}
}
}
}

View File

@@ -1,8 +1,10 @@
using Content.Shared.GameObjects.Components.Mobs;
using Content.Shared.GameObjects.Components.Mobs.State;
using Robust.Client.Graphics.Drawing;
using Robust.Client.Graphics.Overlays;
using Robust.Client.Graphics.Shaders;
using Robust.Client.Interfaces.Graphics.ClientEye;
using Robust.Client.Player;
using Robust.Shared.IoC;
using Robust.Shared.Maths;
using Robust.Shared.Prototypes;
@@ -13,18 +15,43 @@ namespace Content.Client.Graphics.Overlays
{
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
[Dependency] private readonly IEyeManager _eyeManager = default!;
[Dependency] private readonly IPlayerManager _playerManager = default!;
public override OverlaySpace Space => OverlaySpace.WorldSpace;
private readonly ShaderInstance _shader;
public GradientCircleMaskOverlay() : base(nameof(SharedOverlayID.GradientCircleMaskOverlay))
public GradientCircleMaskOverlay() : base(nameof(GradientCircleMaskOverlay))
{
IoCManager.InjectDependencies(this);
_shader = _prototypeManager.Index<ShaderPrototype>("GradientCircleMask").Instance();
}
public static bool LocalPlayerHasState(IPlayerManager pm, bool critical, bool dead) {
var playerEntity = pm.LocalPlayer?.ControlledEntity;
if (playerEntity == null)
{
return false;
}
if (playerEntity.TryGetComponent<IMobStateComponent>(out var mobState))
{
if (critical)
if (mobState.IsCritical())
return true;
if (dead)
if (mobState.IsDead())
return true;
}
return false;
}
protected override void Draw(DrawingHandleBase handle, OverlaySpace currentSpace)
{
if (!LocalPlayerHasState(_playerManager, true, false))
return;
handle.UseShader(_shader);
var worldHandle = (DrawingHandleWorld)handle;
var viewport = _eyeManager.GetWorldViewport();

View File

@@ -47,7 +47,7 @@ namespace Content.Client.StationEvents
// TODO: When worldHandle can do DrawCircle change this.
public override OverlaySpace Space => OverlaySpace.ScreenSpace;
public RadiationPulseOverlay() : base(nameof(SharedOverlayID.RadiationPulseOverlay))
public RadiationPulseOverlay() : base(nameof(RadiationPulseOverlay))
{
IoCManager.InjectDependencies(this);
_lastTick = _gameTiming.CurTime;