Stack and storage enhancements (#16405)
This commit is contained in:
@@ -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"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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))
|
||||||
|
|||||||
@@ -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:
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
Reference in New Issue
Block a user