From eb0c86f803648c0ad8387f7255e15c402dc41653 Mon Sep 17 00:00:00 2001 From: Leon Friedrich <60421075+ElectroJr@users.noreply.github.com> Date: Mon, 13 Nov 2023 23:43:03 +1100 Subject: [PATCH] Storage CanInsert() tweaks (#21623) --- .../Storage/Systems/StorageSystem.cs | 6 +- Content.Server/Item/ItemSystem.cs | 19 +- Content.Server/Stack/StackSystem.cs | 11 - .../Storage/EntitySystems/StorageSystem.cs | 2 +- .../EntitySystems/SharedHandsSystem.Drop.cs | 14 ++ Content.Shared/Item/SharedItemSystem.cs | 7 - .../EntitySystems/SharedStorageSystem.cs | 229 +++++++++--------- Content.Shared/Storage/StorageComponent.cs | 2 + 8 files changed, 135 insertions(+), 155 deletions(-) diff --git a/Content.Client/Storage/Systems/StorageSystem.cs b/Content.Client/Storage/Systems/StorageSystem.cs index 5b55c3c8d57ab6..86d6ec637898bf 100644 --- a/Content.Client/Storage/Systems/StorageSystem.cs +++ b/Content.Client/Storage/Systems/StorageSystem.cs @@ -23,10 +23,10 @@ public override void Initialize() SubscribeNetworkEvent(HandleAnimatingInsertingEntities); } - public override void UpdateUI(EntityUid uid, StorageComponent component) + public override void UpdateUI(Entity entity) { - // Should we wrap this in some prediction call maybe? - StorageUpdated?.Invoke(uid, component); + if (Resolve(entity.Owner, ref entity.Comp)) + StorageUpdated?.Invoke(entity.Owner, entity.Comp); } /// diff --git a/Content.Server/Item/ItemSystem.cs b/Content.Server/Item/ItemSystem.cs index efb99ae6533426..9053ec05cd38b6 100644 --- a/Content.Server/Item/ItemSystem.cs +++ b/Content.Server/Item/ItemSystem.cs @@ -1,24 +1,7 @@ -using Content.Server.Storage.Components; -using Content.Server.Storage.EntitySystems; -using Content.Shared.Item; -using Content.Shared.Stacks; -using Content.Shared.Storage; +using Content.Shared.Item; namespace Content.Server.Item; public sealed class ItemSystem : SharedItemSystem { - [Dependency] private readonly StorageSystem _storage = default!; - - protected override void OnStackCountChanged(EntityUid uid, ItemComponent component, StackCountChangedEvent args) - { - base.OnStackCountChanged(uid, component, args); - - if (!Container.TryGetContainingContainer(uid, out var container) || - !TryComp(container.Owner, out var storage)) - return; - - _storage.RecalculateStorageUsed(container.Owner, storage); - _storage.UpdateUI(container.Owner, storage); - } } diff --git a/Content.Server/Stack/StackSystem.cs b/Content.Server/Stack/StackSystem.cs index f49e02ab9aa765..001093a8dd4f9b 100644 --- a/Content.Server/Stack/StackSystem.cs +++ b/Content.Server/Stack/StackSystem.cs @@ -1,10 +1,7 @@ -using Content.Server.Storage.EntitySystems; using Content.Shared.Popups; using Content.Shared.Stacks; -using Content.Shared.Storage; using Content.Shared.Verbs; using JetBrains.Annotations; -using Robust.Server.Containers; using Robust.Shared.Map; using Robust.Shared.Prototypes; @@ -17,8 +14,6 @@ namespace Content.Server.Stack [UsedImplicitly] public sealed class StackSystem : SharedStackSystem { - [Dependency] private readonly ContainerSystem _container = default!; - [Dependency] private readonly StorageSystem _storage = default!; [Dependency] private readonly IPrototypeManager _prototypeManager = default!; public static readonly int[] DefaultSplitAmounts = { 1, 5, 10, 20, 30, 50 }; @@ -165,12 +160,6 @@ private void UserSplit(EntityUid uid, EntityUid userUid, int amount, if (Split(uid, amount, userTransform.Coordinates, stack) is not {} split) return; - if (_container.TryGetContainingContainer(uid, out var container) && - TryComp(container.Owner, out var storage)) - { - _storage.UpdateUI(container.Owner, storage); - } - Hands.PickupOrDrop(userUid, split); Popup.PopupCursor(Loc.GetString("comp-stack-split"), userUid); diff --git a/Content.Server/Storage/EntitySystems/StorageSystem.cs b/Content.Server/Storage/EntitySystems/StorageSystem.cs index 8b4ae1c76f9f4f..d59006e75315c3 100644 --- a/Content.Server/Storage/EntitySystems/StorageSystem.cs +++ b/Content.Server/Storage/EntitySystems/StorageSystem.cs @@ -90,7 +90,7 @@ private void OnBoundUIClosed(EntityUid uid, StorageComponent storageComp, BoundU if (!_uiSystem.IsUiOpen(uid, args.UiKey)) { storageComp.IsUiOpen = false; - UpdateStorageVisualization(uid, storageComp); + UpdateAppearance((uid, storageComp, null)); if (storageComp.StorageCloseSound is not null) Audio.Play(storageComp.StorageCloseSound, Filter.Pvs(uid, entityManager: EntityManager), uid, true, storageComp.StorageCloseSound.Params); diff --git a/Content.Shared/Hands/EntitySystems/SharedHandsSystem.Drop.cs b/Content.Shared/Hands/EntitySystems/SharedHandsSystem.Drop.cs index 77752c4fbdeb7c..42909201328c12 100644 --- a/Content.Shared/Hands/EntitySystems/SharedHandsSystem.Drop.cs +++ b/Content.Shared/Hands/EntitySystems/SharedHandsSystem.Drop.cs @@ -27,6 +27,20 @@ protected virtual void HandleEntityRemoved(EntityUid uid, HandsComponent hands, RaiseLocalEvent(uid, didUnequip); } + /// + /// Checks whether an entity can drop a given entity. Will return false if they are not holding the entity. + /// + public bool CanDrop(EntityUid uid, EntityUid entity, HandsComponent? handsComp = null, bool checkActionBlocker = true) + { + if (!Resolve(uid, ref handsComp)) + return false; + + if (!IsHolding(uid, entity, out var hand, handsComp)) + return false; + + return CanDropHeld(uid, hand, checkActionBlocker); + } + /// /// Checks if the contents of a hand is able to be removed from its container. /// diff --git a/Content.Shared/Item/SharedItemSystem.cs b/Content.Shared/Item/SharedItemSystem.cs index ee4dc1e45f71fd..21679bbd72186c 100644 --- a/Content.Shared/Item/SharedItemSystem.cs +++ b/Content.Shared/Item/SharedItemSystem.cs @@ -1,6 +1,5 @@ using Content.Shared.Hands.EntitySystems; using Content.Shared.Interaction; -using Content.Shared.Stacks; using Content.Shared.Verbs; using Content.Shared.Examine; using JetBrains.Annotations; @@ -22,7 +21,6 @@ public override void Initialize() base.Initialize(); SubscribeLocalEvent>(AddPickupVerb); SubscribeLocalEvent(OnHandInteract, before: new []{typeof(SharedItemSystem)}); - SubscribeLocalEvent(OnStackCountChanged); SubscribeLocalEvent(OnGetState); SubscribeLocalEvent(OnHandleState); @@ -80,11 +78,6 @@ private void OnHandInteract(EntityUid uid, ItemComponent component, InteractHand args.Handled = _handsSystem.TryPickup(args.User, uid, animateUser: false); } - protected virtual void OnStackCountChanged(EntityUid uid, ItemComponent component, StackCountChangedEvent args) - { - - } - private void OnHandleState(EntityUid uid, ItemComponent component, ref ComponentHandleState args) { if (args.Current is not ItemComponentState state) diff --git a/Content.Shared/Storage/EntitySystems/SharedStorageSystem.cs b/Content.Shared/Storage/EntitySystems/SharedStorageSystem.cs index 63f5ba39a54a40..88e263b5562a97 100644 --- a/Content.Shared/Storage/EntitySystems/SharedStorageSystem.cs +++ b/Content.Shared/Storage/EntitySystems/SharedStorageSystem.cs @@ -69,9 +69,11 @@ public override void Initialize() SubscribeLocalEvent(OnDestroy); SubscribeLocalEvent(OnInsertItemMessage); SubscribeLocalEvent(OnBoundUIOpen); + SubscribeLocalEvent(OnStackCountChanged); - SubscribeLocalEvent(OnStorageItemInserted); - SubscribeLocalEvent(OnStorageItemRemoved); + SubscribeLocalEvent(OnContainerModified); + SubscribeLocalEvent(OnContainerModified); + SubscribeLocalEvent(OnInsertAttempt); SubscribeLocalEvent(OnDoAfter); @@ -80,31 +82,11 @@ public override void Initialize() private void OnComponentInit(EntityUid uid, StorageComponent storageComp, ComponentInit args) { - // ReSharper disable once StringLiteralTypo - storageComp.Container = _containerSystem.EnsureContainer(uid, "storagebase"); - UpdateStorage(uid, storageComp); + storageComp.Container = _containerSystem.EnsureContainer(uid, StorageComponent.ContainerId); + UpdateAppearance((uid, storageComp, null)); } - /// - /// Updates the storage UI, visualizer, etc. - /// - /// - /// - private void UpdateStorage(EntityUid uid, StorageComponent component) - { - // TODO: I had this. - // We can get states being applied before the container is ready. - // ReSharper disable once ConditionIsAlwaysTrueOrFalseAccordingToNullableAPIContract - if (component.Container == default) - return; - - RecalculateStorageUsed(uid, component); - UpdateStorageVisualization(uid, component); - UpdateUI(uid, component); - Dirty(uid, component); - } - - public virtual void UpdateUI(EntityUid uid, StorageComponent component) {} + public virtual void UpdateUI(Entity entity) {} public virtual void OpenStorageUI(EntityUid uid, EntityUid entity, StorageComponent? storageComp = null, bool silent = false) { } @@ -120,7 +102,7 @@ private void AddTransferVerbs(EntityUid uid, StorageComponent component, GetVerb // if the target is storage, add a verb to transfer storage. if (TryComp(args.Target, out StorageComponent? targetStorage) - && (!TryComp(uid, out LockComponent? targetLock) || !targetLock.Locked)) + && (!TryComp(args.Target, out LockComponent? targetLock) || !targetLock.Locked)) { UtilityVerb verb = new() { @@ -142,8 +124,6 @@ private void OnInteractUsing(EntityUid uid, StorageComponent storageComp, Intera if (args.Handled || !storageComp.ClickInsert || TryComp(uid, out LockComponent? lockComponent) && lockComponent.Locked) return; - Log.Debug($"Storage (UID {uid}) attacked by user (UID {args.User}) with entity (UID {args.Used})."); - if (HasComp(uid)) return; @@ -184,7 +164,7 @@ private void OnImplantActivate(EntityUid uid, StorageComponent storageComp, Open /// private void AfterInteract(EntityUid uid, StorageComponent storageComp, AfterInteractEvent args) { - if (!args.CanReach) + if (args.Handled || !args.CanReach) return; // Pick up all entities in a radius around the clicked location. @@ -217,6 +197,7 @@ private void AfterInteract(EntityUid uid, StorageComponent storageComp, AfterInt }; _doAfterSystem.TryStartDoAfter(doAfterArgs); + args.Handled = true; } return; @@ -245,6 +226,7 @@ private void AfterInteract(EntityUid uid, StorageComponent storageComp, AfterInt _transform ); + args.Handled = true; if (PlayerInsertEntityInWorld((uid, storageComp), args.User, target)) { RaiseNetworkEvent(new AnimateInsertingEntitiesEvent(GetNetEntity(uid), @@ -261,6 +243,7 @@ private void OnDoAfter(EntityUid uid, StorageComponent component, AreaPickupDoAf if (args.Handled || args.Cancelled) return; + args.Handled = true; var successfullyInserted = new List(); var successfullyInsertedPositions = new List(); var successfullyInsertedAngles = new List(); @@ -374,44 +357,57 @@ private void OnBoundUIOpen(EntityUid uid, StorageComponent storageComp, BoundUIO if (!storageComp.IsUiOpen) { storageComp.IsUiOpen = true; - UpdateStorageVisualization(uid, storageComp); + UpdateAppearance((uid, storageComp, null)); } } - private void OnStorageItemInserted(EntityUid uid, StorageComponent component, EntInsertedIntoContainerMessage args) + private void OnContainerModified(EntityUid uid, StorageComponent component, ContainerModifiedMessage args) { - UpdateStorage(uid, component); - } + // ReSharper disable once ConditionIsAlwaysTrueOrFalseAccordingToNullableAPIContract + if (component.Container == null) + return; - private void OnStorageItemRemoved(EntityUid uid, StorageComponent storageComp, EntRemovedFromContainerMessage args) - { - UpdateStorage(uid, storageComp); + if (args.Container.ID != StorageComponent.ContainerId) + return; + + UpdateAppearance((uid, component, null)); + UpdateUI((uid, component)); } - protected void UpdateStorageVisualization(EntityUid uid, StorageComponent storageComp) + private void OnInsertAttempt(EntityUid uid, StorageComponent component, ContainerIsInsertingAttemptEvent args) { - if (!TryComp(uid, out var appearance)) + if (args.Cancelled || args.Container.ID != StorageComponent.ContainerId) return; - _appearance.SetData(uid, StorageVisuals.Open, storageComp.IsUiOpen, appearance); - _appearance.SetData(uid, SharedBagOpenVisuals.BagState, storageComp.IsUiOpen ? SharedBagState.Open : SharedBagState.Closed); - - if (HasComp(uid)) - _appearance.SetData(uid, StackVisuals.Hide, !storageComp.IsUiOpen); + if (!CanInsert(uid, args.EntityUid, out _, component, ignoreStacks: true)) + args.Cancel(); } - public void RecalculateStorageUsed(EntityUid uid, StorageComponent storageComp) + public void UpdateAppearance(Entity entity) { - if (storageComp.MaxSlots == null) + // TODO STORAGE remove appearance data and just use the data on the component. + var (uid, storage, appearance) = entity; + if (!Resolve(uid, ref storage, ref appearance, false)) + return; + + int capacity; + int used; + if (storage.MaxSlots == null) { - _appearance.SetData(uid, StorageVisuals.StorageUsed, GetCumulativeItemSizes(uid, storageComp)); - _appearance.SetData(uid, StorageVisuals.Capacity, storageComp.MaxTotalWeight); + used = GetCumulativeItemSizes(uid, storage); + capacity = storage.MaxTotalWeight; } else { - _appearance.SetData(uid, StorageVisuals.StorageUsed, storageComp.Container.ContainedEntities.Count); - _appearance.SetData(uid, StorageVisuals.Capacity, storageComp.MaxSlots.Value); + capacity = storage.MaxSlots.Value; + used = storage.Container.ContainedEntities.Count; } + + _appearance.SetData(uid, StorageVisuals.StorageUsed, used, appearance); + _appearance.SetData(uid, StorageVisuals.Capacity, capacity, appearance); + _appearance.SetData(uid, StorageVisuals.Open, storage.IsUiOpen, appearance); + _appearance.SetData(uid, SharedBagOpenVisuals.BagState, storage.IsUiOpen ? SharedBagState.Open : SharedBagState.Closed, appearance); + _appearance.SetData(uid, StackVisuals.Hide, !storage.IsUiOpen, appearance); } /// @@ -449,9 +445,9 @@ public void TransferEntities(EntityUid source, EntityUid target, EntityUid? user /// /// /// true if it can be inserted, false otherwise - public bool CanInsert(EntityUid uid, EntityUid insertEnt, out string? reason, StorageComponent? storageComp = null, ItemComponent? item = null) + public bool CanInsert(EntityUid uid, EntityUid insertEnt, out string? reason, StorageComponent? storageComp = null, ItemComponent? item = null, bool ignoreStacks = false) { - if (!Resolve(uid, ref storageComp) || !Resolve(insertEnt, ref item)) + if (!Resolve(uid, ref storageComp) || !Resolve(insertEnt, ref item, false)) { reason = null; return false; @@ -475,36 +471,41 @@ public bool CanInsert(EntityUid uid, EntityUid insertEnt, out string? reason, St return false; } - if (!_stackQuery.TryGetComponent(insertEnt, out var stack) || !HasSpaceInStacks(uid, stack.StackTypeId)) + if (!ignoreStacks + && _stackQuery.TryGetComponent(insertEnt, out var stack) + && HasSpaceInStacks((uid, storageComp), stack.StackTypeId)) { - var maxSize = _item.GetSizePrototype(GetMaxItemSize((uid, storageComp))); - if (_item.GetSizePrototype(item.Size) > maxSize) - { - reason = "comp-storage-too-big"; - return false; - } + reason = null; + return true; + } - if (TryComp(insertEnt, out var insertStorage) - && _item.GetSizePrototype(GetMaxItemSize((insertEnt, insertStorage))) >= maxSize) - { - reason = "comp-storage-too-big"; - return false; - } + var maxSize = _item.GetSizePrototype(GetMaxItemSize((uid, storageComp))); + if (_item.GetSizePrototype(item.Size) > maxSize) + { + reason = "comp-storage-too-big"; + return false; + } - if (storageComp.MaxSlots != null) - { - if (storageComp.Container.ContainedEntities.Count >= storageComp.MaxSlots) - { - reason = "comp-storage-insufficient-capacity"; - return false; - } - } - else if (_item.GetItemSizeWeight(item.Size) + GetCumulativeItemSizes(uid, storageComp) > storageComp.MaxTotalWeight) + if (TryComp(insertEnt, out var insertStorage) + && _item.GetSizePrototype(GetMaxItemSize((insertEnt, insertStorage))) >= maxSize) + { + reason = "comp-storage-too-big"; + return false; + } + + if (storageComp.MaxSlots != null) + { + if (storageComp.Container.ContainedEntities.Count >= storageComp.MaxSlots) { reason = "comp-storage-insufficient-capacity"; return false; } } + else if (_item.GetItemSizeWeight(item.Size) + GetCumulativeItemSizes(uid, storageComp) > storageComp.MaxTotalWeight) + { + reason = "comp-storage-insufficient-capacity"; + return false; + } reason = null; return true; @@ -513,7 +514,8 @@ public bool CanInsert(EntityUid uid, EntityUid insertEnt, out string? reason, St /// /// Inserts into the storage container /// - /// true if the entity was inserted, false otherwise + /// true if the entity was inserted, false otherwise. This will also return true if a stack was partially + /// inserted. public bool Insert( EntityUid uid, EntityUid insertEnt, @@ -528,7 +530,8 @@ public bool Insert( /// /// Inserts into the storage container /// - /// true if the entity was inserted, false otherwise + /// true if the entity was inserted, false otherwise. This will also return true if a stack was partially + /// inserted public bool Insert( EntityUid uid, EntityUid insertEnt, @@ -541,7 +544,7 @@ public bool Insert( stackedEntity = null; reason = null; - if (!Resolve(uid, ref storageComp) || !CanInsert(uid, insertEnt, out reason, storageComp)) + if (!Resolve(uid, ref storageComp)) return false; /* @@ -553,56 +556,42 @@ public bool Insert( * For now we just treat items as always being the same size regardless of stack count. */ - // If it's stackable then prefer to stack it - if (_stackQuery.TryGetComponent(insertEnt, out var insertStack)) + if (!_stackQuery.TryGetComponent(insertEnt, out var insertStack)) { - var toInsertCount = insertStack.Count; - - foreach (var ent in storageComp.Container.ContainedEntities) - { - if (!_stackQuery.TryGetComponent(ent, out var containedStack)) - continue; + if (!_containerSystem.Insert(insertEnt, storageComp.Container)) + return false; - if (!_stack.TryAdd(insertEnt, ent, insertStack, containedStack)) - continue; + if (playSound) + Audio.PlayPredicted(storageComp.StorageInsertSound, uid, user); - stackedEntity = ent; - var remaining = insertStack.Count; - toInsertCount -= toInsertCount - remaining; + return true; + } - if (remaining > 0) - continue; + var toInsertCount = insertStack.Count; - break; - } + foreach (var ent in storageComp.Container.ContainedEntities) + { + if (!_stackQuery.TryGetComponent(ent, out var containedStack)) + continue; - // Still stackable remaining - if (toInsertCount > 0) - { - // Try to insert it as a new stack. - if (!CanInsert(uid, insertEnt, out _, storageComp) || - !storageComp.Container.Insert(insertEnt)) - { - UpdateUI(uid, storageComp); + if (!_stack.TryAdd(insertEnt, ent, insertStack, containedStack)) + continue; - // If we also didn't do any stack fills above then just end - // otherwise play sound and update UI anyway. - if (toInsertCount == insertStack.Count) - return false; - } - } - else - { - UpdateUI(uid, storageComp); - } + stackedEntity = ent; + if (insertStack.Count == 0) + break; } - // Non-stackable but no insertion for reasons. - else if (!storageComp.Container.Insert(insertEnt)) + + // Still stackable remaining + if (insertStack.Count > 0 + && !_containerSystem.Insert(insertEnt, storageComp.Container) + && toInsertCount == insertStack.Count) { + // Failed to insert anything. return false; } - if (playSound && storageComp.StorageInsertSound is not null) + if (playSound) Audio.PlayPredicted(storageComp.StorageInsertSound, uid, user); return true; @@ -628,7 +617,7 @@ public bool PlayerInsertHeldEntity(EntityUid uid, EntityUid player, StorageCompo return false; } - if (!_sharedHandsSystem.TryDrop(player, toInsert.Value, handsComp: hands)) + if (!_sharedHandsSystem.CanDrop(player, toInsert.Value, hands)) { _popupSystem.PopupClient(Loc.GetString("comp-storage-cant-drop"), uid, player); return false; @@ -737,6 +726,16 @@ public ProtoId GetMaxItemSize(Entity uid) return sizes[Math.Max(currentSizeIndex - 1, 0)].ID; } + private void OnStackCountChanged(EntityUid uid, MetaDataComponent component, StackCountChangedEvent args) + { + if (_containerSystem.TryGetContainingContainer(uid, out var container, component) && + container.ID == StorageComponent.ContainerId) + { + UpdateAppearance(container.Owner); + UpdateUI(container.Owner); + } + } + public FixedPoint2 GetStorageFillPercentage(Entity uid) { if (!Resolve(uid, ref uid.Comp)) diff --git a/Content.Shared/Storage/StorageComponent.cs b/Content.Shared/Storage/StorageComponent.cs index 56aa07d6498b55..422b7f9989b69e 100644 --- a/Content.Shared/Storage/StorageComponent.cs +++ b/Content.Shared/Storage/StorageComponent.cs @@ -16,6 +16,8 @@ namespace Content.Shared.Storage [RegisterComponent, NetworkedComponent, AutoGenerateComponentState] public sealed partial class StorageComponent : Component { + public static string ContainerId = "storagebase"; + // TODO: This fucking sucks [ViewVariables(VVAccess.ReadWrite), DataField("isOpen"), AutoNetworkedField] public bool IsUiOpen;