| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724 |
- using System.Diagnostics.CodeAnalysis;
- using System.Linq;
- using System.Numerics;
- using Content.Client.Hands.Systems;
- using Content.Client.Items.Systems;
- using Content.Client.Storage;
- using Content.Client.Storage.Systems;
- using Content.Shared.IdentityManagement;
- using Content.Shared.Input;
- using Content.Shared.Item;
- using Content.Shared.Storage;
- using Robust.Client.GameObjects;
- using Robust.Client.Graphics;
- using Robust.Client.UserInterface;
- using Robust.Client.UserInterface.Controls;
- using Robust.Client.UserInterface.CustomControls;
- using Robust.Shared.Collections;
- using Robust.Shared.Containers;
- using Robust.Shared.Timing;
- using Robust.Shared.Utility;
- namespace Content.Client.UserInterface.Systems.Storage.Controls;
- public sealed class StorageWindow : BaseWindow
- {
- [Dependency] private readonly IEntityManager _entity = default!;
- private readonly StorageUIController _storageController;
- public EntityUid? StorageEntity;
- private readonly GridContainer _pieceGrid;
- private readonly GridContainer _backgroundGrid;
- private readonly GridContainer _sidebar;
- private Control _titleContainer;
- private Label _titleLabel;
- // Needs to be nullable in case a piece is in default spot.
- private readonly Dictionary<EntityUid, (ItemStorageLocation? Loc, ItemGridPiece Control)> _pieces = new();
- private readonly List<Control> _controlGrid = new();
- private ValueList<EntityUid> _contained = new();
- private ValueList<EntityUid> _toRemove = new();
- private TextureButton? _backButton;
- private bool _isDirty;
- public event Action<GUIBoundKeyEventArgs, ItemGridPiece>? OnPiecePressed;
- public event Action<GUIBoundKeyEventArgs, ItemGridPiece>? OnPieceUnpressed;
- private readonly string _emptyTexturePath = "Storage/tile_empty";
- private Texture? _emptyTexture;
- private readonly string _blockedTexturePath = "Storage/tile_blocked";
- private Texture? _blockedTexture;
- private readonly string _emptyOpaqueTexturePath = "Storage/tile_empty_opaque";
- private Texture? _emptyOpaqueTexture;
- private readonly string _blockedOpaqueTexturePath = "Storage/tile_blocked_opaque";
- private Texture? _blockedOpaqueTexture;
- private readonly string _exitTexturePath = "Storage/exit";
- private Texture? _exitTexture;
- private readonly string _backTexturePath = "Storage/back";
- private Texture? _backTexture;
- private readonly string _sidebarTopTexturePath = "Storage/sidebar_top";
- private Texture? _sidebarTopTexture;
- private readonly string _sidebarMiddleTexturePath = "Storage/sidebar_mid";
- private Texture? _sidebarMiddleTexture;
- private readonly string _sidebarBottomTexturePath = "Storage/sidebar_bottom";
- private Texture? _sidebarBottomTexture;
- private readonly string _sidebarFatTexturePath = "Storage/sidebar_fat";
- private Texture? _sidebarFatTexture;
- public StorageWindow()
- {
- IoCManager.InjectDependencies(this);
- Resizable = false;
- _storageController = UserInterfaceManager.GetUIController<StorageUIController>();
- OnThemeUpdated();
- MouseFilter = MouseFilterMode.Stop;
- _sidebar = new GridContainer
- {
- Name = "SideBar",
- HSeparationOverride = 0,
- VSeparationOverride = 0,
- Columns = 1
- };
- _pieceGrid = new GridContainer
- {
- Name = "PieceGrid",
- HSeparationOverride = 0,
- VSeparationOverride = 0
- };
- _backgroundGrid = new GridContainer
- {
- Name = "BackgroundGrid",
- HSeparationOverride = 0,
- VSeparationOverride = 0
- };
- _titleLabel = new Label()
- {
- HorizontalExpand = true,
- Name = "StorageLabel",
- ClipText = true,
- Text = "Dummy",
- StyleClasses =
- {
- "FancyWindowTitle",
- }
- };
- _titleContainer = new PanelContainer()
- {
- StyleClasses =
- {
- "WindowHeadingBackground"
- },
- Children =
- {
- _titleLabel
- }
- };
- var container = new BoxContainer
- {
- Orientation = BoxContainer.LayoutOrientation.Vertical,
- Children =
- {
- _titleContainer,
- new BoxContainer
- {
- Orientation = BoxContainer.LayoutOrientation.Horizontal,
- Children =
- {
- _sidebar,
- new Control
- {
- Children =
- {
- _backgroundGrid,
- _pieceGrid
- }
- }
- }
- }
- }
- };
- AddChild(container);
- }
- protected override void OnThemeUpdated()
- {
- base.OnThemeUpdated();
- _emptyTexture = Theme.ResolveTextureOrNull(_emptyTexturePath)?.Texture;
- _blockedTexture = Theme.ResolveTextureOrNull(_blockedTexturePath)?.Texture;
- _emptyOpaqueTexture = Theme.ResolveTextureOrNull(_emptyOpaqueTexturePath)?.Texture;
- _blockedOpaqueTexture = Theme.ResolveTextureOrNull(_blockedOpaqueTexturePath)?.Texture;
- _exitTexture = Theme.ResolveTextureOrNull(_exitTexturePath)?.Texture;
- _backTexture = Theme.ResolveTextureOrNull(_backTexturePath)?.Texture;
- _sidebarTopTexture = Theme.ResolveTextureOrNull(_sidebarTopTexturePath)?.Texture;
- _sidebarMiddleTexture = Theme.ResolveTextureOrNull(_sidebarMiddleTexturePath)?.Texture;
- _sidebarBottomTexture = Theme.ResolveTextureOrNull(_sidebarBottomTexturePath)?.Texture;
- _sidebarFatTexture = Theme.ResolveTextureOrNull(_sidebarFatTexturePath)?.Texture;
- }
- public void UpdateContainer(Entity<StorageComponent>? entity)
- {
- Visible = entity != null;
- StorageEntity = entity;
- if (entity == null)
- return;
- if (UserInterfaceManager.GetUIController<StorageUIController>().WindowTitle)
- {
- _titleLabel.Text = Identity.Name(entity.Value, _entity);
- _titleContainer.Visible = true;
- }
- else
- {
- _titleContainer.Visible = false;
- }
- BuildGridRepresentation();
- }
- private void CloseParent()
- {
- if (StorageEntity == null)
- return;
- var containerSystem = _entity.System<SharedContainerSystem>();
- var uiSystem = _entity.System<UserInterfaceSystem>();
- if (containerSystem.TryGetContainingContainer(StorageEntity.Value, out var container) &&
- _entity.TryGetComponent(container.Owner, out StorageComponent? storage) &&
- storage.Container.Contains(StorageEntity.Value) &&
- uiSystem
- .TryGetOpenUi<StorageBoundUserInterface>(container.Owner,
- StorageComponent.StorageUiKey.Key,
- out var parentBui))
- {
- parentBui.CloseWindow(Position);
- }
- }
- private void BuildGridRepresentation()
- {
- if (!_entity.TryGetComponent<StorageComponent>(StorageEntity, out var comp) || comp.Grid.Count == 0)
- return;
- var boundingGrid = comp.Grid.GetBoundingBox();
- BuildBackground();
- #region Sidebar
- _sidebar.Children.Clear();
- var rows = boundingGrid.Height + 1;
- _sidebar.Rows = rows;
- var exitButton = new TextureButton
- {
- Name = "ExitButton",
- TextureNormal = _exitTexture,
- Scale = new Vector2(2, 2),
- };
- exitButton.OnPressed += _ =>
- {
- // Close ourselves and all parent BUIs.
- Close();
- CloseParent();
- };
- exitButton.OnKeyBindDown += args =>
- {
- // it just makes sense...
- if (!args.Handled && args.Function == ContentKeyFunctions.ActivateItemInWorld)
- {
- Close();
- CloseParent();
- args.Handle();
- }
- };
- var exitContainer = new BoxContainer
- {
- Name = "ExitContainer",
- Children =
- {
- new TextureRect
- {
- Texture = boundingGrid.Height != 0
- ? _sidebarTopTexture
- : _sidebarFatTexture,
- TextureScale = new Vector2(2, 2),
- Children =
- {
- exitButton
- }
- }
- }
- };
- _sidebar.AddChild(exitContainer);
- var offset = 2;
- if (_entity.System<StorageSystem>().NestedStorage && rows > 0)
- {
- _backButton = new TextureButton
- {
- TextureNormal = _backTexture,
- Scale = new Vector2(2, 2),
- };
- _backButton.OnPressed += _ =>
- {
- var containerSystem = _entity.System<SharedContainerSystem>();
- if (containerSystem.TryGetContainingContainer(StorageEntity.Value, out var container) &&
- _entity.TryGetComponent(container.Owner, out StorageComponent? storage) &&
- storage.Container.Contains(StorageEntity.Value))
- {
- Close();
- if (_entity.System<SharedUserInterfaceSystem>()
- .TryGetOpenUi<StorageBoundUserInterface>(container.Owner,
- StorageComponent.StorageUiKey.Key,
- out var parentBui))
- {
- parentBui.Show(Position);
- }
- }
- };
- var backContainer = new BoxContainer
- {
- Name = "ExitContainer",
- Children =
- {
- new TextureRect
- {
- Texture = rows > 2 ? _sidebarMiddleTexture : _sidebarBottomTexture,
- TextureScale = new Vector2(2, 2),
- Children =
- {
- _backButton,
- }
- }
- }
- };
- _sidebar.AddChild(backContainer);
- }
- var fillerRows = rows - offset;
- for (var i = 0; i < fillerRows; i++)
- {
- _sidebar.AddChild(new TextureRect
- {
- Texture = i != (fillerRows - 1) ? _sidebarMiddleTexture : _sidebarBottomTexture,
- TextureScale = new Vector2(2, 2),
- });
- }
- #endregion
- FlagDirty();
- }
- public void BuildBackground()
- {
- if (!_entity.TryGetComponent<StorageComponent>(StorageEntity, out var comp) || !comp.Grid.Any())
- return;
- var boundingGrid = comp.Grid.GetBoundingBox();
- var emptyTexture = _storageController.OpaqueStorageWindow
- ? _emptyOpaqueTexture
- : _emptyTexture;
- var blockedTexture = _storageController.OpaqueStorageWindow
- ? _blockedOpaqueTexture
- : _blockedTexture;
- _backgroundGrid.Children.Clear();
- _backgroundGrid.Rows = boundingGrid.Height + 1;
- _backgroundGrid.Columns = boundingGrid.Width + 1;
- for (var y = boundingGrid.Bottom; y <= boundingGrid.Top; y++)
- {
- for (var x = boundingGrid.Left; x <= boundingGrid.Right; x++)
- {
- var texture = comp.Grid.Contains(x, y)
- ? emptyTexture
- : blockedTexture;
- _backgroundGrid.AddChild(new TextureRect
- {
- Texture = texture,
- TextureScale = new Vector2(2, 2)
- });
- }
- }
- }
- public void Reclaim(ItemStorageLocation location, ItemGridPiece draggingGhost)
- {
- draggingGhost.OnPiecePressed += OnPiecePressed;
- draggingGhost.OnPieceUnpressed += OnPieceUnpressed;
- _pieces[draggingGhost.Entity] = (location, draggingGhost);
- draggingGhost.Location = location;
- var controlIndex = GetGridIndex(draggingGhost);
- _controlGrid[controlIndex].AddChild(draggingGhost);
- }
- private int GetGridIndex(ItemGridPiece piece)
- {
- return piece.Location.Position.X + piece.Location.Position.Y * _pieceGrid.Columns;
- }
- public void FlagDirty()
- {
- _isDirty = true;
- }
- public void RemoveGrid(ItemGridPiece control)
- {
- control.Orphan();
- _pieces.Remove(control.Entity);
- control.OnPiecePressed -= OnPiecePressed;
- control.OnPieceUnpressed -= OnPieceUnpressed;
- }
- public void BuildItemPieces()
- {
- if (!_entity.TryGetComponent<StorageComponent>(StorageEntity, out var storageComp))
- return;
- if (storageComp.Grid.Count == 0)
- return;
- var boundingGrid = storageComp.Grid.GetBoundingBox();
- var size = _emptyTexture!.Size * 2;
- _contained.Clear();
- _contained.AddRange(storageComp.Container.ContainedEntities.Reverse());
- // Build the grid representation
- if (_pieceGrid.Rows - 1 != boundingGrid.Height || _pieceGrid.Columns - 1 != boundingGrid.Width)
- {
- _pieceGrid.Rows = boundingGrid.Height + 1;
- _pieceGrid.Columns = boundingGrid.Width + 1;
- _controlGrid.Clear();
- for (var y = boundingGrid.Bottom; y <= boundingGrid.Top; y++)
- {
- for (var x = boundingGrid.Left; x <= boundingGrid.Right; x++)
- {
- var control = new Control
- {
- MinSize = size
- };
- _controlGrid.Add(control);
- _pieceGrid.AddChild(control);
- }
- }
- }
- _toRemove.Clear();
- // Remove entities no longer relevant / Update existing ones
- foreach (var (ent, data) in _pieces)
- {
- if (storageComp.StoredItems.TryGetValue(ent, out var updated))
- {
- data.Control.Marked = IsMarked(ent);
- if (data.Loc.Equals(updated))
- {
- DebugTools.Assert(data.Control.Location == updated);
- continue;
- }
- // Update
- data.Control.Location = updated;
- var index = GetGridIndex(data.Control);
- data.Control.Orphan();
- _controlGrid[index].AddChild(data.Control);
- _pieces[ent] = (updated, data.Control);
- continue;
- }
- _toRemove.Add(ent);
- }
- foreach (var ent in _toRemove)
- {
- _pieces.Remove(ent, out var data);
- data.Control.Orphan();
- }
- // Add new ones
- foreach (var (ent, loc) in storageComp.StoredItems)
- {
- if (_pieces.TryGetValue(ent, out var existing))
- {
- DebugTools.Assert(existing.Loc == loc);
- continue;
- }
- if (_entity.TryGetComponent<ItemComponent>(ent, out var itemEntComponent))
- {
- var gridPiece = new ItemGridPiece((ent, itemEntComponent), loc, _entity)
- {
- MinSize = size,
- Marked = IsMarked(ent),
- };
- gridPiece.OnPiecePressed += OnPiecePressed;
- gridPiece.OnPieceUnpressed += OnPieceUnpressed;
- var controlIndex = loc.Position.X + loc.Position.Y * (boundingGrid.Width + 1);
- _controlGrid[controlIndex].AddChild(gridPiece);
- _pieces[ent] = (loc, gridPiece);
- }
- }
- }
- private ItemGridPieceMarks? IsMarked(EntityUid uid)
- {
- return _contained.IndexOf(uid) switch
- {
- 0 => ItemGridPieceMarks.First,
- 1 => ItemGridPieceMarks.Second,
- _ => null,
- };
- }
- protected override void FrameUpdate(FrameEventArgs args)
- {
- base.FrameUpdate(args);
- if (!IsOpen)
- return;
- if (_isDirty)
- {
- _isDirty = false;
- BuildItemPieces();
- }
- var containerSystem = _entity.System<SharedContainerSystem>();
- if (_backButton != null)
- {
- if (StorageEntity != null && _entity.System<StorageSystem>().NestedStorage)
- {
- // If parent container nests us then show back button
- if (containerSystem.TryGetContainingContainer(StorageEntity.Value, out var container) &&
- _entity.TryGetComponent(container.Owner, out StorageComponent? storageComp) && storageComp.Container.Contains(StorageEntity.Value))
- {
- _backButton.Visible = true;
- }
- else
- {
- _backButton.Visible = false;
- }
- }
- // Hide the button.
- else
- {
- _backButton.Visible = false;
- }
- }
- var itemSystem = _entity.System<ItemSystem>();
- var storageSystem = _entity.System<StorageSystem>();
- var handsSystem = _entity.System<HandsSystem>();
- foreach (var child in _backgroundGrid.Children)
- {
- child.ModulateSelfOverride = Color.FromHex("#222222");
- }
- if (UserInterfaceManager.CurrentlyHovered is StorageWindow con && con != this)
- return;
- if (!_entity.TryGetComponent<StorageComponent>(StorageEntity, out var storageComponent))
- return;
- EntityUid currentEnt;
- ItemStorageLocation currentLocation;
- var usingInHand = false;
- if (_storageController.IsDragging && _storageController.DraggingGhost is { } dragging)
- {
- currentEnt = dragging.Entity;
- currentLocation = dragging.Location;
- }
- else if (handsSystem.GetActiveHandEntity() is { } handEntity &&
- storageSystem.CanInsert(StorageEntity.Value, handEntity, out _, storageComp: storageComponent, ignoreLocation: true))
- {
- currentEnt = handEntity;
- currentLocation = new ItemStorageLocation(_storageController.DraggingRotation, Vector2i.Zero);
- usingInHand = true;
- }
- else
- {
- return;
- }
- if (!_entity.TryGetComponent<ItemComponent>(currentEnt, out var itemComp))
- return;
- var origin = GetMouseGridPieceLocation((currentEnt, itemComp), currentLocation);
- var itemShape = itemSystem.GetAdjustedItemShape(
- (currentEnt, itemComp),
- currentLocation.Rotation,
- origin);
- var itemBounding = itemShape.GetBoundingBox();
- var validLocation = storageSystem.ItemFitsInGridLocation(
- (currentEnt, itemComp),
- (StorageEntity.Value, storageComponent),
- origin,
- currentLocation.Rotation);
- foreach (var locations in storageComponent.SavedLocations)
- {
- if (!_entity.TryGetComponent<MetaDataComponent>(currentEnt, out var meta) || meta.EntityName != locations.Key)
- continue;
- float spot = 0;
- var marked = new ValueList<Control>();
- foreach (var location in locations.Value)
- {
- var shape = itemSystem.GetAdjustedItemShape(currentEnt, location);
- var bound = shape.GetBoundingBox();
- var spotFree = storageSystem.ItemFitsInGridLocation(currentEnt, StorageEntity.Value, location);
- if (spotFree)
- spot++;
- for (var y = bound.Bottom; y <= bound.Top; y++)
- {
- for (var x = bound.Left; x <= bound.Right; x++)
- {
- if (TryGetBackgroundCell(x, y, out var cell) && shape.Contains(x, y) && !marked.Contains(cell))
- {
- marked.Add(cell);
- cell.ModulateSelfOverride = spotFree
- ? Color.FromHsv((0.18f, 1 / spot, 0.5f / spot + 0.5f, 1f))
- : Color.FromHex("#2222CC");
- }
- }
- }
- }
- }
- var validColor = usingInHand ? Color.Goldenrod : Color.FromHex("#1E8000");
- for (var y = itemBounding.Bottom; y <= itemBounding.Top; y++)
- {
- for (var x = itemBounding.Left; x <= itemBounding.Right; x++)
- {
- if (TryGetBackgroundCell(x, y, out var cell) && itemShape.Contains(x, y))
- {
- cell.ModulateSelfOverride = validLocation ? validColor : Color.FromHex("#B40046");
- }
- }
- }
- }
- protected override DragMode GetDragModeFor(Vector2 relativeMousePos)
- {
- if (_storageController.StaticStorageUIEnabled)
- return DragMode.None;
- if (_sidebar.SizeBox.Contains(relativeMousePos - _sidebar.Position))
- {
- return DragMode.Move;
- }
- return DragMode.None;
- }
- public Vector2i GetMouseGridPieceLocation(Entity<ItemComponent?> entity, ItemStorageLocation location)
- {
- var origin = Vector2i.Zero;
- if (StorageEntity != null)
- origin = _entity.GetComponent<StorageComponent>(StorageEntity.Value).Grid.GetBoundingBox().BottomLeft;
- var textureSize = (Vector2) _emptyTexture!.Size * 2;
- var position = ((UserInterfaceManager.MousePositionScaled.Position
- - _backgroundGrid.GlobalPosition
- - ItemGridPiece.GetCenterOffset(entity, location, _entity) * 2
- + textureSize / 2f)
- / textureSize).Floored() + origin;
- return position;
- }
- public bool TryGetBackgroundCell(int x, int y, [NotNullWhen(true)] out Control? cell)
- {
- cell = null;
- if (!_entity.TryGetComponent<StorageComponent>(StorageEntity, out var storageComponent))
- return false;
- var boundingBox = storageComponent.Grid.GetBoundingBox();
- x -= boundingBox.Left;
- y -= boundingBox.Bottom;
- if (x < 0 ||
- x >= _backgroundGrid.Columns ||
- y < 0 ||
- y >= _backgroundGrid.Rows)
- {
- return false;
- }
- cell = _backgroundGrid.GetChild(y * _backgroundGrid.Columns + x);
- return true;
- }
- protected override void KeyBindDown(GUIBoundKeyEventArgs args)
- {
- base.KeyBindDown(args);
- if (!IsOpen)
- return;
- var storageSystem = _entity.System<StorageSystem>();
- var handsSystem = _entity.System<HandsSystem>();
- if (args.Function == ContentKeyFunctions.MoveStoredItem && StorageEntity != null)
- {
- if (handsSystem.GetActiveHandEntity() is { } handEntity &&
- storageSystem.CanInsert(StorageEntity.Value, handEntity, out _))
- {
- var pos = GetMouseGridPieceLocation((handEntity, null),
- new ItemStorageLocation(_storageController.DraggingRotation, Vector2i.Zero));
- var insertLocation = new ItemStorageLocation(_storageController.DraggingRotation, pos);
- if (storageSystem.ItemFitsInGridLocation(
- (handEntity, null),
- (StorageEntity.Value, null),
- insertLocation))
- {
- _entity.RaisePredictiveEvent(new StorageInsertItemIntoLocationEvent(
- _entity.GetNetEntity(handEntity),
- _entity.GetNetEntity(StorageEntity.Value),
- insertLocation));
- _storageController.DraggingRotation = Angle.Zero;
- args.Handle();
- }
- }
- }
- }
- }
|