diff --git a/Content.Client/EscapeMenu/UI/Tabs/GraphicsTab.xaml b/Content.Client/EscapeMenu/UI/Tabs/GraphicsTab.xaml index f8ae37134a..7d22e1ef52 100644 --- a/Content.Client/EscapeMenu/UI/Tabs/GraphicsTab.xaml +++ b/Content.Client/EscapeMenu/UI/Tabs/GraphicsTab.xaml @@ -19,6 +19,7 @@ + diff --git a/Content.Client/EscapeMenu/UI/Tabs/GraphicsTab.xaml.cs b/Content.Client/EscapeMenu/UI/Tabs/GraphicsTab.xaml.cs index 25583b1e39..112be58634 100644 --- a/Content.Client/EscapeMenu/UI/Tabs/GraphicsTab.xaml.cs +++ b/Content.Client/EscapeMenu/UI/Tabs/GraphicsTab.xaml.cs @@ -73,6 +73,7 @@ namespace Content.Client.EscapeMenu.UI.Tabs UpdateViewportScale(); }; + ShowHeldItemCheckBox.OnToggled += OnCheckBoxToggled; IntegerScalingCheckBox.OnToggled += OnCheckBoxToggled; ViewportLowResCheckBox.OnToggled += OnCheckBoxToggled; ApplyButton.OnPressed += OnApplyButtonPressed; @@ -85,6 +86,7 @@ namespace Content.Client.EscapeMenu.UI.Tabs ViewportStretchCheckBox.Pressed = _cfg.GetCVar(CCVars.ViewportStretch); IntegerScalingCheckBox.Pressed = _cfg.GetCVar(CCVars.ViewportSnapToleranceMargin) != 0; ViewportLowResCheckBox.Pressed = !_cfg.GetCVar(CCVars.ViewportScaleRender); + ShowHeldItemCheckBox.Pressed = _cfg.GetCVar(CCVars.HudHeldItemShow); UpdateViewportScale(); UpdateApplyButton(); @@ -119,6 +121,7 @@ namespace Content.Client.EscapeMenu.UI.Tabs _cfg.SetCVar(CCVars.ViewportSnapToleranceMargin, IntegerScalingCheckBox.Pressed ? CCVars.ViewportSnapToleranceMargin.DefaultValue : 0); _cfg.SetCVar(CCVars.ViewportScaleRender, !ViewportLowResCheckBox.Pressed); + _cfg.SetCVar(CCVars.HudHeldItemShow, ShowHeldItemCheckBox.Pressed); _cfg.SaveToFile(); UpdateApplyButton(); } @@ -145,6 +148,7 @@ namespace Content.Client.EscapeMenu.UI.Tabs var isVPScaleSame = (int) ViewportScaleSlider.Value == _cfg.GetCVar(CCVars.ViewportFixedScaleFactor); var isIntegerScalingSame = IntegerScalingCheckBox.Pressed == (_cfg.GetCVar(CCVars.ViewportSnapToleranceMargin) != 0); var isVPResSame = ViewportLowResCheckBox.Pressed == !_cfg.GetCVar(CCVars.ViewportScaleRender); + var isShowHeldItemSame = ShowHeldItemCheckBox.Pressed == _cfg.GetCVar(CCVars.HudHeldItemShow); ApplyButton.Disabled = isVSyncSame && isFullscreenSame && @@ -154,7 +158,8 @@ namespace Content.Client.EscapeMenu.UI.Tabs isVPScaleSame && isIntegerScalingSame && isVPResSame && - isHudThemeSame; + isHudThemeSame && + isShowHeldItemSame; } private bool ConfigIsFullscreen => diff --git a/Content.Client/Hands/ShowHandItemOverlay.cs b/Content.Client/Hands/ShowHandItemOverlay.cs new file mode 100644 index 0000000000..46cfb13ceb --- /dev/null +++ b/Content.Client/Hands/ShowHandItemOverlay.cs @@ -0,0 +1,66 @@ +using Content.Shared.CCVar; +using Robust.Client.Graphics; +using Robust.Client.Input; +using Robust.Shared; +using Robust.Shared.Configuration; +using Robust.Shared.Enums; +using Robust.Shared.GameObjects; +using Robust.Shared.IoC; +using Robust.Shared.Maths; + +namespace Content.Client.Hands +{ + public sealed class ShowHandItemOverlay : Overlay + { + [Dependency] private readonly IConfigurationManager _cfg = default!; + [Dependency] private readonly IInputManager _inputManager = default!; + [Dependency] private readonly IClyde _clyde = default!; + + private readonly IRenderTexture _renderBackbuffer; + + public override OverlaySpace Space => OverlaySpace.ScreenSpace; + + public ShowHandItemOverlay() + { + IoCManager.InjectDependencies(this); + + _renderBackbuffer = _clyde.CreateRenderTarget( + (64, 64), + new RenderTargetFormatParameters(RenderTargetColorFormat.Rgba8Srgb, true), + new TextureSampleParameters + { + Filter = true + }, nameof(ShowHandItemOverlay)); + } + + protected override void DisposeBehavior() + { + base.DisposeBehavior(); + + _renderBackbuffer.Dispose(); + } + + protected override void Draw(in OverlayDrawArgs args) + { + var sys = EntitySystem.Get(); + var handEntity = sys.GetActiveHandEntity(); + + if (handEntity == null || !_cfg.GetCVar(CCVars.HudHeldItemShow)) + return; + + var screen = args.ScreenHandle; + var halfSize = _renderBackbuffer.Size / 2; + + screen.RenderInRenderTarget(_renderBackbuffer, () => + { + screen.DrawEntity(handEntity, halfSize, new Vector2(1f, 1f) * _cfg.GetCVar(CVars.DisplayUIScale), Direction.South); + }, Color.Transparent); + + var offset = _cfg.GetCVar(CCVars.HudHeldItemOffset); + + var mousePos = _inputManager.MouseScreenPosition.Position; + screen.DrawTexture(_renderBackbuffer.Texture, mousePos - halfSize + offset, Color.White.WithAlpha(0.75f)); + // screen.DrawRect(UIBox2.FromDimensions((offset, offset) + mousePos, (32, 32)), Color.Red); + } + } +} diff --git a/Content.Client/Hands/Systems/HandsSystem.cs b/Content.Client/Hands/Systems/HandsSystem.cs index c65b9e197f..fc98ea8d1c 100644 --- a/Content.Client/Hands/Systems/HandsSystem.cs +++ b/Content.Client/Hands/Systems/HandsSystem.cs @@ -67,9 +67,7 @@ namespace Content.Client.Hands public HandsGuiState GetGuiState() { - var player = _playerManager.LocalPlayer?.ControlledEntity; - - if (player == null || !player.TryGetComponent(out HandsComponent? hands)) + if (GetPlayerHandsComponent() is not { } hands) return new HandsGuiState(Array.Empty()); var states = hands.Hands @@ -79,6 +77,24 @@ namespace Content.Client.Hands return new HandsGuiState(states, hands.ActiveHand); } + public IEntity? GetActiveHandEntity() + { + if (GetPlayerHandsComponent() is not { ActiveHand: { } active } hands) + return null; + + return hands.GetHand(active).HeldEntity; + } + + private HandsComponent? GetPlayerHandsComponent() + { + var player = _playerManager.LocalPlayer?.ControlledEntity; + + if (player == null || !player.TryGetComponent(out HandsComponent? hands)) + return null; + + return hands; + } + public void UIHandClick(HandsComponent hands, string handName) { if (!hands.TryGetHand(handName, out var pressedHand)) diff --git a/Content.Client/Viewport/GameScreen.cs b/Content.Client/Viewport/GameScreen.cs index e8a93e17c0..97335ff30a 100644 --- a/Content.Client/Viewport/GameScreen.cs +++ b/Content.Client/Viewport/GameScreen.cs @@ -3,6 +3,7 @@ using Content.Client.Chat; using Content.Client.Chat.Managers; using Content.Client.Chat.UI; using Content.Client.Construction.UI; +using Content.Client.Hands; using Content.Client.HUD; using Content.Client.HUD.UI; using Content.Client.Voting; @@ -29,6 +30,7 @@ namespace Content.Client.Viewport [Dependency] private readonly IChatManager _chatManager = default!; [Dependency] private readonly IVoteManager _voteManager = default!; [Dependency] private readonly IEyeManager _eyeManager = default!; + [Dependency] private readonly IOverlayManager _overlayManager = default!; [ViewVariables] private ChatBox? _gameChat; private ConstructionMenuPresenter? _constructionMenu; @@ -70,10 +72,13 @@ namespace Content.Client.Viewport SetupPresenters(); _eyeManager.MainViewport = Viewport.Viewport; + + _overlayManager.AddOverlay(new ShowHandItemOverlay()); } public override void Shutdown() { + _overlayManager.RemoveOverlay(); DisposePresenters(); base.Shutdown(); diff --git a/Content.Shared/CCVar/CCVars.cs b/Content.Shared/CCVar/CCVars.cs index 0dbad615ae..a844896c50 100644 --- a/Content.Shared/CCVar/CCVars.cs +++ b/Content.Shared/CCVar/CCVars.cs @@ -245,6 +245,13 @@ namespace Content.Shared.CCVar public static readonly CVarDef HudTheme = CVarDef.Create("hud.theme", 0, CVar.ARCHIVE | CVar.CLIENTONLY); + public static readonly CVarDef HudHeldItemShow = + CVarDef.Create("hud.held_item_show", true, CVar.ARCHIVE | CVar.CLIENTONLY); + + public static readonly CVarDef HudHeldItemOffset = + CVarDef.Create("hud.held_item_offset", 28f, CVar.ARCHIVE | CVar.CLIENTONLY); + + /* * AI */ diff --git a/Resources/Locale/en-US/escape-menu/ui/options-menu.ftl b/Resources/Locale/en-US/escape-menu/ui/options-menu.ftl index 1b7328b712..1122090f48 100644 --- a/Resources/Locale/en-US/escape-menu/ui/options-menu.ftl +++ b/Resources/Locale/en-US/escape-menu/ui/options-menu.ftl @@ -18,6 +18,7 @@ ui-options-volume-percent = { TOSTRING($volume, "P0") } ## Graphics menu +ui-options-show-held-item = Show held item next to cursor? ui-options-vsync = VSync ui-options-fullscreen = Fullscreen ui-options-lighting-label = Lighting Quality: