Fix screenspace popups (#24987)

* Fix screenspace popups

Never got around to it earlier but need to draw it above UI controls.

* Minor null change
This commit is contained in:
metalgearsloth
2024-02-10 19:51:11 +11:00
committed by GitHub
parent 98015a4523
commit 560ea9775a
3 changed files with 137 additions and 71 deletions

View File

@@ -1,12 +1,6 @@
using System.Numerics;
using Content.Client.Examine;
using Content.Shared.CCVar;
using Content.Shared.Examine;
using Content.Shared.Interaction;
using Content.Shared.Popups;
using Robust.Client.Graphics;
using Robust.Client.Player;
using Robust.Client.ResourceManagement;
using Robust.Client.UserInterface;
using Robust.Shared;
using Robust.Shared.Configuration;
@@ -26,11 +20,9 @@ public sealed class PopupOverlay : Overlay
private readonly IPlayerManager _playerMgr;
private readonly IUserInterfaceManager _uiManager;
private readonly PopupSystem _popup;
private readonly PopupUIController _controller;
private readonly ShaderInstance _shader;
private readonly Font _smallFont;
private readonly Font _mediumFont;
private readonly Font _largeFont;
public override OverlaySpace Space => OverlaySpace.ScreenSpace;
@@ -39,8 +31,8 @@ public sealed class PopupOverlay : Overlay
IEntityManager entManager,
IPlayerManager playerMgr,
IPrototypeManager protoManager,
IResourceCache cache,
IUserInterfaceManager uiManager,
PopupUIController controller,
PopupSystem popup)
{
_configManager = configManager;
@@ -48,11 +40,9 @@ public sealed class PopupOverlay : Overlay
_playerMgr = playerMgr;
_uiManager = uiManager;
_popup = popup;
_controller = controller;
_shader = protoManager.Index<ShaderPrototype>("unshaded").Instance();
_smallFont = new VectorFont(cache.GetResource<FontResource>("/Fonts/NotoSans/NotoSans-Italic.ttf"), 10);
_mediumFont = new VectorFont(cache.GetResource<FontResource>("/Fonts/NotoSans/NotoSans-Italic.ttf"), 12);
_largeFont = new VectorFont(cache.GetResource<FontResource>("/Fonts/NotoSans/NotoSans-BoldItalic.ttf"), 14);
}
protected override void Draw(in OverlayDrawArgs args)
@@ -68,19 +58,18 @@ public sealed class PopupOverlay : Overlay
scale = _uiManager.DefaultUIScale;
DrawWorld(args.ScreenHandle, args, scale);
DrawScreen(args.ScreenHandle, args, scale);
args.DrawingHandle.UseShader(null);
}
private void DrawWorld(DrawingHandleScreen worldHandle, OverlayDrawArgs args, float scale)
{
if (_popup.WorldLabels.Count == 0)
if (_popup.WorldLabels.Count == 0 || args.ViewportControl == null)
return;
var matrix = args.ViewportControl!.GetWorldToScreenMatrix();
var matrix = args.ViewportControl.GetWorldToScreenMatrix();
var viewPos = new MapCoordinates(args.WorldAABB.Center, args.MapId);
var ourEntity = _playerMgr.LocalPlayer?.ControlledEntity;
var ourEntity = _playerMgr.LocalEntity;
foreach (var popup in _popup.WorldLabels)
{
@@ -92,62 +81,12 @@ public sealed class PopupOverlay : Overlay
var distance = (mapPos.Position - args.WorldBounds.Center).Length();
// Should handle fade here too wyci.
if (!args.WorldAABB.Contains(mapPos.Position) || !ExamineSystemShared.InRangeUnOccluded(viewPos, mapPos, distance,
if (!args.WorldBounds.Contains(mapPos.Position) || !ExamineSystemShared.InRangeUnOccluded(viewPos, mapPos, distance,
e => e == popup.InitialPos.EntityId || e == ourEntity, entMan: _entManager))
continue;
var pos = matrix.Transform(mapPos.Position);
DrawPopup(popup, worldHandle, pos, scale);
_controller.DrawPopup(popup, worldHandle, pos, scale);
}
}
private void DrawScreen(DrawingHandleScreen screenHandle, OverlayDrawArgs args, float scale)
{
foreach (var popup in _popup.CursorLabels)
{
// Different window
if (popup.InitialPos.Window != args.ViewportControl?.Window?.Id)
continue;
DrawPopup(popup, screenHandle, popup.InitialPos.Position, scale);
}
}
private void DrawPopup(PopupSystem.PopupLabel popup, DrawingHandleScreen handle, Vector2 position, float scale)
{
var lifetime = PopupSystem.GetPopupLifetime(popup);
// Keep alpha at 1 until TotalTime passes half its lifetime, then gradually decrease to 0.
var alpha = MathF.Min(1f, 1f - MathF.Max(0f, popup.TotalTime - lifetime / 2) * 2 / lifetime);
var updatedPosition = position - new Vector2(0f, MathF.Min(8f, 12f * (popup.TotalTime * popup.TotalTime + popup.TotalTime)));
var font = _smallFont;
var color = Color.White.WithAlpha(alpha);
switch (popup.Type)
{
case PopupType.SmallCaution:
color = Color.Red;
break;
case PopupType.Medium:
font = _mediumFont;
color = Color.LightGray;
break;
case PopupType.MediumCaution:
font = _mediumFont;
color = Color.Red;
break;
case PopupType.Large:
font = _largeFont;
color = Color.LightGray;
break;
case PopupType.LargeCaution:
font = _largeFont;
color = Color.Red;
break;
}
var dimensions = handle.GetDimensions(font, popup.Text, scale);
handle.DrawString(font, updatedPosition - dimensions / 2f, popup.Text, scale, color.WithAlpha(alpha));
}
}

View File

@@ -23,7 +23,6 @@ namespace Content.Client.Popups
[Dependency] private readonly IOverlayManager _overlay = default!;
[Dependency] private readonly IPlayerManager _playerManager = default!;
[Dependency] private readonly IPrototypeManager _prototype = default!;
[Dependency] private readonly IResourceCache _resource = default!;
[Dependency] private readonly IGameTiming _timing = default!;
[Dependency] private readonly IUserInterfaceManager _uiManager = default!;
[Dependency] private readonly IReplayRecordingManager _replayRecording = default!;
@@ -45,7 +44,14 @@ namespace Content.Client.Popups
SubscribeNetworkEvent<PopupEntityEvent>(OnPopupEntityEvent);
SubscribeNetworkEvent<RoundRestartCleanupEvent>(OnRoundRestart);
_overlay
.AddOverlay(new PopupOverlay(_configManager, EntityManager, _playerManager, _prototype, _resource, _uiManager, this));
.AddOverlay(new PopupOverlay(
_configManager,
EntityManager,
_playerManager,
_prototype,
_uiManager,
_uiManager.GetUIController<PopupUIController>(),
this));
}
public override void Shutdown()

