Stack and storage enhancements (#16405)

This commit is contained in:
metalgearsloth
2023-05-15 12:24:45 +10:00
committed by GitHub
parent b20cc6f4d3
commit a9c0007c77
6 changed files with 127 additions and 23 deletions

View File

@@ -5,7 +5,9 @@ using Robust.Client.UserInterface.CustomControls;
using Content.Client.Items.Components; using Content.Client.Items.Components;
using Content.Client.Stylesheets; using Content.Client.Stylesheets;
using Content.Client.UserInterface.Controls; using Content.Client.UserInterface.Controls;
using Content.Shared.IdentityManagement;
using Content.Shared.Item; using Content.Shared.Item;
using Content.Shared.Stacks;
using Robust.Client.UserInterface; using Robust.Client.UserInterface;
using static Robust.Client.UserInterface.Controls.BoxContainer; using static Robust.Client.UserInterface.Controls.BoxContainer;
using static Content.Shared.Storage.SharedStorageComponent; using static Content.Shared.Storage.SharedStorageComponent;
@@ -28,7 +30,7 @@ namespace Content.Client.Storage.UI
public StorageWindow(IEntityManager entityManager) public StorageWindow(IEntityManager entityManager)
{ {
_entityManager = entityManager; _entityManager = entityManager;
SetSize = (200, 320); SetSize = (240, 320);
Title = Loc.GetString("comp-storage-window-title"); Title = Loc.GetString("comp-storage-window-title");
RectClipContent = true; RectClipContent = true;
@@ -112,6 +114,9 @@ namespace Content.Client.Storage.UI
_entityManager.TryGetComponent(entity, out SpriteComponent? sprite); _entityManager.TryGetComponent(entity, out SpriteComponent? sprite);
_entityManager.TryGetComponent(entity, out ItemComponent? item); _entityManager.TryGetComponent(entity, out ItemComponent? item);
_entityManager.TryGetComponent(entity, out StackComponent? stack);
var count = stack?.Count ?? 1;
var size = item?.Size;
button.AddChild(new BoxContainer button.AddChild(new BoxContainer
{ {
@@ -131,12 +136,13 @@ namespace Content.Client.Storage.UI
{ {
HorizontalExpand = true, HorizontalExpand = true,
ClipText = true, ClipText = true,
Text = _entityManager.GetComponent<MetaDataComponent>(entity).EntityName Text = _entityManager.GetComponent<MetaDataComponent>(Identity.Entity(entity, _entityManager)).EntityName +
(count > 1 ? $" x {count}" : string.Empty),
}, },
new Label new Label
{ {
Align = Label.AlignMode.Right, Align = Label.AlignMode.Right,
Text = item?.Size.ToString() ?? Loc.GetString("comp-storage-no-item-size"), Text = size.ToString() ?? Loc.GetString("comp-storage-no-item-size"),
} }
} }
}); });

View File

@@ -1,7 +1,10 @@
using Content.Server.Storage.Components;
using Content.Server.Storage.EntitySystems;
using Content.Shared.Popups; using Content.Shared.Popups;
using Content.Shared.Stacks; using Content.Shared.Stacks;
using Content.Shared.Verbs; using Content.Shared.Verbs;
using JetBrains.Annotations; using JetBrains.Annotations;
using Robust.Server.Containers;
using Robust.Shared.Map; using Robust.Shared.Map;
using Robust.Shared.Prototypes; using Robust.Shared.Prototypes;
@@ -14,6 +17,8 @@ namespace Content.Server.Stack
[UsedImplicitly] [UsedImplicitly]
public sealed class StackSystem : SharedStackSystem public sealed class StackSystem : SharedStackSystem
{ {
[Dependency] private readonly ContainerSystem _container = default!;
[Dependency] private readonly StorageSystem _storage = default!;
[Dependency] private readonly IPrototypeManager _prototypeManager = default!; [Dependency] private readonly IPrototypeManager _prototypeManager = default!;
public static readonly int[] DefaultSplitAmounts = { 1, 5, 10, 20, 30, 50 }; public static readonly int[] DefaultSplitAmounts = { 1, 5, 10, 20, 30, 50 };
@@ -160,6 +165,12 @@ namespace Content.Server.Stack
if (Split(uid, amount, userTransform.Coordinates, stack) is not {} split) if (Split(uid, amount, userTransform.Coordinates, stack) is not {} split)
return; return;
if (_container.TryGetContainingContainer(uid, out var container) &&
TryComp<ServerStorageComponent>(container.Owner, out var storage))
{
_storage.UpdateStorageUI(container.Owner, storage);
}
HandsSystem.PickupOrDrop(userUid, split); HandsSystem.PickupOrDrop(userUid, split);
PopupSystem.PopupCursor(Loc.GetString("comp-stack-split"), userUid); PopupSystem.PopupCursor(Loc.GetString("comp-stack-split"), userUid);

View File

@@ -3,6 +3,7 @@ using Content.Server.Administration.Managers;
using Content.Server.Ghost.Components; using Content.Server.Ghost.Components;
using Content.Server.Interaction; using Content.Server.Interaction;
using Content.Server.Popups; using Content.Server.Popups;
using Content.Server.Stack;
using Content.Server.Storage.Components; using Content.Server.Storage.Components;
using Content.Shared.ActionBlocker; using Content.Shared.ActionBlocker;
using Content.Shared.Administration; using Content.Shared.Administration;
@@ -37,10 +38,8 @@ using static Content.Shared.Storage.SharedStorageComponent;
namespace Content.Server.Storage.EntitySystems namespace Content.Server.Storage.EntitySystems
{ {
[UsedImplicitly]
public sealed partial class StorageSystem : EntitySystem public sealed partial class StorageSystem : EntitySystem
{ {
[Dependency] private readonly IGameTiming _gameTiming = default!;
[Dependency] private readonly IRobustRandom _random = default!; [Dependency] private readonly IRobustRandom _random = default!;
[Dependency] private readonly IAdminManager _admin = default!; [Dependency] private readonly IAdminManager _admin = default!;
[Dependency] private readonly ContainerSystem _containerSystem = default!; [Dependency] private readonly ContainerSystem _containerSystem = default!;
@@ -57,6 +56,7 @@ namespace Content.Server.Storage.EntitySystems
[Dependency] private readonly SharedCombatModeSystem _combatMode = default!; [Dependency] private readonly SharedCombatModeSystem _combatMode = default!;
[Dependency] private readonly SharedTransformSystem _transform = default!; [Dependency] private readonly SharedTransformSystem _transform = default!;
[Dependency] private readonly SharedAppearanceSystem _appearance = default!; [Dependency] private readonly SharedAppearanceSystem _appearance = default!;
[Dependency] private readonly StackSystem _stack = default!;
[Dependency] private readonly UseDelaySystem _useDelay = default!; [Dependency] private readonly UseDelaySystem _useDelay = default!;
/// <inheritdoc /> /// <inheritdoc />
@@ -423,7 +423,7 @@ namespace Content.Server.Storage.EntitySystems
_appearance.SetData(uid, StackVisuals.Hide, !storageComp.IsOpen); _appearance.SetData(uid, StackVisuals.Hide, !storageComp.IsOpen);
} }
private void RecalculateStorageUsed(ServerStorageComponent storageComp) public void RecalculateStorageUsed(ServerStorageComponent storageComp)
{ {
storageComp.StorageUsed = 0; storageComp.StorageUsed = 0;
storageComp.SizeCache.Clear(); storageComp.SizeCache.Clear();
@@ -438,11 +438,20 @@ namespace Content.Server.Storage.EntitySystems
if (!itemQuery.TryGetComponent(entity, out var itemComp)) if (!itemQuery.TryGetComponent(entity, out var itemComp))
continue; continue;
storageComp.StorageUsed += itemComp.Size; var size = itemComp.Size;
storageComp.SizeCache.Add(entity, itemComp.Size); storageComp.StorageUsed += size;
storageComp.SizeCache.Add(entity, size);
} }
} }
public int GetAvailableSpace(EntityUid uid, ServerStorageComponent? component = null)
{
if (!Resolve(uid, ref component))
return 0;
return component.StorageCapacityMax - component.StorageUsed;
}
/// <summary> /// <summary>
/// Move entities from one storage to another. /// Move entities from one storage to another.
/// </summary> /// </summary>
@@ -508,7 +517,7 @@ namespace Content.Server.Storage.EntitySystems
return false; return false;
} }
if (TryComp(insertEnt, out ItemComponent? itemComp) && if (!HasComp<StackComponent>(insertEnt) && TryComp(insertEnt, out ItemComponent? itemComp) &&
itemComp.Size > storageComp.StorageCapacityMax - storageComp.StorageUsed) itemComp.Size > storageComp.StorageCapacityMax - storageComp.StorageUsed)
{ {
reason = "comp-storage-insufficient-capacity"; reason = "comp-storage-insufficient-capacity";
@@ -525,9 +534,63 @@ namespace Content.Server.Storage.EntitySystems
/// <returns>true if the entity was inserted, false otherwise</returns> /// <returns>true if the entity was inserted, false otherwise</returns>
public bool Insert(EntityUid uid, EntityUid insertEnt, ServerStorageComponent? storageComp = null, bool playSound = true) public bool Insert(EntityUid uid, EntityUid insertEnt, ServerStorageComponent? storageComp = null, bool playSound = true)
{ {
if (!Resolve(uid, ref storageComp) || !CanInsert(uid, insertEnt, out _, storageComp) || storageComp.Storage?.Insert(insertEnt) == false) if (!Resolve(uid, ref storageComp) || !CanInsert(uid, insertEnt, out _, storageComp) || storageComp.Storage == null)
return false; return false;
/*
* 1. If the inserted thing is stackable then try to stack it to existing stacks
* 2. If anything remains insert whatever is possible.
* 3. If insertion is not possible then leave the stack as is.
* At either rate still play the insertion sound
*
* 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
var stackQuery = GetEntityQuery<StackComponent>();
if (stackQuery.TryGetComponent(insertEnt, out var insertStack))
{
var toInsertCount = insertStack.Count;
foreach (var ent in storageComp.Storage.ContainedEntities)
{
if (!stackQuery.TryGetComponent(ent, out var containedStack) || !insertStack.StackTypeId.Equals(containedStack.StackTypeId))
continue;
if (!_stack.TryAdd(insertEnt, ent, insertStack, containedStack))
continue;
var remaining = insertStack.Count;
toInsertCount -= toInsertCount - remaining;
if (remaining > 0)
continue;
break;
}
// Still stackable remaining
if (insertStack.Count > 0)
{
// Try to insert it as a new stack.
if (TryComp(insertEnt, out ItemComponent? itemComp) &&
itemComp.Size > storageComp.StorageCapacityMax - storageComp.StorageUsed ||
!storageComp.Storage.Insert(insertEnt))
{
// 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;
}
}
}
// Non-stackable but no insertion for reasons.
else if (!storageComp.Storage.Insert(insertEnt))
{
return false;
}
if (playSound && storageComp.StorageInsertSound is not null) if (playSound && storageComp.StorageInsertSound is not null)
_audio.PlayPvs(storageComp.StorageInsertSound, uid); _audio.PlayPvs(storageComp.StorageInsertSound, uid);
@@ -643,7 +706,7 @@ namespace Content.Server.Storage.EntitySystems
} }
} }
private void UpdateStorageUI(EntityUid uid, ServerStorageComponent storageComp) public void UpdateStorageUI(EntityUid uid, ServerStorageComponent storageComp)
{ {
if (storageComp.Storage == null) if (storageComp.Storage == null)
return; return;

View File

@@ -105,7 +105,7 @@ namespace Content.Shared.Stacks
if (!Resolve(recipient, ref recipientStack, false) || !Resolve(donor, ref donorStack, false)) if (!Resolve(recipient, ref recipientStack, false) || !Resolve(donor, ref donorStack, false))
return false; return false;
if (recipientStack.StackTypeId == null || !recipientStack.StackTypeId.Equals(donorStack.StackTypeId)) if (string.IsNullOrEmpty(recipientStack.StackTypeId) || !recipientStack.StackTypeId.Equals(donorStack.StackTypeId))
return false; return false;
transfered = Math.Min(donorStack.Count, GetAvailableSpace(recipientStack)); transfered = Math.Min(donorStack.Count, GetAvailableSpace(recipientStack));
@@ -270,7 +270,7 @@ namespace Content.Shared.Stacks
if (component.MaxCountOverride != null) if (component.MaxCountOverride != null)
return component.MaxCountOverride.Value; return component.MaxCountOverride.Value;
if (component.StackTypeId == null) if (string.IsNullOrEmpty(component.StackTypeId))
return 1; return 1;
var stackProto = _prototype.Index<StackPrototype>(component.StackTypeId); var stackProto = _prototype.Index<StackPrototype>(component.StackTypeId);
@@ -289,6 +289,38 @@ namespace Content.Shared.Stacks
return GetMaxCount(component) - component.Count; return GetMaxCount(component) - component.Count;
} }
/// <summary>
/// Tries to add one stack to another. May have some leftover count in the inserted entity.
/// </summary>
public bool TryAdd(EntityUid insertEnt, EntityUid targetEnt, StackComponent? insertStack = null, StackComponent? targetStack = null)
{
if (!Resolve(insertEnt, ref insertStack) || !Resolve(targetEnt, ref targetStack))
return false;
var count = insertStack.Count;
return TryAdd(insertEnt, targetEnt, count, insertStack, targetStack);
}
/// <summary>
/// Tries to add one stack to another. May have some leftover count in the inserted entity.
/// </summary>
public bool TryAdd(EntityUid insertEnt, EntityUid targetEnt, int count, StackComponent? insertStack = null, StackComponent? targetStack = null)
{
if (!Resolve(insertEnt, ref insertStack) || !Resolve(targetEnt, ref targetStack))
return false;
var available = GetAvailableSpace(targetStack);
if (available <= 0)
return false;
var change = Math.Min(available, count);
SetCount(targetEnt, targetStack.Count + change, targetStack);
SetCount(insertEnt, insertStack.Count - change, insertStack);
return true;
}
private void OnStackStarted(EntityUid uid, StackComponent component, ComponentStartup args) private void OnStackStarted(EntityUid uid, StackComponent component, ComponentStartup args)
{ {
if (!TryComp(uid, out AppearanceComponent? appearance)) if (!TryComp(uid, out AppearanceComponent? appearance))

View File

@@ -9,6 +9,7 @@
sprite: Objects/Materials/ore.rsi sprite: Objects/Materials/ore.rsi
- type: Item - type: Item
sprite: Objects/Materials/ore.rsi sprite: Objects/Materials/ore.rsi
size: 30
- type: ItemStatus - type: ItemStatus
- type: Tag - type: Tag
tags: tags:

View File

@@ -17,9 +17,9 @@
stackType: Cable stackType: Cable
- type: Sprite - type: Sprite
sprite: Objects/Tools/cable-coils.rsi sprite: Objects/Tools/cable-coils.rsi
netsync: false
- type: Item - type: Item
sprite: Objects/Tools/cable-coils.rsi sprite: Objects/Tools/cable-coils.rsi
size: 10
- type: CablePlacer - type: CablePlacer
- type: Clickable - type: Clickable
- type: StaticPrice - type: StaticPrice
@@ -39,7 +39,6 @@
- type: Sprite - type: Sprite
state: coilhv-30 state: coilhv-30
- type: Item - type: Item
size: 10
heldPrefix: coilhv heldPrefix: coilhv
- type: CablePlacer - type: CablePlacer
cablePrototypeID: CableHV cablePrototypeID: CableHV
@@ -59,8 +58,6 @@
components: components:
- type: Sprite - type: Sprite
state: coilhv-10 state: coilhv-10
- type: Item
size: 3
- type: Stack - type: Stack
count: 1 count: 1
@@ -76,7 +73,6 @@
- type: Sprite - type: Sprite
state: coilmv-30 state: coilmv-30
- type: Item - type: Item
size: 10
heldPrefix: coilmv heldPrefix: coilmv
- type: CablePlacer - type: CablePlacer
cablePrototypeID: CableMV cablePrototypeID: CableMV
@@ -96,8 +92,6 @@
components: components:
- type: Sprite - type: Sprite
state: coilmv-10 state: coilmv-10
- type: Item
size: 3
- type: Stack - type: Stack
count: 1 count: 1
@@ -111,7 +105,6 @@
- type: Sprite - type: Sprite
state: coillv-30 state: coillv-30
- type: Item - type: Item
size: 10
heldPrefix: coillv heldPrefix: coillv
- type: CablePlacer - type: CablePlacer
cablePrototypeID: CableApcExtension cablePrototypeID: CableApcExtension
@@ -131,7 +124,5 @@
components: components:
- type: Sprite - type: Sprite
state: coillv-10 state: coillv-10
- type: Item
size: 3
- type: Stack - type: Stack
count: 1 count: 1