From: chromiumboy <50505512+chromiumboy@users.noreply.github.com>
Date: Sun, 31 Mar 2024 04:29:47 +0000 (-0500)
Subject: Improved RCDs (#22799)
X-Git-Url: https://git.smokeofanarchy.ru/gitweb.cgi?a=commitdiff_plain;h=02273ca0e7a4091bac88e585ecca5253dd0e7fd7;p=space-station-14.git
Improved RCDs (#22799)
* Initial radial menu prototyping for the RCD
* Radial UI buttons can send messages to the server
* Beginning to update RCDSystem
* RCD building system in progress
* Further updates
* Added extra effects, RCDSystem now reads RCD prototype data
* Replacing tiles is instant, multiple constructions are allowed, deconstruction is broken
* Added extra functionality to RadialContainers plus documentation
* Fixed localization of RCD UI strings
* Menu opens near cursor, added basic RCD
* Avoiding merge conflict
* Implemented atomized construction / deconstruction rules
* Increased RCD ammo base charges
* Moved input context definition to content
* Removed obsoleted code
* Updates to system
* Switch machine and computer frames for electrical cabling
* Added construction ghosts
* Fixed issue with keybind detection code
* Fixed RCD construction ghost mispredications
* Code clean up
* Updated deconstruction effects
* RCDs effects don't rotate
* Code clean up
* Balancing for ammo counts
* Code clean up
* Added missing localized strings
* More clean up
* Made directional window handling more robust
* Added documentation to radial menus and made them no longer dependent on Content
* Made radial containers more robust
* Further robustness to the radial menu
* The RCD submenu buttons are only shown when the destination layer has at least one children
* Expanded upon deconstructing plus construction balance
* Fixed line endings
* Updated list of RCD deconstructable entities. Now needs a component to deconstruct instead of a tag
* Bug fixes
* Revert unnecessary change
* Updated RCD strings
* Fixed bug
* More fixes
* Deconstructed tiles/subflooring convert to lattice instead
* Fixed failed tests (Linux doesn't like invalid spritespecifer paths)
* Fixing merge conflict
* Updated airlock assembly
* Fixing merge conflict
* Fixing merge conflict
* More fixing...
* Removed erroneous project file change
* Fixed string handling issue
* Trying to fix merge conflict
* Still fixing merge conflicts
* Balancing
* Hidden RCD construction ghosts when in 'build' mode
* Fixing merge conflict
* Implemented requested changes (Part 1)
* Added more requested changes
* Fix for failed test. Removed sussy null suppression
* Made requested changes - custom construction ghost system was replaced
* Fixing merge conflict
* Fixed merge conflict
* Fixed bug in RCD construction ghost validation
* Fixing merge conflict
* Merge conflict fixed
* Made required update
* Removed lingering RCD deconstruct tag
* Fixing merge conflict
* Merge conflict fixed
* Made requested changes
* Bug fixes and balancing
* Made string names more consistent
* Can no longer stack catwalks
---
diff --git a/Content.Client/Input/ContentContexts.cs b/Content.Client/Input/ContentContexts.cs
index 589de6d6a7..2e888b3df9 100644
--- a/Content.Client/Input/ContentContexts.cs
+++ b/Content.Client/Input/ContentContexts.cs
@@ -45,6 +45,9 @@ namespace Content.Client.Input
// Not in engine because the engine doesn't understand what a flipped object is
common.AddFunction(ContentKeyFunctions.EditorFlipObject);
+ // Not in engine so that the RCD can rotate objects
+ common.AddFunction(EngineKeyFunctions.EditorRotateObject);
+
var human = contexts.GetContext("human");
human.AddFunction(EngineKeyFunctions.MoveUp);
human.AddFunction(EngineKeyFunctions.MoveDown);
diff --git a/Content.Client/RCD/AlignRCDConstruction.cs b/Content.Client/RCD/AlignRCDConstruction.cs
new file mode 100644
index 0000000000..da7b22c91a
--- /dev/null
+++ b/Content.Client/RCD/AlignRCDConstruction.cs
@@ -0,0 +1,122 @@
+using System.Numerics;
+using Content.Client.Gameplay;
+using Content.Shared.Hands.Components;
+using Content.Shared.Interaction;
+using Content.Shared.RCD.Components;
+using Content.Shared.RCD.Systems;
+using Robust.Client.Placement;
+using Robust.Client.Player;
+using Robust.Client.State;
+using Robust.Shared.Map;
+using Robust.Shared.Map.Components;
+
+namespace Content.Client.RCD;
+
+public sealed class AlignRCDConstruction : PlacementMode
+{
+ [Dependency] private readonly IEntityManager _entityManager = default!;
+ [Dependency] private readonly IMapManager _mapManager = default!;
+ [Dependency] private readonly SharedMapSystem _mapSystem = default!;
+ [Dependency] private readonly RCDSystem _rcdSystem = default!;
+ [Dependency] private readonly SharedTransformSystem _transformSystem = default!;
+ [Dependency] private readonly IPlayerManager _playerManager = default!;
+ [Dependency] private readonly IStateManager _stateManager = default!;
+
+ private const float SearchBoxSize = 2f;
+ private const float PlaceColorBaseAlpha = 0.5f;
+
+ private EntityCoordinates _unalignedMouseCoords = default;
+
+ ///
+ /// This placement mode is not on the engine because it is content specific (i.e., for the RCD)
+ ///
+ public AlignRCDConstruction(PlacementManager pMan) : base(pMan)
+ {
+ var dependencies = IoCManager.Instance!;
+ _entityManager = dependencies.Resolve();
+ _mapManager = dependencies.Resolve();
+ _playerManager = dependencies.Resolve();
+ _stateManager = dependencies.Resolve();
+
+ _mapSystem = _entityManager.System();
+ _rcdSystem = _entityManager.System();
+ _transformSystem = _entityManager.System();
+
+ ValidPlaceColor = ValidPlaceColor.WithAlpha(PlaceColorBaseAlpha);
+ }
+
+ public override void AlignPlacementMode(ScreenCoordinates mouseScreen)
+ {
+ _unalignedMouseCoords = ScreenToCursorGrid(mouseScreen);
+ MouseCoords = _unalignedMouseCoords.AlignWithClosestGridTile(SearchBoxSize, _entityManager, _mapManager);
+
+ var gridId = MouseCoords.GetGridUid(_entityManager);
+
+ if (!_entityManager.TryGetComponent(gridId, out var mapGrid))
+ return;
+
+ CurrentTile = _mapSystem.GetTileRef(gridId.Value, mapGrid, MouseCoords);
+
+ float tileSize = mapGrid.TileSize;
+ GridDistancing = tileSize;
+
+ if (pManager.CurrentPermission!.IsTile)
+ {
+ MouseCoords = new EntityCoordinates(MouseCoords.EntityId, new Vector2(CurrentTile.X + tileSize / 2,
+ CurrentTile.Y + tileSize / 2));
+ }
+ else
+ {
+ MouseCoords = new EntityCoordinates(MouseCoords.EntityId, new Vector2(CurrentTile.X + tileSize / 2 + pManager.PlacementOffset.X,
+ CurrentTile.Y + tileSize / 2 + pManager.PlacementOffset.Y));
+ }
+ }
+
+ public override bool IsValidPosition(EntityCoordinates position)
+ {
+ var player = _playerManager.LocalSession?.AttachedEntity;
+
+ // If the destination is out of interaction range, set the placer alpha to zero
+ if (!_entityManager.TryGetComponent(player, out var xform))
+ return false;
+
+ if (!xform.Coordinates.InRange(_entityManager, _transformSystem, position, SharedInteractionSystem.InteractionRange))
+ {
+ InvalidPlaceColor = InvalidPlaceColor.WithAlpha(0);
+ return false;
+ }
+
+ // Otherwise restore the alpha value
+ else
+ {
+ InvalidPlaceColor = InvalidPlaceColor.WithAlpha(PlaceColorBaseAlpha);
+ }
+
+ // Determine if player is carrying an RCD in their active hand
+ if (!_entityManager.TryGetComponent(player, out var hands))
+ return false;
+
+ var heldEntity = hands.ActiveHand?.HeldEntity;
+
+ if (!_entityManager.TryGetComponent(heldEntity, out var rcd))
+ return false;
+
+ // Retrieve the map grid data for the position
+ if (!_rcdSystem.TryGetMapGridData(position, out var mapGridData))
+ return false;
+
+ // Determine if the user is hovering over a target
+ var currentState = _stateManager.CurrentState;
+
+ if (currentState is not GameplayStateBase screen)
+ return false;
+
+ var target = screen.GetClickedEntity(_unalignedMouseCoords.ToMap(_entityManager, _transformSystem));
+
+ // Determine if the RCD operation is valid or not
+ if (!_rcdSystem.IsRCDOperationStillValid(heldEntity.Value, rcd, mapGridData.Value, target, player.Value, false))
+ return false;
+
+ return true;
+ }
+}
diff --git a/Content.Client/RCD/RCDConstructionGhostSystem.cs b/Content.Client/RCD/RCDConstructionGhostSystem.cs
new file mode 100644
index 0000000000..792916b892
--- /dev/null
+++ b/Content.Client/RCD/RCDConstructionGhostSystem.cs
@@ -0,0 +1,78 @@
+using Content.Shared.Hands.Components;
+using Content.Shared.Interaction;
+using Content.Shared.RCD;
+using Content.Shared.RCD.Components;
+using Content.Shared.RCD.Systems;
+using Robust.Client.Placement;
+using Robust.Client.Player;
+using Robust.Shared.Enums;
+
+namespace Content.Client.RCD;
+
+public sealed class RCDConstructionGhostSystem : EntitySystem
+{
+ [Dependency] private readonly IPlayerManager _playerManager = default!;
+ [Dependency] private readonly RCDSystem _rcdSystem = default!;
+ [Dependency] private readonly IPlacementManager _placementManager = default!;
+
+ private string _placementMode = typeof(AlignRCDConstruction).Name;
+ private Direction _placementDirection = default;
+
+ public override void Update(float frameTime)
+ {
+ base.Update(frameTime);
+
+ // Get current placer data
+ var placerEntity = _placementManager.CurrentPermission?.MobUid;
+ var placerProto = _placementManager.CurrentPermission?.EntityType;
+ var placerIsRCD = HasComp(placerEntity);
+
+ // Exit if erasing or the current placer is not an RCD (build mode is active)
+ if (_placementManager.Eraser || (placerEntity != null && !placerIsRCD))
+ return;
+
+ // Determine if player is carrying an RCD in their active hand
+ var player = _playerManager.LocalSession?.AttachedEntity;
+
+ if (!TryComp(player, out var hands))
+ return;
+
+ var heldEntity = hands.ActiveHand?.HeldEntity;
+
+ if (!TryComp(heldEntity, out var rcd))
+ {
+ // If the player was holding an RCD, but is no longer, cancel placement
+ if (placerIsRCD)
+ _placementManager.Clear();
+
+ return;
+ }
+
+ // Update the direction the RCD prototype based on the placer direction
+ if (_placementDirection != _placementManager.Direction)
+ {
+ _placementDirection = _placementManager.Direction;
+ RaiseNetworkEvent(new RCDConstructionGhostRotationEvent(GetNetEntity(heldEntity.Value), _placementDirection));
+ }
+
+ // If the placer has not changed, exit
+ _rcdSystem.UpdateCachedPrototype(heldEntity.Value, rcd);
+
+ if (heldEntity == placerEntity && rcd.CachedPrototype.Prototype == placerProto)
+ return;
+
+ // Create a new placer
+ var newObjInfo = new PlacementInformation
+ {
+ MobUid = heldEntity.Value,
+ PlacementOption = _placementMode,
+ EntityType = rcd.CachedPrototype.Prototype,
+ Range = (int) Math.Ceiling(SharedInteractionSystem.InteractionRange),
+ IsTile = (rcd.CachedPrototype.Mode == RcdMode.ConstructTile),
+ UseEditorContext = false,
+ };
+
+ _placementManager.Clear();
+ _placementManager.BeginPlacing(newObjInfo);
+ }
+}
diff --git a/Content.Client/RCD/RCDMenu.xaml b/Content.Client/RCD/RCDMenu.xaml
new file mode 100644
index 0000000000..b3d5367a5f
--- /dev/null
+++ b/Content.Client/RCD/RCDMenu.xaml
@@ -0,0 +1,47 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Content.Client/RCD/RCDMenu.xaml.cs b/Content.Client/RCD/RCDMenu.xaml.cs
new file mode 100644
index 0000000000..8679e789dc
--- /dev/null
+++ b/Content.Client/RCD/RCDMenu.xaml.cs
@@ -0,0 +1,137 @@
+using Content.Client.UserInterface.Controls;
+using Content.Shared.RCD;
+using Content.Shared.RCD.Components;
+using Robust.Client.AutoGenerated;
+using Robust.Client.GameObjects;
+using Robust.Client.UserInterface;
+using Robust.Client.UserInterface.Controls;
+using Robust.Client.UserInterface.XAML;
+using Robust.Shared.Prototypes;
+using System.Numerics;
+
+namespace Content.Client.RCD;
+
+[GenerateTypedNameReferences]
+public sealed partial class RCDMenu : RadialMenu
+{
+ [Dependency] private readonly EntityManager _entManager = default!;
+ [Dependency] private readonly IPrototypeManager _protoManager = default!;
+
+ private readonly SpriteSystem _spriteSystem;
+
+ public event Action>? SendRCDSystemMessageAction;
+
+ public RCDMenu(EntityUid owner, RCDMenuBoundUserInterface bui)
+ {
+ IoCManager.InjectDependencies(this);
+ RobustXamlLoader.Load(this);
+
+ _spriteSystem = _entManager.System();
+
+ // Find the main radial container
+ var main = FindControl("Main");
+
+ if (main == null)
+ return;
+
+ // Populate secondary radial containers
+ if (!_entManager.TryGetComponent(owner, out var rcd))
+ return;
+
+ foreach (var protoId in rcd.AvailablePrototypes)
+ {
+ if (!_protoManager.TryIndex(protoId, out var proto))
+ continue;
+
+ if (proto.Mode == RcdMode.Invalid)
+ continue;
+
+ var parent = FindControl(proto.Category);
+
+ if (parent == null)
+ continue;
+
+ var name = Loc.GetString(proto.SetName);
+ name = char.ToUpper(name[0]) + name.Remove(0, 1);
+
+ var button = new RCDMenuButton()
+ {
+ StyleClasses = { "RadialMenuButton" },
+ SetSize = new Vector2(64f, 64f),
+ ToolTip = name,
+ ProtoId = protoId,
+ };
+
+ if (proto.Sprite != null)
+ {
+ var tex = new TextureRect()
+ {
+ VerticalAlignment = VAlignment.Center,
+ HorizontalAlignment = HAlignment.Center,
+ Texture = _spriteSystem.Frame0(proto.Sprite),
+ TextureScale = new Vector2(2f, 2f),
+ };
+
+ button.AddChild(tex);
+ }
+
+ parent.AddChild(button);
+
+ // Ensure that the button that transitions the menu to the associated category layer
+ // is visible in the main radial container (as these all start with Visible = false)
+ foreach (var child in main.Children)
+ {
+ var castChild = child as RadialMenuTextureButton;
+
+ if (castChild is not RadialMenuTextureButton)
+ continue;
+
+ if (castChild.TargetLayer == proto.Category)
+ {
+ castChild.Visible = true;
+ break;
+ }
+ }
+ }
+
+ // Set up menu actions
+ foreach (var child in Children)
+ AddRCDMenuButtonOnClickActions(child);
+
+ OnChildAdded += AddRCDMenuButtonOnClickActions;
+
+ SendRCDSystemMessageAction += bui.SendRCDSystemMessage;
+ }
+
+ private void AddRCDMenuButtonOnClickActions(Control control)
+ {
+ var radialContainer = control as RadialContainer;
+
+ if (radialContainer == null)
+ return;
+
+ foreach (var child in radialContainer.Children)
+ {
+ var castChild = child as RCDMenuButton;
+
+ if (castChild == null)
+ continue;
+
+ castChild.OnButtonUp += _ =>
+ {
+ SendRCDSystemMessageAction?.Invoke(castChild.ProtoId);
+ Close();
+ };
+ }
+ }
+}
+
+public sealed class RCDMenuButton : RadialMenuTextureButton
+{
+ public ProtoId ProtoId { get; set; }
+
+ public RCDMenuButton()
+ {
+
+ }
+}
diff --git a/Content.Client/RCD/RCDMenuBoundUserInterface.cs b/Content.Client/RCD/RCDMenuBoundUserInterface.cs
new file mode 100644
index 0000000000..a37dbcecf8
--- /dev/null
+++ b/Content.Client/RCD/RCDMenuBoundUserInterface.cs
@@ -0,0 +1,49 @@
+using Content.Shared.RCD;
+using Content.Shared.RCD.Components;
+using JetBrains.Annotations;
+using Robust.Client.Graphics;
+using Robust.Client.Input;
+using Robust.Shared.Prototypes;
+
+namespace Content.Client.RCD;
+
+[UsedImplicitly]
+public sealed class RCDMenuBoundUserInterface : BoundUserInterface
+{
+ [Dependency] private readonly IClyde _displayManager = default!;
+ [Dependency] private readonly IInputManager _inputManager = default!;
+
+ private RCDMenu? _menu;
+
+ public RCDMenuBoundUserInterface(EntityUid owner, Enum uiKey) : base(owner, uiKey)
+ {
+ IoCManager.InjectDependencies(this);
+ }
+
+ protected override void Open()
+ {
+ base.Open();
+
+ _menu = new(Owner, this);
+ _menu.OnClose += Close;
+
+ // Open the menu, centered on the mouse
+ var vpSize = _displayManager.ScreenSize;
+ _menu.OpenCenteredAt(_inputManager.MouseScreenPosition.Position / vpSize);
+ }
+
+ public void SendRCDSystemMessage(ProtoId protoId)
+ {
+ // A predicted message cannot be used here as the RCD UI is closed immediately
+ // after this message is sent, which will stop the server from receiving it
+ SendMessage(new RCDSystemMessage(protoId));
+ }
+
+ protected override void Dispose(bool disposing)
+ {
+ base.Dispose(disposing);
+ if (!disposing) return;
+
+ _menu?.Dispose();
+ }
+}
diff --git a/Content.Client/Stylesheets/StyleNano.cs b/Content.Client/Stylesheets/StyleNano.cs
index 426af1616e..2c7a1873a3 100644
--- a/Content.Client/Stylesheets/StyleNano.cs
+++ b/Content.Client/Stylesheets/StyleNano.cs
@@ -290,7 +290,7 @@ namespace Content.Client.Stylesheets
var buttonTex = resCache.GetTexture("/Textures/Interface/Nano/button.svg.96dpi.png");
var topButtonBase = new StyleBoxTexture
{
- Texture = buttonTex,
+ Texture = buttonTex,
};
topButtonBase.SetPatchMargin(StyleBox.Margin.All, 10);
topButtonBase.SetPadding(StyleBox.Margin.All, 0);
@@ -298,19 +298,19 @@ namespace Content.Client.Stylesheets
var topButtonOpenRight = new StyleBoxTexture(topButtonBase)
{
- Texture = new AtlasTexture(buttonTex, UIBox2.FromDimensions(new Vector2(0, 0), new Vector2(14, 24))),
+ Texture = new AtlasTexture(buttonTex, UIBox2.FromDimensions(new Vector2(0, 0), new Vector2(14, 24))),
};
topButtonOpenRight.SetPatchMargin(StyleBox.Margin.Right, 0);
var topButtonOpenLeft = new StyleBoxTexture(topButtonBase)
{
- Texture = new AtlasTexture(buttonTex, UIBox2.FromDimensions(new Vector2(10, 0), new Vector2(14, 24))),
+ Texture = new AtlasTexture(buttonTex, UIBox2.FromDimensions(new Vector2(10, 0), new Vector2(14, 24))),
};
topButtonOpenLeft.SetPatchMargin(StyleBox.Margin.Left, 0);
var topButtonSquare = new StyleBoxTexture(topButtonBase)
{
- Texture = new AtlasTexture(buttonTex, UIBox2.FromDimensions(new Vector2(10, 0), new Vector2(3, 24))),
+ Texture = new AtlasTexture(buttonTex, UIBox2.FromDimensions(new Vector2(10, 0), new Vector2(3, 24))),
};
topButtonSquare.SetPatchMargin(StyleBox.Margin.Horizontal, 0);
@@ -368,9 +368,9 @@ namespace Content.Client.Stylesheets
};
tabContainerPanel.SetPatchMargin(StyleBox.Margin.All, 2);
- var tabContainerBoxActive = new StyleBoxFlat {BackgroundColor = new Color(64, 64, 64)};
+ var tabContainerBoxActive = new StyleBoxFlat { BackgroundColor = new Color(64, 64, 64) };
tabContainerBoxActive.SetContentMarginOverride(StyleBox.Margin.Horizontal, 5);
- var tabContainerBoxInactive = new StyleBoxFlat {BackgroundColor = new Color(32, 32, 32)};
+ var tabContainerBoxInactive = new StyleBoxFlat { BackgroundColor = new Color(32, 32, 32) };
tabContainerBoxInactive.SetContentMarginOverride(StyleBox.Margin.Horizontal, 5);
var progressBarBackground = new StyleBoxFlat
@@ -409,21 +409,21 @@ namespace Content.Client.Stylesheets
// Placeholder
var placeholderTexture = resCache.GetTexture("/Textures/Interface/Nano/placeholder.png");
- var placeholder = new StyleBoxTexture {Texture = placeholderTexture};
+ var placeholder = new StyleBoxTexture { Texture = placeholderTexture };
placeholder.SetPatchMargin(StyleBox.Margin.All, 19);
placeholder.SetExpandMargin(StyleBox.Margin.All, -5);
placeholder.Mode = StyleBoxTexture.StretchMode.Tile;
- var itemListBackgroundSelected = new StyleBoxFlat {BackgroundColor = new Color(75, 75, 86)};
+ var itemListBackgroundSelected = new StyleBoxFlat { BackgroundColor = new Color(75, 75, 86) };
itemListBackgroundSelected.SetContentMarginOverride(StyleBox.Margin.Vertical, 2);
itemListBackgroundSelected.SetContentMarginOverride(StyleBox.Margin.Horizontal, 4);
- var itemListItemBackgroundDisabled = new StyleBoxFlat {BackgroundColor = new Color(10, 10, 12)};
+ var itemListItemBackgroundDisabled = new StyleBoxFlat { BackgroundColor = new Color(10, 10, 12) };
itemListItemBackgroundDisabled.SetContentMarginOverride(StyleBox.Margin.Vertical, 2);
itemListItemBackgroundDisabled.SetContentMarginOverride(StyleBox.Margin.Horizontal, 4);
- var itemListItemBackground = new StyleBoxFlat {BackgroundColor = new Color(55, 55, 68)};
+ var itemListItemBackground = new StyleBoxFlat { BackgroundColor = new Color(55, 55, 68) };
itemListItemBackground.SetContentMarginOverride(StyleBox.Margin.Vertical, 2);
itemListItemBackground.SetContentMarginOverride(StyleBox.Margin.Horizontal, 4);
- var itemListItemBackgroundTransparent = new StyleBoxFlat {BackgroundColor = Color.Transparent};
+ var itemListItemBackgroundTransparent = new StyleBoxFlat { BackgroundColor = Color.Transparent };
itemListItemBackgroundTransparent.SetContentMarginOverride(StyleBox.Margin.Vertical, 2);
itemListItemBackgroundTransparent.SetContentMarginOverride(StyleBox.Margin.Horizontal, 4);
@@ -489,9 +489,9 @@ namespace Content.Client.Stylesheets
sliderForeBox.SetPatchMargin(StyleBox.Margin.All, 12);
sliderGrabBox.SetPatchMargin(StyleBox.Margin.All, 12);
- var sliderFillGreen = new StyleBoxTexture(sliderFillBox) {Modulate = Color.LimeGreen};
- var sliderFillRed = new StyleBoxTexture(sliderFillBox) {Modulate = Color.Red};
- var sliderFillBlue = new StyleBoxTexture(sliderFillBox) {Modulate = Color.Blue};
+ var sliderFillGreen = new StyleBoxTexture(sliderFillBox) { Modulate = Color.LimeGreen };
+ var sliderFillRed = new StyleBoxTexture(sliderFillBox) { Modulate = Color.Red };
+ var sliderFillBlue = new StyleBoxTexture(sliderFillBox) { Modulate = Color.Blue };
var sliderFillWhite = new StyleBoxTexture(sliderFillBox) { Modulate = Color.White };
var boxFont13 = resCache.GetFont("/Fonts/Boxfont-round/Boxfont Round.ttf", 13);
@@ -1468,6 +1468,25 @@ namespace Content.Client.Stylesheets
Element