diff --git a/Content.Client/Storage/StorageBoundUserInterface.cs b/Content.Client/Storage/StorageBoundUserInterface.cs index bacc90eabff..899df30f7fc 100644 --- a/Content.Client/Storage/StorageBoundUserInterface.cs +++ b/Content.Client/Storage/StorageBoundUserInterface.cs @@ -1,80 +1,37 @@ -using Content.Client.UserInterface.Systems.Storage; -using Content.Client.UserInterface.Systems.Storage.Controls; +using Content.Client.Storage.Systems; using Content.Shared.Storage; using JetBrains.Annotations; -using Robust.Client.UserInterface; namespace Content.Client.Storage; [UsedImplicitly] public sealed class StorageBoundUserInterface : BoundUserInterface { - private StorageWindow? _window; + [Dependency] private readonly IEntityManager _entManager = default!; + + private readonly StorageSystem _storage; public StorageBoundUserInterface(EntityUid owner, Enum uiKey) : base(owner, uiKey) { + IoCManager.InjectDependencies(this); + _storage = _entManager.System(); } protected override void Open() { base.Open(); - _window = IoCManager.Resolve() - .GetUIController() - .CreateStorageWindow(Owner); - - if (EntMan.TryGetComponent(Owner, out StorageComponent? storage)) - { - _window.UpdateContainer((Owner, storage)); - } - - _window.OnClose += Close; - _window.FlagDirty(); - } - - public void Refresh() - { - _window?.FlagDirty(); - } - - public void Reclaim() - { - if (_window == null) - return; - - _window.OnClose -= Close; - _window.Orphan(); - _window = null; + if (_entManager.TryGetComponent(Owner, out var comp)) + _storage.OpenStorageWindow((Owner, comp)); } protected override void Dispose(bool disposing) { base.Dispose(disposing); - - Reclaim(); - } - - public void Hide() - { - if (_window == null) + if (!disposing) return; - _window.Visible = false; - } - - public void Show() - { - if (_window == null) - return; - - _window.Visible = true; - } - - public void ReOpen() - { - _window?.Orphan(); - _window = null; - Open(); + _storage.CloseStorageWindow(Owner); } } diff --git a/Content.Client/Storage/Systems/StorageSystem.cs b/Content.Client/Storage/Systems/StorageSystem.cs index ab4d9407b22..eea7b9ec797 100644 --- a/Content.Client/Storage/Systems/StorageSystem.cs +++ b/Content.Client/Storage/Systems/StorageSystem.cs @@ -4,8 +4,7 @@ using Content.Shared.Hands; using Content.Shared.Storage; using Content.Shared.Storage.EntitySystems; -using Robust.Client.Player; -using Robust.Shared.GameStates; +using Robust.Shared.Collections; using Robust.Shared.Map; using Robust.Shared.Timing; @@ -14,95 +13,114 @@ namespace Content.Client.Storage.Systems; public sealed class StorageSystem : SharedStorageSystem { [Dependency] private readonly IGameTiming _timing = default!; - [Dependency] private readonly IPlayerManager _player = default!; [Dependency] private readonly EntityPickupAnimationSystem _entityPickupAnimation = default!; - private Dictionary _oldStoredItems = new(); + private readonly List> _openStorages = new(); + public int OpenStorageAmount => _openStorages.Count; + + public event Action>? StorageUpdated; + public event Action?>? StorageOrderChanged; public override void Initialize() { base.Initialize(); - SubscribeLocalEvent(OnStorageHandleState); + SubscribeLocalEvent(OnShutdown); SubscribeNetworkEvent(HandlePickupAnimation); SubscribeAllEvent(HandleAnimatingInsertingEntities); } - private void OnStorageHandleState(EntityUid uid, StorageComponent component, ref ComponentHandleState args) + public override void UpdateUI(Entity entity) { - if (args.Current is not StorageComponentState state) - return; - - component.Grid.Clear(); - component.Grid.AddRange(state.Grid); - component.MaxItemSize = state.MaxItemSize; - component.Whitelist = state.Whitelist; - component.Blacklist = state.Blacklist; - - _oldStoredItems.Clear(); + if (Resolve(entity.Owner, ref entity.Comp)) + StorageUpdated?.Invoke((entity, entity.Comp)); + } - foreach (var item in component.StoredItems) + public void OpenStorageWindow(Entity entity) + { + if (_openStorages.Contains(entity)) { - _oldStoredItems.Add(item.Key, item.Value); - } + if (_openStorages.LastOrDefault() == entity) + { + CloseStorageWindow((entity, entity.Comp)); + } + else + { + var storages = new ValueList>(_openStorages); + var reverseStorages = storages.Reverse(); - component.StoredItems.Clear(); + foreach (var storageEnt in reverseStorages) + { + if (storageEnt == entity) + break; - foreach (var (nent, location) in state.StoredItems) - { - var ent = EnsureEntity(nent, uid); - component.StoredItems[ent] = location; + CloseStorageBoundUserInterface(storageEnt.Owner); + _openStorages.Remove(entity); + } + } + return; } - component.SavedLocations.Clear(); + ClearNonParentStorages(entity); + _openStorages.Add(entity); + Entity? last = _openStorages.LastOrDefault(); + StorageOrderChanged?.Invoke(last); + } - foreach (var loc in state.SavedLocations) - { - component.SavedLocations[loc.Key] = new(loc.Value); - } + public void CloseStorageWindow(Entity entity) + { + if (!Resolve(entity, ref entity.Comp, false)) + return; - var uiDirty = !component.StoredItems.SequenceEqual(_oldStoredItems); + if (!_openStorages.Contains((entity, entity.Comp))) + return; - if (uiDirty && UI.TryGetOpenUi(uid, StorageComponent.StorageUiKey.Key, out var storageBui)) - { - storageBui.Refresh(); - // Make sure nesting still updated. - var player = _player.LocalEntity; + var storages = new ValueList>(_openStorages); + var reverseStorages = storages.Reverse(); - if (NestedStorage && player != null && ContainerSystem.TryGetContainingContainer((uid, null, null), out var container) && - UI.TryGetOpenUi(container.Owner, StorageComponent.StorageUiKey.Key, out var containerBui)) - { - containerBui.Hide(); - } - else - { - storageBui.Show(); - } + foreach (var storage in reverseStorages) + { + CloseStorageBoundUserInterface(storage.Owner); + _openStorages.Remove(storage); + if (storage.Owner == entity.Owner) + break; } + + Entity? last = null; + if (_openStorages.Any()) + last = _openStorages.LastOrDefault(); + StorageOrderChanged?.Invoke(last); } - public override void UpdateUI(Entity entity) + private void ClearNonParentStorages(EntityUid uid) { - if (UI.TryGetOpenUi(entity.Owner, StorageComponent.StorageUiKey.Key, out var sBui)) + var storages = new ValueList>(_openStorages); + var reverseStorages = storages.Reverse(); + + foreach (var storage in reverseStorages) { - sBui.Refresh(); + if (storage.Comp.Container.Contains(uid)) + break; + + CloseStorageBoundUserInterface(storage.Owner); + _openStorages.Remove(storage); } } - protected override void HideStorageWindow(EntityUid uid, EntityUid actor) + private void CloseStorageBoundUserInterface(Entity entity) { - if (UI.TryGetOpenUi(uid, StorageComponent.StorageUiKey.Key, out var storageBui)) - { - storageBui.Hide(); - } + if (!Resolve(entity, ref entity.Comp, false)) + return; + + if (entity.Comp.ClientOpenInterfaces.GetValueOrDefault(StorageComponent.StorageUiKey.Key) is not { } bui) + return; + + bui.Close(); } - protected override void ShowStorageWindow(EntityUid uid, EntityUid actor) + private void OnShutdown(Entity ent, ref ComponentShutdown args) { - if (UI.TryGetOpenUi(uid, StorageComponent.StorageUiKey.Key, out var storageBui)) - { - storageBui.Show(); - } + CloseStorageWindow((ent, ent.Comp)); } /// @@ -124,7 +142,7 @@ public void PickupAnimation(EntityUid item, EntityCoordinates initialCoords, Ent { if (!_timing.IsFirstTimePredicted) return; - + if (TransformSystem.InRange(finalCoords, initialCoords, 0.1f) || !Exists(initialCoords.EntityId) || !Exists(finalCoords.EntityId)) { diff --git a/Content.Client/UserInterface/Systems/Hotbar/HotbarUIController.cs b/Content.Client/UserInterface/Systems/Hotbar/HotbarUIController.cs index b89115da86b..2f266cfdd6b 100644 --- a/Content.Client/UserInterface/Systems/Hotbar/HotbarUIController.cs +++ b/Content.Client/UserInterface/Systems/Hotbar/HotbarUIController.cs @@ -31,12 +31,13 @@ private void OnScreenLoad() ReloadHotbar(); } - public void Setup(HandsContainer handsContainer) + public void Setup(HandsContainer handsContainer, StorageContainer storageContainer) { _inventory = UIManager.GetUIController(); _hands = UIManager.GetUIController(); _storage = UIManager.GetUIController(); _hands.RegisterHandContainer(handsContainer); + _storage.RegisterStorageContainer(storageContainer); } public void ReloadHotbar() diff --git a/Content.Client/UserInterface/Systems/Hotbar/Widgets/HotbarGui.xaml b/Content.Client/UserInterface/Systems/Hotbar/Widgets/HotbarGui.xaml index 153e02bd558..00ba1878b48 100644 --- a/Content.Client/UserInterface/Systems/Hotbar/Widgets/HotbarGui.xaml +++ b/Content.Client/UserInterface/Systems/Hotbar/Widgets/HotbarGui.xaml @@ -1,6 +1,7 @@  + (); - hotbarController.Setup(HandContainer); + hotbarController.Setup(HandContainer, StoragePanel); LayoutContainer.SetGrowVertical(this, LayoutContainer.GrowDirection.Begin); } diff --git a/Content.Client/UserInterface/Systems/Storage/Controls/ItemGridPiece.cs b/Content.Client/UserInterface/Systems/Storage/Controls/ItemGridPiece.cs index f4c4158b5ce..dd9986e4c6e 100644 --- a/Content.Client/UserInterface/Systems/Storage/Controls/ItemGridPiece.cs +++ b/Content.Client/UserInterface/Systems/Storage/Controls/ItemGridPiece.cs @@ -59,7 +59,7 @@ public ItemGridPiece(Entity entity, ItemStorageLocation location, Location = location; Visible = true; - MouseFilter = MouseFilterMode.Stop; + MouseFilter = MouseFilterMode.Pass; TooltipSupplier = SupplyTooltip; @@ -105,11 +105,8 @@ protected override void Draw(DrawingHandleScreen handle) return; } - if (_storageController.IsDragging && _storageController.DraggingGhost?.Entity == Entity && - _storageController.DraggingGhost != this) - { + if (_storageController.IsDragging && _storageController.DraggingGhost?.Entity == Entity && _storageController.DraggingGhost != this) return; - } var adjustedShape = _entityManager.System().GetAdjustedItemShape((Entity, itemComponent), Location.Rotation, Vector2i.Zero); var boundingGrid = adjustedShape.GetBoundingBox(); diff --git a/Content.Client/UserInterface/Systems/Storage/Controls/StorageWindow.cs b/Content.Client/UserInterface/Systems/Storage/Controls/StorageContainer.cs similarity index 63% rename from Content.Client/UserInterface/Systems/Storage/Controls/StorageWindow.cs rename to Content.Client/UserInterface/Systems/Storage/Controls/StorageContainer.cs index b4df85024ff..44a2bea142b 100644 --- a/Content.Client/UserInterface/Systems/Storage/Controls/StorageWindow.cs +++ b/Content.Client/UserInterface/Systems/Storage/Controls/StorageContainer.cs @@ -1,11 +1,9 @@ -using System.Diagnostics.CodeAnalysis; +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; @@ -13,14 +11,12 @@ 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 +public sealed class StorageContainer : BaseWindow { [Dependency] private readonly IEntityManager _entity = default!; private readonly StorageUIController _storageController; @@ -31,20 +27,6 @@ public sealed class StorageWindow : BaseWindow 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 _pieces = new(); - private readonly List _controlGrid = new(); - - private ValueList _contained = new(); - private ValueList _toRemove = new(); - - private TextureButton? _backButton; - - private bool _isDirty; - public event Action? OnPiecePressed; public event Action? OnPieceUnpressed; @@ -69,10 +51,9 @@ public sealed class StorageWindow : BaseWindow private readonly string _sidebarFatTexturePath = "Storage/sidebar_fat"; private Texture? _sidebarFatTexture; - public StorageWindow() + public StorageContainer() { IoCManager.InjectDependencies(this); - Resizable = false; _storageController = UserInterfaceManager.GetUIController(); @@ -82,7 +63,6 @@ public StorageWindow() _sidebar = new GridContainer { - Name = "SideBar", HSeparationOverride = 0, VSeparationOverride = 0, Columns = 1 @@ -90,48 +70,21 @@ public StorageWindow() _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, @@ -177,22 +130,12 @@ public void UpdateContainer(Entity? entity) if (entity == null) return; - if (UserInterfaceManager.GetUIController().WindowTitle) - { - _titleLabel.Text = Identity.Name(entity.Value, _entity); - _titleContainer.Visible = true; - } - else - { - _titleContainer.Visible = false; - } - BuildGridRepresentation(); } private void BuildGridRepresentation() { - if (!_entity.TryGetComponent(StorageEntity, out var comp) || comp.Grid.Count == 0) + if (!_entity.TryGetComponent(StorageEntity, out var comp) || !comp.Grid.Any()) return; var boundingGrid = comp.Grid.GetBoundingBox(); @@ -201,13 +144,12 @@ private void BuildGridRepresentation() #region Sidebar _sidebar.Children.Clear(); - var rows = boundingGrid.Height + 1; - _sidebar.Rows = rows; - + _sidebar.Rows = boundingGrid.Height + 1; var exitButton = new TextureButton { - Name = "ExitButton", - TextureNormal = _exitTexture, + TextureNormal = _entity.System().OpenStorageAmount == 1 + ?_exitTexture + : _backTexture, Scale = new Vector2(2, 2), }; exitButton.OnPressed += _ => @@ -223,10 +165,8 @@ private void BuildGridRepresentation() args.Handle(); } }; - var exitContainer = new BoxContainer { - Name = "ExitContainer", Children = { new TextureRect @@ -242,70 +182,28 @@ private void BuildGridRepresentation() } } }; - _sidebar.AddChild(exitContainer); - var offset = 2; - - if (_entity.System().NestedStorage && rows > 0) + for (var i = 0; i < boundingGrid.Height - 1; i++) { - _backButton = new TextureButton - { - TextureNormal = _backTexture, - Scale = new Vector2(2, 2), - }; - _backButton.OnPressed += _ => - { - var containerSystem = _entity.System(); - - if (containerSystem.TryGetContainingContainer(StorageEntity.Value, out var container) && - _entity.TryGetComponent(container.Owner, out StorageComponent? storage)) - { - Close(); - - if (_entity.System() - .TryGetOpenUi(container.Owner, - StorageComponent.StorageUiKey.Key, - out var parentBui)) - { - parentBui.Show(); - } - } - }; - - var backContainer = new BoxContainer + _sidebar.AddChild(new TextureRect { - Name = "ExitContainer", - Children = - { - new TextureRect - { - Texture = rows > 2 ? _sidebarMiddleTexture : _sidebarBottomTexture, - TextureScale = new Vector2(2, 2), - Children = - { - _backButton, - } - } - } - }; - - _sidebar.AddChild(backContainer); + Texture = _sidebarMiddleTexture, + TextureScale = new Vector2(2, 2), + }); } - var fillerRows = rows - offset; - - for (var i = 0; i < fillerRows; i++) + if (boundingGrid.Height > 0) { _sidebar.AddChild(new TextureRect { - Texture = i != (fillerRows - 1) ? _sidebarMiddleTexture : _sidebarBottomTexture, + Texture = _sidebarBottomTexture, TextureScale = new Vector2(2, 2), }); } #endregion - FlagDirty(); + BuildItemPieces(); } public void BuildBackground() @@ -342,136 +240,70 @@ public void BuildBackground() } } - 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(StorageEntity, out var storageComp)) return; - if (storageComp.Grid.Count == 0) + if (!storageComp.Grid.Any()) 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(); + var containedEntities = storageComp.Container.ContainedEntities.Reverse().ToArray(); - for (var y = boundingGrid.Bottom; y <= boundingGrid.Top; y++) - { - for (var x = boundingGrid.Left; x <= boundingGrid.Right; x++) - { - var control = new Control - { - MinSize = size - }; + //todo. at some point, we may want to only rebuild the pieces that have actually received new data. - _controlGrid.Add(control); - _pieceGrid.AddChild(control); - } - } - } - - _toRemove.Clear(); - - // Remove entities no longer relevant / Update existing ones - foreach (var (ent, data) in _pieces) + _pieceGrid.RemoveAllChildren(); + _pieceGrid.Rows = boundingGrid.Height + 1; + _pieceGrid.Columns = boundingGrid.Width + 1; + for (var y = boundingGrid.Bottom; y <= boundingGrid.Top; y++) { - if (storageComp.StoredItems.TryGetValue(ent, out var updated)) + for (var x = boundingGrid.Left; x <= boundingGrid.Right; x++) { - // Begin DeltaV Additions: Fix infinite gold stars - data.Control.Marked = _contained.IndexOf(ent) switch + var control = new Control { - 0 => ItemGridPieceMarks.First, - 1 => ItemGridPieceMarks.Second, - _ => null, + MinSize = size }; - // End DeltaV Additions - if (data.Loc.Equals(updated)) - { - DebugTools.Assert(data.Control.Location == updated); - continue; - } + var currentPosition = new Vector2i(x, y); - // 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 (itemEnt, itemPos) in storageComp.StoredItems) + { + if (itemPos.Position != currentPosition) + continue; - foreach (var ent in _toRemove) - { - _pieces.Remove(ent, out var data); - data.Control.Orphan(); - } + if (_entity.TryGetComponent(itemEnt, out var itemEntComponent)) + { + ItemGridPiece gridPiece; - // Add new ones - foreach (var (ent, loc) in storageComp.StoredItems) - { - if (_pieces.TryGetValue(ent, out var existing)) - { - DebugTools.Assert(existing.Loc == loc); - continue; - } + if (_storageController.CurrentlyDragging?.Entity is { } dragging + && dragging == itemEnt) + { + _storageController.CurrentlyDragging.Orphan(); + gridPiece = _storageController.CurrentlyDragging; + } + else + { + gridPiece = new ItemGridPiece((itemEnt, itemEntComponent), itemPos, _entity) + { + MinSize = size, + Marked = Array.IndexOf(containedEntities, itemEnt) switch + { + 0 => ItemGridPieceMarks.First, + 1 => ItemGridPieceMarks.Second, + _ => null, + } + }; + gridPiece.OnPiecePressed += OnPiecePressed; + gridPiece.OnPieceUnpressed += OnPieceUnpressed; + } - if (_entity.TryGetComponent(ent, out var itemEntComponent)) - { - var gridPiece = new ItemGridPiece((ent, itemEntComponent), loc, _entity) - { - MinSize = size, - Marked = _contained.IndexOf(ent) switch - { - 0 => ItemGridPieceMarks.First, - 1 => ItemGridPieceMarks.Second, - _ => null, + control.AddChild(gridPiece); } - }; - 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); + _pieceGrid.AddChild(control); } } } @@ -483,35 +315,6 @@ protected override void FrameUpdate(FrameEventArgs args) if (!IsOpen) return; - if (_isDirty) - { - _isDirty = false; - BuildItemPieces(); - } - - var containerSystem = _entity.System(); - - if (_backButton != null) - { - if (StorageEntity != null && _entity.System().NestedStorage) - { - if (containerSystem.TryGetContainingContainer(StorageEntity.Value, out var container) && - _entity.HasComponent(container.Owner)) - { - _backButton.Visible = true; - } - else - { - _backButton.Visible = false; - } - } - // Hide the button. - else - { - _backButton.Visible = false; - } - } - var itemSystem = _entity.System(); var storageSystem = _entity.System(); var handsSystem = _entity.System(); @@ -521,7 +324,7 @@ protected override void FrameUpdate(FrameEventArgs args) child.ModulateSelfOverride = Color.FromHex("#222222"); } - if (UserInterfaceManager.CurrentlyHovered is StorageWindow con && con != this) + if (UserInterfaceManager.CurrentlyHovered is StorageContainer con && con != this) return; if (!_entity.TryGetComponent(StorageEntity, out var storageComponent)) @@ -570,7 +373,7 @@ protected override void FrameUpdate(FrameEventArgs args) continue; float spot = 0; - var marked = new ValueList(); + var marked = new List(); foreach (var location in locations.Value) { @@ -697,4 +500,14 @@ protected override void KeyBindDown(GUIBoundKeyEventArgs args) } } } + + public override void Close() + { + base.Close(); + + if (StorageEntity == null) + return; + + _entity.System().CloseStorageWindow(StorageEntity.Value); + } } diff --git a/Content.Client/UserInterface/Systems/Storage/StorageUIController.cs b/Content.Client/UserInterface/Systems/Storage/StorageUIController.cs index cbcf4293e8d..1e61ad98380 100644 --- a/Content.Client/UserInterface/Systems/Storage/StorageUIController.cs +++ b/Content.Client/UserInterface/Systems/Storage/StorageUIController.cs @@ -2,7 +2,6 @@ using Content.Client.Examine; using Content.Client.Hands.Systems; using Content.Client.Interaction; -using Content.Client.Storage; using Content.Client.Storage.Systems; using Content.Client.UserInterface.Systems.Hotbar.Widgets; using Content.Client.UserInterface.Systems.Storage.Controls; @@ -10,9 +9,9 @@ using Content.Shared.CCVar; using Content.Shared.Input; using Content.Shared.Interaction; +using Content.Shared.Item; using Content.Shared.Storage; using Robust.Client.Input; -using Robust.Client.Player; using Robust.Client.UserInterface; using Robust.Client.UserInterface.Controllers; using Robust.Client.UserInterface.Controls; @@ -24,28 +23,19 @@ namespace Content.Client.UserInterface.Systems.Storage; public sealed class StorageUIController : UIController, IOnSystemChanged { - /* - * Things are a bit over the shop but essentially - * - Clicking into storagewindow is handled via storagewindow - * - Clicking out of it is via ItemGridPiece - * - Dragging around is handled here - * - Drawing is handled via ItemGridPiece - * - StorageSystem handles any sim stuff around open windows. - */ - [Dependency] private readonly IConfigurationManager _configuration = default!; + [Dependency] private readonly IEntityManager _entity = default!; [Dependency] private readonly IInputManager _input = default!; - [Dependency] private readonly IPlayerManager _player = default!; - [UISystemDependency] private readonly StorageSystem _storage = default!; - - /// - /// Cached positions for opening nested storage. - /// - private readonly Dictionary _reservedStorage = new(); + [Dependency] private readonly IUserInterfaceManager _ui = default!; private readonly DragDropHelper _menuDragHelper; + private StorageContainer? _container; + + private Vector2? _lastContainerPosition; - public ItemGridPiece? DraggingGhost => _menuDragHelper.Dragged; + private HotbarGui? Hotbar => UIManager.GetActiveUIWidgetOrNull(); + + public ItemGridPiece? DraggingGhost; public Angle DraggingRotation = Angle.Zero; public bool StaticStorageUIEnabled; public bool OpaqueStorageWindow; @@ -53,8 +43,6 @@ public sealed class StorageUIController : UIController, IOnSystemChanged _menuDragHelper.IsDragging; public ItemGridPiece? CurrentlyDragging => _menuDragHelper.Dragged; - public bool WindowTitle { get; private set; } = false; - public StorageUIController() { _menuDragHelper = new DragDropHelper(OnMenuBeginDrag, OnMenuContinueDrag, OnMenuEndDrag); @@ -64,93 +52,106 @@ public override void Initialize() { base.Initialize(); - UIManager.OnScreenChanged += OnScreenChange; - _configuration.OnValueChanged(CCVars.StaticStorageUI, OnStaticStorageChanged, true); _configuration.OnValueChanged(CCVars.OpaqueStorageWindow, OnOpaqueWindowChanged, true); - _configuration.OnValueChanged(CCVars.StorageWindowTitle, OnStorageWindowTitle, true); } - private void OnScreenChange((UIScreen? Old, UIScreen? New) obj) + public void OnSystemLoaded(StorageSystem system) { - // Handle reconnects with hotbargui. - - // Essentially HotbarGui / the screen gets loaded AFTER gamestates at the moment (because clientgameticker manually changes it via event) - // and changing this may be a massive change. - // So instead we'll just manually reload it for now. - if (!StaticStorageUIEnabled || - obj.New == null || - !EntityManager.TryGetComponent(_player.LocalEntity, out UserInterfaceUserComponent? userComp)) - { + _input.FirstChanceOnKeyEvent += OnMiddleMouse; + system.StorageUpdated += OnStorageUpdated; + system.StorageOrderChanged += OnStorageOrderChanged; + } + + public void OnSystemUnloaded(StorageSystem system) + { + _input.FirstChanceOnKeyEvent -= OnMiddleMouse; + system.StorageUpdated -= OnStorageUpdated; + system.StorageOrderChanged -= OnStorageOrderChanged; + } + + private void OnStorageOrderChanged(Entity? nullEnt) + { + if (_container == null) return; - } - // UISystemDependency not injected at this point so do it the old fashion way, I love ordering issues. - var uiSystem = EntityManager.System(); + if (IsDragging) + _menuDragHelper.EndDrag(); + + _container.UpdateContainer(nullEnt); - foreach (var bui in uiSystem.GetActorUis((_player.LocalEntity.Value, userComp))) + if (nullEnt is not null) { - if (!uiSystem.TryGetOpenUi(bui.Entity, StorageComponent.StorageUiKey.Key, out var storageBui)) - continue; + // center it if we knock it off screen somehow. + if (!StaticStorageUIEnabled && + (_lastContainerPosition == null || + _lastContainerPosition.Value.X < 0 || + _lastContainerPosition.Value.Y < 0 || + _lastContainerPosition.Value.X > _ui.WindowRoot.Width || + _lastContainerPosition.Value.Y > _ui.WindowRoot.Height)) + { + _container.OpenCenteredAt(new Vector2(0.5f, 0.75f)); + } + else + { + _container.Open(); - storageBui.ReOpen(); - } - } + var pos = !StaticStorageUIEnabled && _lastContainerPosition != null + ? _lastContainerPosition.Value + : Vector2.Zero; - private void OnStorageWindowTitle(bool obj) - { - WindowTitle = obj; - } + LayoutContainer.SetPosition(_container, pos); + } - private void OnOpaqueWindowChanged(bool obj) - { - OpaqueStorageWindow = obj; + if (StaticStorageUIEnabled) + { + // we have to orphan it here because Open() sets the parent. + _container.Orphan(); + Hotbar?.StorageContainer.AddChild(_container); + } + _lastContainerPosition = _container.GlobalPosition; + } + else + { + _lastContainerPosition = _container.GlobalPosition; + _container.Close(); + } } private void OnStaticStorageChanged(bool obj) { + if (StaticStorageUIEnabled == obj) + return; + StaticStorageUIEnabled = obj; - } + _lastContainerPosition = null; - public StorageWindow CreateStorageWindow(EntityUid uid) - { - var window = new StorageWindow(); - window.MouseFilter = Control.MouseFilterMode.Pass; + if (_container == null) + return; - window.OnPiecePressed += (args, piece) => - { - OnPiecePressed(args, window, piece); - }; - window.OnPieceUnpressed += (args, piece) => - { - OnPieceUnpressed(args, window, piece); - }; + if (!_container.IsOpen) + return; + _container.Orphan(); if (StaticStorageUIEnabled) { - UIManager.GetActiveUIWidgetOrNull()?.StorageContainer.AddChild(window); + Hotbar?.StorageContainer.AddChild(_container); } else { - window.OpenCenteredLeft(); - - if (_reservedStorage.Remove(uid, out var pos)) - { - LayoutContainer.SetPosition(window, pos); - } + _ui.WindowRoot.AddChild(_container); } - return window; - } - - public void OnSystemLoaded(StorageSystem system) - { - _input.FirstChanceOnKeyEvent += OnMiddleMouse; + if (_entity.TryGetComponent(_container.StorageEntity, out var comp)) + OnStorageOrderChanged((_container.StorageEntity.Value, comp)); } - public void OnSystemUnloaded(StorageSystem system) + private void OnOpaqueWindowChanged(bool obj) { - _input.FirstChanceOnKeyEvent -= OnMiddleMouse; + if (OpaqueStorageWindow == obj) + return; + OpaqueStorageWindow = obj; + _container?.BuildBackground(); } /// One might ask, Hey Emo, why are you parsing raw keyboard input just to rotate a rectangle? @@ -189,7 +190,7 @@ private void OnMiddleMouse(KeyEventArgs keyEvent, KeyEventType type) binding.Mod3 == Keyboard.Key.Control)) return; - if (!IsDragging && EntityManager.System().GetActiveHandEntity() == null) + if (!IsDragging && _entity.System().GetActiveHandEntity() == null) return; //clamp it to a cardinal. @@ -197,18 +198,43 @@ private void OnMiddleMouse(KeyEventArgs keyEvent, KeyEventType type) if (DraggingGhost != null) DraggingGhost.Location.Rotation = DraggingRotation; - if (IsDragging || UIManager.CurrentlyHovered is StorageWindow) + if (IsDragging || (_container != null && UIManager.CurrentlyHovered == _container)) keyEvent.Handle(); } - private void OnPiecePressed(GUIBoundKeyEventArgs args, StorageWindow window, ItemGridPiece control) + private void OnStorageUpdated(Entity uid) { - if (IsDragging || !window.IsOpen) + if (_container?.StorageEntity != uid) + return; + + _container.BuildItemPieces(); + } + + public void RegisterStorageContainer(StorageContainer container) + { + if (_container != null) + { + container.OnPiecePressed -= OnPiecePressed; + container.OnPieceUnpressed -= OnPieceUnpressed; + } + + _container = container; + container.OnPiecePressed += OnPiecePressed; + container.OnPieceUnpressed += OnPieceUnpressed; + + if (!StaticStorageUIEnabled) + _container.Orphan(); + } + + private void OnPiecePressed(GUIBoundKeyEventArgs args, ItemGridPiece control) + { + if (IsDragging || !_container?.IsOpen == true) return; if (args.Function == ContentKeyFunctions.MoveStoredItem) { DraggingRotation = control.Location.Rotation; + _menuDragHelper.MouseDown(control); _menuDragHelper.Update(0f); @@ -216,17 +242,17 @@ private void OnPiecePressed(GUIBoundKeyEventArgs args, StorageWindow window, Ite } else if (args.Function == ContentKeyFunctions.SaveItemLocation) { - if (window.StorageEntity is not {} storage) + if (_container?.StorageEntity is not {} storage) return; - EntityManager.RaisePredictiveEvent(new StorageSaveItemLocationEvent( - EntityManager.GetNetEntity(control.Entity), - EntityManager.GetNetEntity(storage))); + _entity.RaisePredictiveEvent(new StorageSaveItemLocationEvent( + _entity.GetNetEntity(control.Entity), + _entity.GetNetEntity(storage))); args.Handle(); } else if (args.Function == ContentKeyFunctions.ExamineEntity) { - EntityManager.System().DoExamine(control.Entity); + _entity.System().DoExamine(control.Entity); args.Handle(); } else if (args.Function == EngineKeyFunctions.UseSecondary) @@ -236,102 +262,62 @@ private void OnPiecePressed(GUIBoundKeyEventArgs args, StorageWindow window, Ite } else if (args.Function == ContentKeyFunctions.ActivateItemInWorld) { - EntityManager.RaisePredictiveEvent( - new InteractInventorySlotEvent(EntityManager.GetNetEntity(control.Entity), altInteract: false)); + _entity.RaisePredictiveEvent( + new InteractInventorySlotEvent(_entity.GetNetEntity(control.Entity), altInteract: false)); args.Handle(); } else if (args.Function == ContentKeyFunctions.AltActivateItemInWorld) { - EntityManager.RaisePredictiveEvent(new InteractInventorySlotEvent(EntityManager.GetNetEntity(control.Entity), altInteract: true)); + _entity.RaisePredictiveEvent(new InteractInventorySlotEvent(_entity.GetNetEntity(control.Entity), altInteract: true)); args.Handle(); } - - window.FlagDirty(); } - private void OnPieceUnpressed(GUIBoundKeyEventArgs args, StorageWindow window, ItemGridPiece control) + private void OnPieceUnpressed(GUIBoundKeyEventArgs args, ItemGridPiece control) { if (args.Function != ContentKeyFunctions.MoveStoredItem) return; - // Want to get the control under the dragged control. - // This means we can drag the original control around (and not hide the original). - control.MouseFilter = Control.MouseFilterMode.Ignore; - var targetControl = UIManager.MouseGetControl(args.PointerLocation); - var targetStorage = targetControl as StorageWindow; - control.MouseFilter = Control.MouseFilterMode.Pass; - - var localPlayer = _player.LocalEntity; - window.RemoveGrid(control); - window.FlagDirty(); - - // If we tried to drag it on top of another grid piece then cancel out. - if (targetControl is ItemGridPiece || window.StorageEntity is not { } sourceStorage || localPlayer == null) - { - window.Reclaim(control.Location, control); - args.Handle(); - _menuDragHelper.EndDrag(); + if (_container?.StorageEntity is not { } storageEnt|| !_entity.TryGetComponent(storageEnt, out var storageComp)) return; - } - if (_menuDragHelper.IsDragging && DraggingGhost is { } draggingGhost) + if (DraggingGhost is { } draggingGhost) { var dragEnt = draggingGhost.Entity; var dragLoc = draggingGhost.Location; - - // Dragging in the same storage - // The existing ItemGridPiece just stops rendering but still exists so check if it's hovered. - if (targetStorage == window) - { - var position = targetStorage.GetMouseGridPieceLocation(dragEnt, dragLoc); - var newLocation = new ItemStorageLocation(DraggingRotation, position); - - EntityManager.RaisePredictiveEvent(new StorageSetItemLocationEvent( - EntityManager.GetNetEntity(draggingGhost.Entity), - EntityManager.GetNetEntity(sourceStorage), - newLocation)); - - window.Reclaim(newLocation, control); - } - // Dragging to new storage - else if (targetStorage?.StorageEntity != null && targetStorage != window) + var itemSys = _entity.System(); + + var position = _container.GetMouseGridPieceLocation(dragEnt, dragLoc); + var itemBounding = itemSys.GetAdjustedItemShape(dragEnt, dragLoc).GetBoundingBox(); + var gridBounding = storageComp.Grid.GetBoundingBox(); + + // The extended bounding box for if this is out of the window is the grid bounding box dimensions combined + // with the item shape bounding box dimensions. Plus 1 on the left for the sidebar. This makes it so that. + // dropping an item on the floor requires dragging it all the way out of the window. + var left = gridBounding.Left - itemBounding.Width - 1; + var bottom = gridBounding.Bottom - itemBounding.Height; + var top = gridBounding.Top; + var right = gridBounding.Right; + var lenientBounding = new Box2i(left, bottom, right, top); + + if (lenientBounding.Contains(position)) { - var position = targetStorage.GetMouseGridPieceLocation(dragEnt, dragLoc); - var newLocation = new ItemStorageLocation(DraggingRotation, position); - - // Check it fits and we can move to hand (no free transfers). - if (_storage.ItemFitsInGridLocation( - (dragEnt, null), - (targetStorage.StorageEntity.Value, null), - newLocation)) - { - // Can drop and move. - EntityManager.RaisePredictiveEvent(new StorageTransferItemEvent( - EntityManager.GetNetEntity(dragEnt), - EntityManager.GetNetEntity(targetStorage.StorageEntity.Value), - newLocation)); - - targetStorage.Reclaim(newLocation, control); - DraggingRotation = Angle.Zero; - } - else - { - // Cancel it (rather than dropping). - window.Reclaim(dragLoc, control); - } + _entity.RaisePredictiveEvent(new StorageSetItemLocationEvent( + _entity.GetNetEntity(draggingGhost.Entity), + _entity.GetNetEntity(storageEnt), + new ItemStorageLocation(DraggingRotation, position))); } - targetStorage?.FlagDirty(); + _menuDragHelper.EndDrag(); + _container?.BuildItemPieces(); } - // If we just clicked, then take it out of the bag. - else + else //if we just clicked, then take it out of the bag. { - EntityManager.RaisePredictiveEvent(new StorageInteractWithItemEvent( - EntityManager.GetNetEntity(control.Entity), - EntityManager.GetNetEntity(sourceStorage))); + _menuDragHelper.EndDrag(); + _entity.RaisePredictiveEvent(new StorageInteractWithItemEvent( + _entity.GetNetEntity(control.Entity), + _entity.GetNetEntity(storageEnt))); } - - _menuDragHelper.EndDrag(); args.Handle(); } @@ -340,8 +326,14 @@ private bool OnMenuBeginDrag() if (_menuDragHelper.Dragged is not { } dragged) return false; - DraggingGhost!.Orphan(); DraggingRotation = dragged.Location.Rotation; + DraggingGhost = new ItemGridPiece( + (dragged.Entity, _entity.GetComponent(dragged.Entity)), + dragged.Location, + _entity); + DraggingGhost.MouseFilter = Control.MouseFilterMode.Ignore; + DraggingGhost.Visible = true; + DraggingGhost.Orphan(); UIManager.PopupRoot.AddChild(DraggingGhost); SetDraggingRotation(); @@ -352,7 +344,6 @@ private bool OnMenuContinueDrag(float frameTime) { if (DraggingGhost == null) return false; - SetDraggingRotation(); return true; } @@ -365,7 +356,7 @@ private void SetDraggingRotation() var offset = ItemGridPiece.GetCenterOffset( (DraggingGhost.Entity, null), new ItemStorageLocation(DraggingRotation, Vector2i.Zero), - EntityManager); + _entity); // I don't know why it divides the position by 2. Hope this helps! -emo LayoutContainer.SetPosition(DraggingGhost, UIManager.MousePositionScaled.Position / 2 - offset ); @@ -375,13 +366,18 @@ private void OnMenuEndDrag() { if (DraggingGhost == null) return; - + DraggingGhost.Visible = false; + DraggingGhost = null; DraggingRotation = Angle.Zero; } public override void FrameUpdate(FrameEventArgs args) { base.FrameUpdate(args); + _menuDragHelper.Update(args.DeltaSeconds); + + if (!StaticStorageUIEnabled && _container?.Parent != null && _lastContainerPosition != null) + _lastContainerPosition = _container.GlobalPosition; } } diff --git a/Content.Shared/CCVar/CCVars.Interactions.cs b/Content.Shared/CCVar/CCVars.Interactions.cs index fcefa73a96a..c62f81be0ca 100644 --- a/Content.Shared/CCVar/CCVars.Interactions.cs +++ b/Content.Shared/CCVar/CCVars.Interactions.cs @@ -51,23 +51,4 @@ public sealed partial class CCVars /// public static readonly CVarDef OpaqueStorageWindow = CVarDef.Create("control.opaque_storage_background", false, CVar.CLIENTONLY | CVar.ARCHIVE); - - /// - /// Whether or not the storage window has a title of the entity name. - /// - public static readonly CVarDef StorageWindowTitle = - CVarDef.Create("control.storage_window_title", false, CVar.CLIENTONLY | CVar.ARCHIVE); - - /// - /// How many storage windows are allowed to be open at once. - /// Recommended that you utilise this in conjunction with - /// - public static readonly CVarDef StorageLimit = - CVarDef.Create("control.storage_limit", 1, CVar.REPLICATED | CVar.SERVER); - - /// - /// Whether or not storage can be opened recursively. - /// - public static readonly CVarDef NestedStorage = - CVarDef.Create("control.nested_storage", true, CVar.REPLICATED | CVar.SERVER); } diff --git a/Content.Shared/Storage/EntitySystems/SharedStorageSystem.cs b/Content.Shared/Storage/EntitySystems/SharedStorageSystem.cs index a8548f35571..bae12df5464 100644 --- a/Content.Shared/Storage/EntitySystems/SharedStorageSystem.cs +++ b/Content.Shared/Storage/EntitySystems/SharedStorageSystem.cs @@ -3,7 +3,6 @@ using System.Linq; using Content.Shared.ActionBlocker; using Content.Shared.Administration.Logs; -using Content.Shared.CCVar; using Content.Shared.Containers.ItemSlots; using Content.Shared.Database; using Content.Shared.Destructible; @@ -29,7 +28,6 @@ using Content.Shared.Whitelist; using Robust.Shared.Audio; using Robust.Shared.Audio.Systems; -using Robust.Shared.Configuration; using Robust.Shared.Containers; using Robust.Shared.GameStates; using Robust.Shared.Input.Binding; @@ -38,46 +36,36 @@ using Robust.Shared.Prototypes; using Robust.Shared.Random; using Robust.Shared.Serialization; -using Robust.Shared.Timing; using Robust.Shared.Utility; namespace Content.Shared.Storage.EntitySystems; public abstract class SharedStorageSystem : EntitySystem { - [Dependency] private readonly IConfigurationManager _cfg = default!; - [Dependency] protected readonly IGameTiming Timing = default!; - [Dependency] private readonly IPrototypeManager _prototype = default!; + [Dependency] private readonly IPrototypeManager _prototype = default!; [Dependency] protected readonly IRobustRandom Random = default!; - [Dependency] private readonly ISharedAdminLogManager _adminLog = default!; - [Dependency] protected readonly ActionBlockerSystem ActionBlocker = default!; - [Dependency] private readonly EntityLookupSystem _entityLookupSystem = default!; - [Dependency] private readonly EntityWhitelistSystem _whitelistSystem = default!; - [Dependency] private readonly InventorySystem _inventory = default!; - [Dependency] private readonly SharedAppearanceSystem _appearance = default!; + [Dependency] private readonly EntityLookupSystem _entityLookupSystem = default!; + [Dependency] private readonly SharedAppearanceSystem _appearance = default!; [Dependency] protected readonly SharedAudioSystem Audio = default!; - [Dependency] protected readonly SharedContainerSystem ContainerSystem = default!; - [Dependency] private readonly SharedDoAfterSystem _doAfterSystem = default!; + [Dependency] private readonly SharedContainerSystem _containerSystem = default!; + [Dependency] private readonly SharedDoAfterSystem _doAfterSystem = default!; [Dependency] protected readonly SharedEntityStorageSystem EntityStorage = default!; - [Dependency] private readonly SharedInteractionSystem _interactionSystem = default!; + [Dependency] private readonly SharedInteractionSystem _interactionSystem = default!; + [Dependency] private readonly InventorySystem _inventory = default!; [Dependency] protected readonly SharedItemSystem ItemSystem = default!; - [Dependency] private readonly SharedPopupSystem _popupSystem = default!; - [Dependency] private readonly SharedHandsSystem _sharedHandsSystem = default!; - [Dependency] private readonly SharedStackSystem _stack = default!; + [Dependency] private readonly SharedPopupSystem _popupSystem = default!; + [Dependency] private readonly SharedHandsSystem _sharedHandsSystem = default!; + [Dependency] private readonly SharedStackSystem _stack = default!; [Dependency] protected readonly SharedTransformSystem TransformSystem = default!; - [Dependency] protected readonly SharedUserInterfaceSystem UI = default!; + [Dependency] private readonly SharedUserInterfaceSystem _ui = default!; [Dependency] protected readonly UseDelaySystem UseDelay = default!; + [Dependency] private readonly EntityWhitelistSystem _whitelistSystem = default!; + [Dependency] private readonly ISharedAdminLogManager _adminLog = default!; private EntityQuery _itemQuery; private EntityQuery _stackQuery; private EntityQuery _xformQuery; - private EntityQuery _userQuery; - - /// - /// Whether we're allowed to go up-down storage via UI. - /// - public bool NestedStorage = true; [ValidatePrototypeId] public const string DefaultStorageMaxItemSize = "Normal"; @@ -89,15 +77,10 @@ public abstract class SharedStorageSystem : EntitySystem private ItemSizePrototype _defaultStorageMaxItemSize = default!; - /// - /// Flag for whether we're checking for nested storage interactions. - /// - private bool _nestedCheck; - public bool CheckingCanInsert; - private readonly List _entList = new(); - private readonly HashSet _entSet = new(); + private List _entList = new(); + private HashSet _entSet = new(); private readonly List _sortedSizes = new(); private FrozenDictionary _nextSmallest = FrozenDictionary.Empty; @@ -105,11 +88,6 @@ public abstract class SharedStorageSystem : EntitySystem private const string QuickInsertUseDelayID = "quickInsert"; private const string OpenUiUseDelayID = "storage"; - /// - /// How many storage windows are allowed to be open at once. - /// - private int _openStorageLimit = -1; - protected readonly List CantFillReasons = []; /// @@ -120,11 +98,8 @@ public override void Initialize() _itemQuery = GetEntityQuery(); _stackQuery = GetEntityQuery(); _xformQuery = GetEntityQuery(); - _userQuery = GetEntityQuery(); _prototype.PrototypesReloaded += OnPrototypesReloaded; - Subs.CVar(_cfg, CCVars.StorageLimit, OnStorageLimitChanged, true); - Subs.BuiEvents(StorageComponent.StorageUiKey.Key, subs => { subs.Event(OnBoundUIClosed); @@ -134,6 +109,7 @@ public override void Initialize() SubscribeLocalEvent(OnMapInit); SubscribeLocalEvent>(AddUiVerb); SubscribeLocalEvent(OnStorageGetState); + SubscribeLocalEvent(OnStorageHandleState); SubscribeLocalEvent(OnComponentInit, before: new[] { typeof(SharedContainerSystem) }); SubscribeLocalEvent>(AddTransferVerbs); SubscribeLocalEvent(OnInteractUsing, after: new[] { typeof(ItemSlotsSystem) }); @@ -141,7 +117,6 @@ public override void Initialize() SubscribeLocalEvent(OnImplantActivate); SubscribeLocalEvent(AfterInteract); SubscribeLocalEvent(OnDestroy); - SubscribeLocalEvent(OnBoundUIAttempt); SubscribeLocalEvent(OnBoundUIOpen); SubscribeLocalEvent(OnLockToggled); SubscribeLocalEvent(OnStackCountChanged); @@ -152,8 +127,6 @@ public override void Initialize() SubscribeLocalEvent(OnDoAfter); - SubscribeAllEvent(OnStorageNested); - SubscribeAllEvent(OnStorageTransfer); SubscribeAllEvent(OnInteractWithItem); SubscribeAllEvent(OnSetItemLocation); SubscribeAllEvent(OnInsertItemIntoLocation); @@ -166,24 +139,12 @@ public override void Initialize() .Bind(ContentKeyFunctions.OpenBelt, InputCmdHandler.FromDelegate(HandleOpenBelt, handle: false)) .Register(); - Subs.CVar(_cfg, CCVars.NestedStorage, OnNestedStorageCvar, true); - UpdatePrototypeCache(); } - private void OnNestedStorageCvar(bool obj) - { - NestedStorage = obj; - } - - private void OnStorageLimitChanged(int obj) - { - _openStorageLimit = obj; - } - private void OnRemove(Entity entity, ref ComponentRemove args) { - UI.CloseUi(entity.Owner, StorageComponent.StorageUiKey.Key); + _ui.CloseUi(entity.Owner, StorageComponent.StorageUiKey.Key); } private void OnMapInit(Entity entity, ref MapInitEvent args) @@ -212,6 +173,28 @@ private void OnStorageGetState(EntityUid uid, StorageComponent component, ref Co }; } + private void OnStorageHandleState(EntityUid uid, StorageComponent component, ref ComponentHandleState args) + { + if (args.Current is not StorageComponentState state) + return; + + component.Grid.Clear(); + component.Grid.AddRange(state.Grid); + component.MaxItemSize = state.MaxItemSize; + component.Whitelist = state.Whitelist; + component.Blacklist = state.Blacklist; + + component.StoredItems.Clear(); + + foreach (var (nent, location) in state.StoredItems) + { + var ent = EnsureEntity(nent, uid); + component.StoredItems[ent] = location; + } + + component.SavedLocations = state.SavedLocations; + } + public override void Shutdown() { _prototype.PrototypesReloaded -= OnPrototypesReloaded; @@ -246,7 +229,7 @@ private void UpdatePrototypeCache() private void OnComponentInit(EntityUid uid, StorageComponent storageComp, ComponentInit args) { - storageComp.Container = ContainerSystem.EnsureContainer(uid, StorageComponent.ContainerId); + storageComp.Container = _containerSystem.EnsureContainer(uid, StorageComponent.ContainerId); UpdateAppearance((uid, storageComp, null)); } @@ -265,7 +248,7 @@ private void CloseNestedInterfaces(EntityUid uid, EntityUid actor, StorageCompon // close ui foreach (var entity in storageComp.Container.ContainedEntities) { - UI.CloseUis(entity, actor); + _ui.CloseUis(entity, actor); } } @@ -274,7 +257,7 @@ private void OnBoundUIClosed(EntityUid uid, StorageComponent storageComp, BoundU CloseNestedInterfaces(uid, args.Actor, storageComp); // If UI is closed for everyone - if (!UI.IsUiOpen(uid, args.UiKey)) + if (!_ui.IsUiOpen(uid, args.UiKey)) { UpdateAppearance((uid, storageComp, null)); Audio.PlayPredicted(storageComp.StorageCloseSound, uid, args.Actor); @@ -287,7 +270,7 @@ private void AddUiVerb(EntityUid uid, StorageComponent component, GetVerbsEvent< return; // Does this player currently have the storage UI open? - var uiOpen = UI.IsUiOpen(uid, StorageComponent.StorageUiKey.Key, args.User); + var uiOpen = _ui.IsUiOpen(uid, StorageComponent.StorageUiKey.Key, args.User); ActivationVerb verb = new() { @@ -295,7 +278,7 @@ private void AddUiVerb(EntityUid uid, StorageComponent component, GetVerbsEvent< { if (uiOpen) { - UI.CloseUi(uid, StorageComponent.StorageUiKey.Key, args.User); + _ui.CloseUi(uid, StorageComponent.StorageUiKey.Key, args.User); } else { @@ -333,16 +316,16 @@ public void OpenStorageUI(EntityUid uid, EntityUid entity, StorageComponent? sto if (!CanInteract(entity, (uid, storageComp), silent: silent)) return; - if (!UI.TryOpenUi(uid, StorageComponent.StorageUiKey.Key, entity)) - return; - if (!silent) { - Audio.PlayPredicted(storageComp.StorageOpenSound, uid, entity); + if (!_ui.IsUiOpen(uid, StorageComponent.StorageUiKey.Key)) + Audio.PlayPredicted(storageComp.StorageOpenSound, uid, entity); if (useDelay != null) UseDelay.TryResetDelay((uid, useDelay), id: OpenUiUseDelayID); } + + _ui.OpenUi(uid, StorageComponent.StorageUiKey.Key, entity); } public virtual void UpdateUI(Entity entity) {} @@ -402,43 +385,18 @@ private void OnActivate(EntityUid uid, StorageComponent storageComp, ActivateInW return; // Toggle - if (UI.IsUiOpen(uid, StorageComponent.StorageUiKey.Key, args.User)) + if (_ui.IsUiOpen(uid, StorageComponent.StorageUiKey.Key, args.User)) { - UI.CloseUi(uid, StorageComponent.StorageUiKey.Key, args.User); + _ui.CloseUi(uid, StorageComponent.StorageUiKey.Key, args.User); } else { - // Handle recursively opening nested storages. - if (ContainerSystem.TryGetContainingContainer((args.Target, null, null), out var container) && - UI.IsUiOpen(container.Owner, StorageComponent.StorageUiKey.Key, args.User)) - { - _nestedCheck = true; - HideStorageWindow(container.Owner, args.User); - OpenStorageUI(uid, args.User, storageComp, silent: true); - _nestedCheck = false; - } - else - { - // If you need something more sophisticated for multi-UI you'll need to code some smarter - // interactions. - if (_openStorageLimit == 1) - UI.CloseUserUis(args.User); - - OpenStorageUI(uid, args.User, storageComp, silent: false); - } + OpenStorageUI(uid, args.User, storageComp, false); } args.Handled = true; } - protected virtual void HideStorageWindow(EntityUid uid, EntityUid actor) - { - } - - protected virtual void ShowStorageWindow(EntityUid uid, EntityUid actor) - { - } - /// /// Specifically for storage implants. /// @@ -447,10 +405,10 @@ private void OnImplantActivate(EntityUid uid, StorageComponent storageComp, Open if (args.Handled) return; - var uiOpen = UI.IsUiOpen(uid, StorageComponent.StorageUiKey.Key, args.Performer); + var uiOpen = _ui.IsUiOpen(uid, StorageComponent.StorageUiKey.Key, args.Performer); if (uiOpen) - UI.CloseUi(uid, StorageComponent.StorageUiKey.Key, args.Performer); + _ui.CloseUi(uid, StorageComponent.StorageUiKey.Key, args.Performer); else OpenStorageUI(uid, args.Performer, storageComp, false); @@ -517,7 +475,7 @@ private void AfterInteract(EntityUid uid, StorageComponent storageComp, AfterInt if (args.Target is not { Valid: true } target) return; - if (ContainerSystem.IsEntityInContainer(target) + if (_containerSystem.IsEntityInContainer(target) || target == args.User || !_itemQuery.HasComponent(target)) { @@ -568,7 +526,7 @@ private void OnDoAfter(EntityUid uid, StorageComponent component, AreaPickupDoAf var entity = GetEntity(args.Entities[i]); // Check again, situation may have changed for some entities, but we'll still pick up any that are valid - if (ContainerSystem.IsEntityInContainer(entity) + if (_containerSystem.IsEntityInContainer(entity) || entity == args.Args.User || !_itemQuery.HasComponent(entity)) { @@ -613,7 +571,7 @@ private void OnDoAfter(EntityUid uid, StorageComponent component, AreaPickupDoAf private void OnReclaimed(EntityUid uid, StorageComponent storageComp, GotReclaimedEvent args) { - ContainerSystem.EmptyContainer(storageComp.Container, destination: args.ReclaimerCoordinates); + _containerSystem.EmptyContainer(storageComp.Container, destination: args.ReclaimerCoordinates); } private void OnDestroy(EntityUid uid, StorageComponent storageComp, DestructionEventArgs args) @@ -621,7 +579,7 @@ private void OnDestroy(EntityUid uid, StorageComponent storageComp, DestructionE var coordinates = TransformSystem.GetMoverCoordinates(uid); // Being destroyed so need to recalculate. - ContainerSystem.EmptyContainer(storageComp.Container, destination: coordinates); + _containerSystem.EmptyContainer(storageComp.Container, destination: coordinates); } /// @@ -681,54 +639,6 @@ private void OnSetItemLocation(StorageSetItemLocationEvent msg, EntitySessionEve TrySetItemStorageLocation(item!, storage!, msg.Location); } - private void OnStorageNested(OpenNestedStorageEvent msg, EntitySessionEventArgs args) - { - if (!NestedStorage) - return; - - if (!TryGetEntity(msg.InteractedItemUid, out var itemEnt)) - return; - - _nestedCheck = true; - - var result = ValidateInput(args, - msg.StorageUid, - msg.InteractedItemUid, - out var player, - out var storage, - out var item); - - if (!result) - { - _nestedCheck = false; - return; - } - - HideStorageWindow(storage.Owner, player.Owner); - OpenStorageUI(item.Owner, player.Owner, silent: true); - _nestedCheck = false; - } - - private void OnStorageTransfer(StorageTransferItemEvent msg, EntitySessionEventArgs args) - { - if (!TryGetEntity(msg.ItemEnt, out var itemEnt)) - return; - - var localPlayer = args.SenderSession.AttachedEntity; - - if (!TryComp(localPlayer, out HandsComponent? handsComp) || !_sharedHandsSystem.TryPickup(localPlayer.Value, itemEnt.Value, handsComp: handsComp, animate: false)) - return; - - if (!ValidateInput(args, msg.StorageEnt, msg.ItemEnt, out var player, out var storage, out var item, held: true)) - return; - - _adminLog.Add( - LogType.Storage, - LogImpact.Low, - $"{ToPrettyString(player):player} is inserting {ToPrettyString(item):item} into {ToPrettyString(storage):storage}"); - InsertAt(storage!, item!, msg.Location, out _, player, stackAutomatically: false); - } - private void OnInsertItemIntoLocation(StorageInsertItemIntoLocationEvent msg, EntitySessionEventArgs args) { if (!ValidateInput(args, msg.StorageEnt, msg.ItemEnt, out var player, out var storage, out var item, held: true)) @@ -749,46 +659,9 @@ private void OnSaveItemLocation(StorageSaveItemLocationEvent msg, EntitySessionE SaveItemLocation(storage!, item.Owner); } - private void OnBoundUIOpen(Entity ent, ref BoundUIOpenedEvent args) - { - UpdateAppearance((ent.Owner, ent.Comp, null)); - } - - private void OnBoundUIAttempt(BoundUserInterfaceMessageAttempt args) + private void OnBoundUIOpen(EntityUid uid, StorageComponent storageComp, BoundUIOpenedEvent args) { - if (args.UiKey is not StorageComponent.StorageUiKey.Key || - _openStorageLimit == -1 || - _nestedCheck || - args.Message is not OpenBoundInterfaceMessage) - return; - - var uid = args.Target; - var actor = args.Actor; - var count = 0; - - if (_userQuery.TryComp(actor, out var userComp)) - { - foreach (var (ui, keys) in userComp.OpenInterfaces) - { - if (ui == uid) - continue; - - foreach (var key in keys) - { - if (key is not StorageComponent.StorageUiKey) - continue; - - count++; - - if (count >= _openStorageLimit) - { - args.Cancel(); - } - - break; - } - } - } + UpdateAppearance((uid, storageComp, null)); } private void OnEntInserted(Entity entity, ref EntInsertedIntoContainerMessage args) @@ -804,7 +677,7 @@ private void OnEntInserted(Entity entity, ref EntInsertedIntoC { if (!TryGetAvailableGridSpace((entity.Owner, entity.Comp), (args.Entity, null), out var location)) { - ContainerSystem.Remove(args.Entity, args.Container, force: true); + _containerSystem.Remove(args.Entity, args.Container, force: true); return; } @@ -866,7 +739,7 @@ public void UpdateAppearance(Entity ent var capacity = storage.Grid.GetArea(); var used = GetCumulativeItemAreas((uid, storage)); - var isOpen = UI.IsUiOpen(entity.Owner, StorageComponent.StorageUiKey.Key); + var isOpen = _ui.IsUiOpen(entity.Owner, StorageComponent.StorageUiKey.Key); _appearance.SetData(uid, StorageVisuals.StorageUsed, used, appearance); _appearance.SetData(uid, StorageVisuals.Capacity, capacity, appearance); @@ -979,7 +852,7 @@ public bool CanInsert( } CheckingCanInsert = true; - if (!ContainerSystem.CanInsert(insertEnt, storageComp.Container)) + if (!_containerSystem.CanInsert(insertEnt, storageComp.Container)) { CheckingCanInsert = false; reason = null; @@ -1080,7 +953,7 @@ public bool Insert( if (!stackAutomatically || !_stackQuery.TryGetComponent(insertEnt, out var insertStack)) { - if (!ContainerSystem.Insert(insertEnt, storageComp.Container)) + if (!_containerSystem.Insert(insertEnt, storageComp.Container)) return false; if (playSound) @@ -1106,7 +979,7 @@ public bool Insert( // Still stackable remaining if (insertStack.Count > 0 - && !ContainerSystem.Insert(insertEnt, storageComp.Container) + && !_containerSystem.Insert(insertEnt, storageComp.Container) && toInsertCount == insertStack.Count) { // Failed to insert anything. @@ -1185,7 +1058,6 @@ public bool TrySetItemStorageLocation(Entity itemEnt, Entity - /// Target storage to receive the transfer. - /// - public readonly NetEntity StorageEnt; - - public readonly ItemStorageLocation Location; - - public StorageTransferItemEvent(NetEntity itemEnt, NetEntity storageEnt, ItemStorageLocation location) - { - ItemEnt = itemEnt; - StorageEnt = storageEnt; - Location = location; - } - } - [Serializable, NetSerializable] public sealed class StorageInsertItemIntoLocationEvent : EntityEventArgs { diff --git a/Resources/ConfigPresets/Build/development.toml b/Resources/ConfigPresets/Build/development.toml index ac121b5e783..96345f58cf9 100644 --- a/Resources/ConfigPresets/Build/development.toml +++ b/Resources/ConfigPresets/Build/development.toml @@ -1,4 +1,4 @@ -[game] +[game] # Straight in-game baby lobbyenabled = false # Dev map for faster loading & convenience @@ -37,6 +37,3 @@ see_own_notes = true [server] # DeltaV rules_file = "DeltaVRuleset" - -[control] # DeltaV -storage_limit = 2 diff --git a/Resources/ConfigPresets/DeltaV/deltav.toml b/Resources/ConfigPresets/DeltaV/deltav.toml index 1fe5c489368..738cfab5439 100644 --- a/Resources/ConfigPresets/DeltaV/deltav.toml +++ b/Resources/ConfigPresets/DeltaV/deltav.toml @@ -89,6 +89,3 @@ easy_mode = false # reclaimer can work on soul-ful bodies, mrp server [surgery] can_operate_on_self = false # mrp... - -[control] -storage_limit = 2