diff --git a/Content.Client/Storage/Visualizers/StorageFillVisualizerSystem.cs b/Content.Client/Storage/Visualizers/StorageFillVisualizerSystem.cs new file mode 100644 index 0000000000..e0019f6258 --- /dev/null +++ b/Content.Client/Storage/Visualizers/StorageFillVisualizerSystem.cs @@ -0,0 +1,22 @@ +using Content.Shared.Storage; +using Content.Shared.Storage.Components; +using Robust.Client.GameObjects; + +namespace Content.Client.Storage.Visualizers; + +public sealed class StorageFillVisualizerSystem : VisualizerSystem +{ + protected override void OnAppearanceChange(EntityUid uid, StorageFillVisualizerComponent component, ref AppearanceChangeEvent args) + { + base.OnAppearanceChange(uid, component, ref args); + + if (!TryComp(uid, out SpriteComponent? sprite)) + return; + + if (!args.Component.TryGetData(StorageFillVisuals.FillLevel, out int level)) + return; + + var state = $"{component.FillBaseName}-{level}"; + sprite.LayerSetState(StorageFillLayers.Fill, state); + } +} diff --git a/Content.Server/Storage/Components/ServerStorageComponent.cs b/Content.Server/Storage/Components/ServerStorageComponent.cs index a569ecd42b..fe57a65e16 100644 --- a/Content.Server/Storage/Components/ServerStorageComponent.cs +++ b/Content.Server/Storage/Components/ServerStorageComponent.cs @@ -73,9 +73,9 @@ namespace Content.Server.Storage.Components private EntityWhitelist? _whitelist = null; private bool _storageInitialCalculated; - private int _storageUsed; + public int StorageUsed; [DataField("capacity")] - private int _storageCapacityMax = 10000; + public int StorageCapacityMax = 10000; public readonly HashSet SubscribedSessions = new(); [DataField("storageSoundCollection")] @@ -123,7 +123,7 @@ namespace Content.Server.Storage.Components private void RecalculateStorageUsed() { - _storageUsed = 0; + StorageUsed = 0; _sizeCache.Clear(); if (Storage == null) @@ -134,7 +134,7 @@ namespace Content.Server.Storage.Components foreach (var entity in Storage.ContainedEntities) { var item = _entityManager.GetComponent(entity); - _storageUsed += item.Size; + StorageUsed += item.Size; _sizeCache.Add(entity, item.Size); } } @@ -149,13 +149,13 @@ namespace Content.Server.Storage.Components EnsureInitialCalculated(); if (_entityManager.TryGetComponent(entity, out ServerStorageComponent? storage) && - storage._storageCapacityMax >= _storageCapacityMax) + storage.StorageCapacityMax >= StorageCapacityMax) { return false; } if (_entityManager.TryGetComponent(entity, out SharedItemComponent? store) && - store.Size > _storageCapacityMax - _storageUsed) + store.Size > StorageCapacityMax - StorageUsed) { return false; } @@ -205,7 +205,7 @@ namespace Content.Server.Storage.Components if (_entityManager.TryGetComponent(message.Entity, out SharedItemComponent? storable)) size = storable.Size; - _storageUsed += size; + StorageUsed += size; _sizeCache[message.Entity] = size; UpdateClientInventories(); @@ -230,7 +230,7 @@ namespace Content.Server.Storage.Components return; } - _storageUsed -= size; + StorageUsed -= size; UpdateClientInventories(); } @@ -350,7 +350,7 @@ namespace Content.Server.Storage.Components var stored = StoredEntities.Select(e => e).ToArray(); #pragma warning disable 618 - SendNetworkMessage(new StorageHeldItemsMessage(stored, _storageUsed, _storageCapacityMax), session.ConnectedClient); + SendNetworkMessage(new StorageHeldItemsMessage(stored, StorageUsed, StorageCapacityMax), session.ConnectedClient); #pragma warning restore 618 } diff --git a/Content.Server/Storage/EntitySystems/StorageFillVisualizerSystem.cs b/Content.Server/Storage/EntitySystems/StorageFillVisualizerSystem.cs new file mode 100644 index 0000000000..5629ebfe68 --- /dev/null +++ b/Content.Server/Storage/EntitySystems/StorageFillVisualizerSystem.cs @@ -0,0 +1,42 @@ +using Content.Server.Storage.Components; +using Content.Shared.Rounding; +using Content.Shared.Storage.Components; +using Robust.Shared.Containers; + +namespace Content.Server.Storage.EntitySystems; + +public sealed class StorageFillVisualizerSystem : EntitySystem +{ + public override void Initialize() + { + base.Initialize(); + SubscribeLocalEvent(OnInit); + SubscribeLocalEvent(OnInserted); + SubscribeLocalEvent(OnRemoved); + } + + private void OnInit(EntityUid uid, StorageFillVisualizerComponent component, ComponentInit args) + { + UpdateAppearance(uid, component: component); + } + + private void OnInserted(EntityUid uid, StorageFillVisualizerComponent component, EntInsertedIntoContainerMessage args) + { + UpdateAppearance(uid, component: component); + } + + private void OnRemoved(EntityUid uid, StorageFillVisualizerComponent component, EntRemovedFromContainerMessage args) + { + UpdateAppearance(uid, component: component); + } + + private void UpdateAppearance(EntityUid uid, ServerStorageComponent? storage = null, AppearanceComponent? appearance = null, + StorageFillVisualizerComponent? component = null) + { + if (!Resolve(uid, ref storage, ref appearance, ref component, false)) + return; + + var level = ContentHelpers.RoundToEqualLevels(storage.StorageUsed, storage.StorageCapacityMax, component.MaxFillLevels); + appearance.SetData(StorageFillVisuals.FillLevel, level); + } +} diff --git a/Content.Shared/Storage/Components/StorageFillVisualizerComponent.cs b/Content.Shared/Storage/Components/StorageFillVisualizerComponent.cs new file mode 100644 index 0000000000..78d0092853 --- /dev/null +++ b/Content.Shared/Storage/Components/StorageFillVisualizerComponent.cs @@ -0,0 +1,28 @@ +using Robust.Shared.Serialization; + +namespace Content.Shared.Storage.Components; + +/// +/// Change sprite depending on a storage fill percent. +/// +[RegisterComponent] +public sealed class StorageFillVisualizerComponent : Component +{ + [DataField("maxFillLevels", required: true)] + public int MaxFillLevels; + + [DataField("fillBaseName", required: true)] + public string FillBaseName = default!; +} + +[Serializable, NetSerializable] +public enum StorageFillVisuals : byte +{ + FillLevel +} + +[Serializable, NetSerializable] +public enum StorageFillLayers : byte +{ + Fill +} diff --git a/Resources/Prototypes/Entities/Objects/Specific/Janitorial/trashbag.yml b/Resources/Prototypes/Entities/Objects/Specific/Janitorial/trashbag.yml index 35de6f531c..2d17ece501 100644 --- a/Resources/Prototypes/Entities/Objects/Specific/Janitorial/trashbag.yml +++ b/Resources/Prototypes/Entities/Objects/Specific/Janitorial/trashbag.yml @@ -4,8 +4,11 @@ parent: BaseItem components: - type: Sprite + netSync: false sprite: Objects/Specific/Janitorial/trashbag.rsi - state: icon-3 + layers: + - state: icon-0 + map: ["enum.StorageFillLayers.Fill"] - type: Item sprite: Objects/Specific/Janitorial/trashbag.rsi size: 125 @@ -23,6 +26,10 @@ tags: - TrashBag - DroneUsable + - type: Appearance + - type: StorageFillVisualizer + maxFillLevels: 4 + fillBaseName: icon - type: entity name: trash bag @@ -30,21 +37,19 @@ parent: TrashBag components: - type: Sprite - state: blue-icon-3 + layers: + - state: blue-icon-0 + map: ["enum.StorageFillLayers.Fill"] - type: Item HeldPrefix: blue + - type: StorageFillVisualizer + fillBaseName: blue-icon - type: entity name: spell of all-consuming cleanliness id: BagOfSummoningGarbage - parent: BaseItem + parent: TrashBagBlue components: - - type: Sprite - sprite: Objects/Specific/Janitorial/trashbag.rsi - state: blue-icon-3 - - type: Item - sprite: Objects/Specific/Janitorial/trashbag.rsi - HeldPrefix: blue - type: Storage capacity: 125000 quickInsert: true