View File

@@ -0,0 +1,121 @@
using System.Numerics;
using Content.Client.Gameplay;
using Content.Shared.Popups;
using Robust.Client.Graphics;
using Robust.Client.ResourceManagement;
using Robust.Client.UserInterface;
using Robust.Client.UserInterface.Controllers;
namespace Content.Client.Popups;
/// <summary>
/// Handles screens-space popups. World popups are handled via PopupOverlay.
/// </summary>
public sealed class PopupUIController : UIController, IOnStateEntered<GameplayState>, IOnStateExited<GameplayState>
{
[UISystemDependency] private readonly PopupSystem? _popup = default!;
private Font _smallFont = default!;
private Font _mediumFont = default!;
private Font _largeFont = default!;
private PopupRootControl? _popupControl;
public override void Initialize()
{
base.Initialize();
var cache = IoCManager.Resolve<IResourceCache>();
_smallFont = new VectorFont(cache.GetResource<FontResource>("/Fonts/NotoSans/NotoSans-Italic.ttf"), 10);
_mediumFont = new VectorFont(cache.GetResource<FontResource>("/Fonts/NotoSans/NotoSans-Italic.ttf"), 12);
_largeFont = new VectorFont(cache.GetResource<FontResource>("/Fonts/NotoSans/NotoSans-BoldItalic.ttf"), 14);
}
public void OnStateEntered(GameplayState state)
{
_popupControl = new PopupRootControl(_popup, this);
UIManager.RootControl.AddChild(_popupControl);
}
public void OnStateExited(GameplayState state)
{
if (_popupControl == null)
return;
UIManager.RootControl.RemoveChild(_popupControl);
_popupControl = null;
}
public void DrawPopup(PopupSystem.PopupLabel popup, DrawingHandleScreen handle, Vector2 position, float scale)
{
var lifetime = PopupSystem.GetPopupLifetime(popup);
// Keep alpha at 1 until TotalTime passes half its lifetime, then gradually decrease to 0.
var alpha = MathF.Min(1f, 1f - MathF.Max(0f, popup.TotalTime - lifetime / 2) * 2 / lifetime);
var updatedPosition = position - new Vector2(0f, MathF.Min(8f, 12f * (popup.TotalTime * popup.TotalTime + popup.TotalTime)));
var font = _smallFont;
var color = Color.White.WithAlpha(alpha);
switch (popup.Type)
{
case PopupType.SmallCaution:
color = Color.Red;
break;
case PopupType.Medium:
font = _mediumFont;
color = Color.LightGray;
break;
case PopupType.MediumCaution:
font = _mediumFont;
color = Color.Red;
break;
case PopupType.Large:
font = _largeFont;
color = Color.LightGray;
break;
case PopupType.LargeCaution:
font = _largeFont;
color = Color.Red;
break;
}
var dimensions = handle.GetDimensions(font, popup.Text, scale);
handle.DrawString(font, updatedPosition - dimensions / 2f, popup.Text, scale, color.WithAlpha(alpha));
}
/// <summary>
/// Handles drawing all screen popups.
/// </summary>
private sealed class PopupRootControl : Control
{
private readonly PopupSystem? _popup;
private readonly PopupUIController _controller;
public PopupRootControl(PopupSystem? system, PopupUIController controller)
{
_popup = system;
_controller = controller;
}
protected override void Draw(DrawingHandleScreen handle)
{
base.Draw(handle);
if (_popup == null)
return;
// Different window
var windowId = UserInterfaceManager.RootControl.Window.Id;
foreach (var popup in _popup.CursorLabels)
{
if (popup.InitialPos.Window != windowId)
continue;
_controller.DrawPopup(popup, handle, popup.InitialPos.Position, UIScale);
}
}
}
}