diff --git a/Content.Client/UserInterface/Systems/Storage/Controls/StorageContainer.cs b/Content.Client/UserInterface/Systems/Storage/Controls/StorageContainer.cs index 8dfe2fff63..53a820edaa 100644 --- a/Content.Client/UserInterface/Systems/Storage/Controls/StorageContainer.cs +++ b/Content.Client/UserInterface/Systems/Storage/Controls/StorageContainer.cs @@ -267,16 +267,14 @@ public sealed class StorageContainer : BaseWindow var currentPosition = new Vector2i(x, y); - foreach (var item in storageComp.StoredItems) + foreach (var (itemEnt, itemPos) in storageComp.StoredItems) { - if (item.Value.Position != currentPosition) + if (itemPos.Position != currentPosition) continue; - var itemEnt = _entity.GetEntity(item.Key); - if (_entity.TryGetComponent(itemEnt, out var itemEntComponent)) { - var gridPiece = new ItemGridPiece((itemEnt, itemEntComponent), item.Value, _entity) + var gridPiece = new ItemGridPiece((itemEnt, itemEntComponent), itemPos, _entity) { MinSize = size, Marked = itemEnt == lastEntity diff --git a/Content.Shared/Storage/EntitySystems/SharedStorageSystem.cs b/Content.Shared/Storage/EntitySystems/SharedStorageSystem.cs index 17eb30ad50..19c1748ec7 100644 --- a/Content.Shared/Storage/EntitySystems/SharedStorageSystem.cs +++ b/Content.Shared/Storage/EntitySystems/SharedStorageSystem.cs @@ -19,29 +19,31 @@ using Content.Shared.Timing; using Content.Shared.Verbs; using Robust.Shared.Audio.Systems; using Robust.Shared.Containers; +using Robust.Shared.GameStates; using Robust.Shared.Map; using Robust.Shared.Prototypes; using Robust.Shared.Random; +using Robust.Shared.Serialization; namespace Content.Shared.Storage.EntitySystems; public abstract class SharedStorageSystem : EntitySystem { - [Dependency] private readonly IPrototypeManager _prototype = default!; + [Dependency] private readonly IPrototypeManager _prototype = default!; [Dependency] protected readonly IRobustRandom Random = default!; + [Dependency] protected readonly ActionBlockerSystem ActionBlocker = default!; + [Dependency] private readonly EntityLookupSystem _entityLookupSystem = default!; + [Dependency] private readonly SharedAppearanceSystem _appearance = default!; + [Dependency] protected readonly SharedAudioSystem Audio = default!; [Dependency] private readonly SharedContainerSystem _containerSystem = default!; [Dependency] private readonly SharedDoAfterSystem _doAfterSystem = default!; - [Dependency] private readonly EntityLookupSystem _entityLookupSystem = default!; [Dependency] protected readonly SharedEntityStorageSystem EntityStorage = default!; [Dependency] private readonly SharedInteractionSystem _interactionSystem = default!; [Dependency] protected readonly SharedItemSystem ItemSystem = default!; [Dependency] private readonly SharedPopupSystem _popupSystem = default!; [Dependency] private readonly SharedHandsSystem _sharedHandsSystem = default!; - [Dependency] protected readonly ActionBlockerSystem ActionBlocker = default!; - [Dependency] private readonly SharedAppearanceSystem _appearance = default!; - [Dependency] protected readonly SharedAudioSystem Audio = default!; - [Dependency] protected readonly SharedTransformSystem TransformSystem = default!; [Dependency] private readonly SharedStackSystem _stack = default!; + [Dependency] protected readonly SharedTransformSystem TransformSystem = default!; [Dependency] private readonly SharedUserInterfaceSystem _ui = default!; [Dependency] protected readonly UseDelaySystem UseDelay = default!; @@ -69,6 +71,8 @@ public abstract class SharedStorageSystem : EntitySystem _xformQuery = GetEntityQuery(); _prototype.PrototypesReloaded += OnPrototypesReloaded; + SubscribeLocalEvent(OnStorageGetState); + SubscribeLocalEvent(OnStorageHandleState); SubscribeLocalEvent(OnComponentInit, before: new[] { typeof(SharedContainerSystem) }); SubscribeLocalEvent>(AddTransferVerbs); SubscribeLocalEvent(OnInteractUsing, after: new[] { typeof(ItemSlotsSystem) }); @@ -92,6 +96,43 @@ public abstract class SharedStorageSystem : EntitySystem UpdatePrototypeCache(); } + private void OnStorageGetState(EntityUid uid, StorageComponent component, ref ComponentGetState args) + { + var storedItems = new Dictionary(); + + foreach (var (ent, location) in component.StoredItems) + { + storedItems[GetNetEntity(ent)] = location; + } + + args.State = new StorageComponentState() + { + Grid = component.Grid, + IsUiOpen = component.IsUiOpen, + MaxItemSize = component.MaxItemSize, + StoredItems = storedItems + }; + } + + 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.IsUiOpen = state.IsUiOpen; + component.MaxItemSize = state.MaxItemSize; + + component.StoredItems.Clear(); + + foreach (var (nent, location) in state.StoredItems) + { + var ent = EnsureEntity(nent, uid); + component.StoredItems[ent] = location; + } + } + public override void Shutdown() { _prototype.PrototypesReloaded -= OnPrototypesReloaded; @@ -497,7 +538,7 @@ public abstract class SharedStorageSystem : EntitySystem if (args.Container.ID != StorageComponent.ContainerId) return; - if (!entity.Comp.StoredItems.ContainsKey(GetNetEntity(args.Entity))) + if (!entity.Comp.StoredItems.ContainsKey(args.Entity)) { if (!TryGetAvailableGridSpace((entity.Owner, entity.Comp), (args.Entity, null), out var location)) { @@ -505,7 +546,7 @@ public abstract class SharedStorageSystem : EntitySystem return; } - entity.Comp.StoredItems[GetNetEntity(args.Entity)] = location.Value; + entity.Comp.StoredItems[args.Entity] = location.Value; Dirty(entity, entity.Comp); } @@ -522,7 +563,7 @@ public abstract class SharedStorageSystem : EntitySystem if (args.Container.ID != StorageComponent.ContainerId) return; - entity.Comp.StoredItems.Remove(GetNetEntity(args.Entity)); + entity.Comp.StoredItems.Remove(args.Entity); Dirty(entity, entity.Comp); UpdateAppearance((entity, entity.Comp, null)); @@ -655,7 +696,7 @@ public abstract class SharedStorageSystem : EntitySystem return false; } - if (!ignoreLocation && !storageComp.StoredItems.ContainsKey(GetNetEntity(insertEnt))) + if (!ignoreLocation && !storageComp.StoredItems.ContainsKey(insertEnt)) { if (!TryGetAvailableGridSpace((uid, storageComp), (insertEnt, item), out _)) { @@ -698,7 +739,7 @@ public abstract class SharedStorageSystem : EntitySystem if (!ItemFitsInGridLocation(insertEnt, uid, location)) return false; - uid.Comp.StoredItems[GetNetEntity(insertEnt)] = location; + uid.Comp.StoredItems[insertEnt] = location; Dirty(uid, uid.Comp); if (Insert(uid, @@ -713,7 +754,7 @@ public abstract class SharedStorageSystem : EntitySystem return true; } - uid.Comp.StoredItems.Remove(GetNetEntity(insertEnt)); + uid.Comp.StoredItems.Remove(insertEnt); return false; } @@ -869,7 +910,7 @@ public abstract class SharedStorageSystem : EntitySystem if (!ItemFitsInGridLocation(itemEnt, storageEnt, location.Position, location.Rotation)) return false; - storageEnt.Comp.StoredItems[GetNetEntity(itemEnt)] = location; + storageEnt.Comp.StoredItems[itemEnt] = location; Dirty(storageEnt, storageEnt.Comp); return true; } @@ -997,10 +1038,8 @@ public abstract class SharedStorageSystem : EntitySystem if (!validGrid) return false; - foreach (var (netEnt, storedItem) in storageEnt.Comp.StoredItems) + foreach (var (ent, storedItem) in storageEnt.Comp.StoredItems) { - var ent = GetEntity(netEnt); - if (ent == itemEnt.Owner) continue; @@ -1102,4 +1141,16 @@ public abstract class SharedStorageSystem : EntitySystem /// public abstract void PlayPickupAnimation(EntityUid uid, EntityCoordinates initialCoordinates, EntityCoordinates finalCoordinates, Angle initialRotation, EntityUid? user = null); + + [Serializable, NetSerializable] + protected sealed class StorageComponentState : ComponentState + { + public bool IsUiOpen; + + public Dictionary StoredItems = new(); + + public List Grid = new(); + + public ProtoId? MaxItemSize; + } } diff --git a/Content.Shared/Storage/StorageComponent.cs b/Content.Shared/Storage/StorageComponent.cs index 796c9cb5ff..fa06e333e8 100644 --- a/Content.Shared/Storage/StorageComponent.cs +++ b/Content.Shared/Storage/StorageComponent.cs @@ -14,13 +14,13 @@ namespace Content.Shared.Storage /// /// Handles generic storage with window, such as backpacks. /// - [RegisterComponent, NetworkedComponent, AutoGenerateComponentState] + [RegisterComponent, NetworkedComponent] public sealed partial class StorageComponent : Component { public static string ContainerId = "storagebase"; // TODO: This fucking sucks - [ViewVariables(VVAccess.ReadWrite), DataField("isOpen"), AutoNetworkedField] + [ViewVariables(VVAccess.ReadWrite), DataField] public bool IsUiOpen; [ViewVariables] @@ -29,69 +29,69 @@ namespace Content.Shared.Storage /// /// A dictionary storing each entity to its position within the storage grid. /// - [DataField, ViewVariables(VVAccess.ReadWrite), AutoNetworkedField] - public Dictionary StoredItems = new(); + [DataField, ViewVariables(VVAccess.ReadWrite)] + public Dictionary StoredItems = new(); /// /// A list of boxes that comprise a combined grid that determines the location that items can be stored. /// - [DataField, ViewVariables(VVAccess.ReadWrite), AutoNetworkedField] + [DataField, ViewVariables(VVAccess.ReadWrite)] public List Grid = new(); /// /// The maximum size item that can be inserted into this storage, /// - [DataField, ViewVariables(VVAccess.ReadWrite), AutoNetworkedField] + [DataField, ViewVariables(VVAccess.ReadWrite)] [Access(typeof(SharedStorageSystem))] public ProtoId? MaxItemSize; // TODO: Make area insert its own component. - [DataField("quickInsert")] + [DataField] public bool QuickInsert; // Can insert storables by "attacking" them with the storage entity - [DataField("clickInsert")] + [DataField] public bool ClickInsert = true; // Can insert stuff by clicking the storage entity with it - [DataField("areaInsert")] + [DataField] public bool AreaInsert; // "Attacking" with the storage entity causes it to insert all nearby storables after a delay - [DataField("areaInsertRadius")] + [DataField] public int AreaInsertRadius = 1; /// /// Whitelist for entities that can go into the storage. /// - [DataField("whitelist")] + [DataField] public EntityWhitelist? Whitelist; /// /// Blacklist for entities that can go into storage. /// - [DataField("blacklist")] + [DataField] public EntityWhitelist? Blacklist; /// /// Sound played whenever an entity is inserted into storage. /// - [DataField("storageInsertSound")] + [DataField] public SoundSpecifier? StorageInsertSound = new SoundCollectionSpecifier("storageRustle"); /// /// Sound played whenever an entity is removed from storage. /// - [DataField("storageRemoveSound")] + [DataField] public SoundSpecifier? StorageRemoveSound; /// /// Sound played whenever the storage window is opened. /// - [DataField("storageOpenSound")] + [DataField] public SoundSpecifier? StorageOpenSound = new SoundCollectionSpecifier("storageRustle"); /// /// Sound played whenever the storage window is closed. /// - [DataField("storageCloseSound")] + [DataField] public SoundSpecifier? StorageCloseSound; /// @@ -103,7 +103,7 @@ namespace Content.Shared.Storage public StorageDefaultOrientation? DefaultStorageOrientation; [Serializable, NetSerializable] - public enum StorageUiKey + public enum StorageUiKey : byte { Key, }