]> git.smokeofanarchy.ru Git - space-station-14.git/commitdiff
cleanup EntityStorageSystem (#40163)
authorslarticodefast <161409025+slarticodefast@users.noreply.github.com>
Tue, 2 Dec 2025 18:33:40 +0000 (19:33 +0100)
committerGitHub <noreply@github.com>
Tue, 2 Dec 2025 18:33:40 +0000 (18:33 +0000)
Content.Client/Storage/Systems/EntityStorageSystem.cs
Content.Server/Storage/EntitySystems/EntityStorageSystem.cs
Content.Shared/Storage/Components/EntityStorageComponent.cs
Content.Shared/Storage/Components/InsideEntityStorageComponent.cs
Content.Shared/Storage/EntitySystems/SharedEntityStorageSystem.cs

index ca2b986667e6c298f457e60b1ebccc833edbce9e..96dc353c4815e258fbf9aeabeb9fcdf01d0b2d50 100644 (file)
@@ -1,43 +1,5 @@
-using System.Diagnostics.CodeAnalysis;
-using Content.Client.Storage.Components;
-using Content.Shared.Destructible;
-using Content.Shared.Foldable;
-using Content.Shared.Interaction;
-using Content.Shared.Lock;
-using Content.Shared.Movement.Events;
-using Content.Shared.Storage.Components;
-using Content.Shared.Storage.EntitySystems;
-using Content.Shared.Verbs;
-using Robust.Shared.GameStates;
+using Content.Shared.Storage.EntitySystems;
 
 namespace Content.Client.Storage.Systems;
 
-public sealed class EntityStorageSystem : SharedEntityStorageSystem
-{
-    public override void Initialize()
-    {
-        base.Initialize();
-        SubscribeLocalEvent<EntityStorageComponent, EntityUnpausedEvent>(OnEntityUnpausedEvent);
-        SubscribeLocalEvent<EntityStorageComponent, ComponentInit>(OnComponentInit);
-        SubscribeLocalEvent<EntityStorageComponent, ComponentStartup>(OnComponentStartup);
-        SubscribeLocalEvent<EntityStorageComponent, ActivateInWorldEvent>(OnInteract, after: new[] { typeof(LockSystem) });
-        SubscribeLocalEvent<EntityStorageComponent, LockToggleAttemptEvent>(OnLockToggleAttempt);
-        SubscribeLocalEvent<EntityStorageComponent, DestructionEventArgs>(OnDestruction);
-        SubscribeLocalEvent<EntityStorageComponent, GetVerbsEvent<InteractionVerb>>(AddToggleOpenVerb);
-        SubscribeLocalEvent<EntityStorageComponent, ContainerRelayMovementEntityEvent>(OnRelayMovement);
-        SubscribeLocalEvent<EntityStorageComponent, FoldAttemptEvent>(OnFoldAttempt);
-
-        SubscribeLocalEvent<EntityStorageComponent, ComponentGetState>(OnGetState);
-        SubscribeLocalEvent<EntityStorageComponent, ComponentHandleState>(OnHandleState);
-    }
-
-    public override bool ResolveStorage(EntityUid uid, [NotNullWhen(true)] ref EntityStorageComponent? component)
-    {
-        if (component != null)
-            return true;
-
-        TryComp<EntityStorageComponent>(uid, out var storage);
-        component = storage;
-        return component != null;
-    }
-}
+public sealed class EntityStorageSystem : SharedEntityStorageSystem;
index c38a3e9b1756c0a25bba26cb4133597220716440..e22a4f5d7ec38e84856f3c9d9a37376fb8570535 100644 (file)
@@ -1,22 +1,10 @@
-using System.Diagnostics.CodeAnalysis;
 using Content.Server.Atmos.EntitySystems;
 using Content.Server.Body.Systems;
 using Content.Server.Construction;
 using Content.Server.Construction.Components;
-using Content.Server.Storage.Components;
-using Content.Shared.Destructible;
-using Content.Shared.Explosion;
-using Content.Shared.Foldable;
-using Content.Shared.Interaction;
-using Content.Shared.Lock;
-using Content.Shared.Movement.Events;
 using Content.Shared.Storage.Components;
 using Content.Shared.Storage.EntitySystems;
-using Content.Shared.Tools.Systems;
-using Content.Shared.Verbs;
 using Robust.Server.GameObjects;
-using Robust.Shared.Containers;
-using Robust.Shared.GameStates;
 using Robust.Shared.Map;
 
 namespace Content.Server.Storage.EntitySystems;
@@ -32,30 +20,11 @@ public sealed class EntityStorageSystem : SharedEntityStorageSystem
     {
         base.Initialize();
 
-        /* CompRef things */
-        SubscribeLocalEvent<EntityStorageComponent, EntityUnpausedEvent>(OnEntityUnpausedEvent);
-        SubscribeLocalEvent<EntityStorageComponent, ComponentInit>(OnComponentInit);
-        SubscribeLocalEvent<EntityStorageComponent, ComponentStartup>(OnComponentStartup);
-        SubscribeLocalEvent<EntityStorageComponent, ActivateInWorldEvent>(OnInteract, after: new[] { typeof(LockSystem) });
-        SubscribeLocalEvent<EntityStorageComponent, LockToggleAttemptEvent>(OnLockToggleAttempt);
-        SubscribeLocalEvent<EntityStorageComponent, DestructionEventArgs>(OnDestruction);
-        SubscribeLocalEvent<EntityStorageComponent, GetVerbsEvent<InteractionVerb>>(AddToggleOpenVerb);
-        SubscribeLocalEvent<EntityStorageComponent, ContainerRelayMovementEntityEvent>(OnRelayMovement);
-        SubscribeLocalEvent<EntityStorageComponent, FoldAttemptEvent>(OnFoldAttempt);
-
-        SubscribeLocalEvent<EntityStorageComponent, ComponentGetState>(OnGetState);
-        SubscribeLocalEvent<EntityStorageComponent, ComponentHandleState>(OnHandleState);
-        /* CompRef things */
-
         SubscribeLocalEvent<EntityStorageComponent, MapInitEvent>(OnMapInit);
-        SubscribeLocalEvent<EntityStorageComponent, WeldableAttemptEvent>(OnWeldableAttempt);
-        SubscribeLocalEvent<EntityStorageComponent, BeforeExplodeEvent>(OnExploded);
 
         SubscribeLocalEvent<InsideEntityStorageComponent, InhaleLocationEvent>(OnInsideInhale);
         SubscribeLocalEvent<InsideEntityStorageComponent, ExhaleLocationEvent>(OnInsideExhale);
         SubscribeLocalEvent<InsideEntityStorageComponent, AtmosExposedGetAirEvent>(OnInsideExposed);
-
-        SubscribeLocalEvent<InsideEntityStorageComponent, EntGotRemovedFromContainerMessage>(OnRemoved);
     }
 
     private void OnMapInit(EntityUid uid, EntityStorageComponent component, MapInitEvent args)
@@ -76,64 +45,30 @@ public sealed class EntityStorageSystem : SharedEntityStorageSystem
             _construction.AddContainer(uid, ContainerName, construction);
     }
 
-    public override bool ResolveStorage(EntityUid uid, [NotNullWhen(true)] ref EntityStorageComponent? component)
-    {
-        if (component != null)
-            return true;
-
-        TryComp<EntityStorageComponent>(uid, out var storage);
-        component = storage;
-        return component != null;
-    }
-
-    private void OnWeldableAttempt(EntityUid uid, EntityStorageComponent component, WeldableAttemptEvent args)
-    {
-        if (component.Open)
-        {
-            args.Cancel();
-            return;
-        }
-
-        if (component.Contents.Contains(args.User))
-        {
-            var msg = Loc.GetString("entity-storage-component-already-contains-user-message");
-            Popup.PopupEntity(msg, args.User, args.User);
-            args.Cancel();
-        }
-    }
-
-    private void OnExploded(Entity<EntityStorageComponent> ent, ref BeforeExplodeEvent args)
-    {
-        args.Contents.AddRange(ent.Comp.Contents.ContainedEntities);
-    }
-
     protected override void TakeGas(EntityUid uid, EntityStorageComponent component)
     {
         if (!component.Airtight)
             return;
 
-        var serverComp = (EntityStorageComponent) component;
-        var tile = GetOffsetTileRef(uid, serverComp);
+        var tile = GetOffsetTileRef(uid, component);
 
-        if (tile != null && _atmos.GetTileMixture(tile.Value.GridUid, null, tile.Value.GridIndices, true) is {} environment)
+        if (tile != null && _atmos.GetTileMixture(tile.Value.GridUid, null, tile.Value.GridIndices, true) is { } environment)
         {
-            _atmos.Merge(serverComp.Air, environment.RemoveVolume(serverComp.Air.Volume));
+            _atmos.Merge(component.Air, environment.RemoveVolume(component.Air.Volume));
         }
     }
 
     public override void ReleaseGas(EntityUid uid, EntityStorageComponent component)
     {
-        var serverComp = (EntityStorageComponent) component;
-
-        if (!serverComp.Airtight)
+        if (!component.Airtight)
             return;
 
-        var tile = GetOffsetTileRef(uid, serverComp);
+        var tile = GetOffsetTileRef(uid, component);
 
-        if (tile != null && _atmos.GetTileMixture(tile.Value.GridUid, null, tile.Value.GridIndices, true) is {} environment)
+        if (tile != null && _atmos.GetTileMixture(tile.Value.GridUid, null, tile.Value.GridIndices, true) is { } environment)
         {
-            _atmos.Merge(environment, serverComp.Air);
-            serverComp.Air.Clear();
+            _atmos.Merge(environment, component.Air);
+            component.Air.Clear();
         }
     }
 
@@ -149,13 +84,6 @@ public sealed class EntityStorageSystem : SharedEntityStorageSystem
         return null;
     }
 
-    private void OnRemoved(EntityUid uid, InsideEntityStorageComponent component, EntGotRemovedFromContainerMessage args)
-    {
-        if (args.Container.Owner != component.Storage)
-            return;
-        RemComp(uid, component);
-    }
-
     #region Gas mix event handlers
 
     private void OnInsideInhale(EntityUid uid, InsideEntityStorageComponent component, InhaleLocationEvent args)
index 009083b2d86274b3e12879b31993fb8937885e9b..ecfcccc45b7723b2149dfce3195e60394435d766 100644 (file)
@@ -5,42 +5,61 @@ using Content.Shared.Whitelist;
 using Robust.Shared.Audio;
 using Robust.Shared.Containers;
 using Robust.Shared.GameStates;
-using Robust.Shared.Serialization;
 
 namespace Content.Shared.Storage.Components;
 
+/// <summary>
+/// A storage component that stores nearby entities in a container when this object is opened or closed.
+/// This does not have an UI like grid storage, but just makes them disappear inside.
+/// Used for lockers, crates etc.
+/// </summary>
 [RegisterComponent, NetworkedComponent]
+[AutoGenerateComponentState, AutoGenerateComponentPause] // TODO: Field deltas
 public sealed partial class EntityStorageComponent : Component, IGasMixtureHolder
 {
-    public readonly float MaxSize = 1.0f; // maximum width or height of an entity allowed inside the storage.
+    /// <summary>
+    /// Maximum width or height of an entity allowed inside the storage.
+    /// </summary>
+    [DataField, AutoNetworkedField]
+    public float MaxSize = 1.0f;
+
+    /// <summary>
+    /// The delay between opening attempts when stuck inside an entity storage.
+    /// </summary>
+    [DataField, AutoNetworkedField]
+    public TimeSpan InternalOpenAttemptDelay = TimeSpan.FromSeconds(0.5);
 
-    public static readonly TimeSpan InternalOpenAttemptDelay = TimeSpan.FromSeconds(0.5);
+    /// <summary>
+    /// The next time a player stuck inside the entity storage can attempt to open it from inside.
+    /// </summary>
+    [DataField, AutoNetworkedField, AutoPausedField]
     public TimeSpan NextInternalOpenAttempt;
 
     /// <summary>
-    ///     Collision masks that get removed when the storage gets opened.
+    /// Collision masks that get removed when the storage gets opened.
     /// </summary>
-    public readonly int MasksToRemove = (int)(
+    [DataField]
+    public int MasksToRemove = (int)(
         CollisionGroup.MidImpassable |
         CollisionGroup.HighImpassable |
         CollisionGroup.LowImpassable);
 
     /// <summary>
-    ///     Collision masks that were removed from ANY layer when the storage was opened;
+    /// Collision masks that were removed from ANY layer when the storage was opened;
     /// </summary>
     [DataField]
     public int RemovedMasks;
 
     /// <summary>
-    /// The total amount of items that can fit in one entitystorage
+    /// The total amount of items that can fit in one entitystorage.
     /// </summary>
-    [DataField]
+    [DataField, AutoNetworkedField]
     public int Capacity = 30;
 
     /// <summary>
-    /// Whether or not the entity still has collision when open
+    /// Whether or not the entity still has collision when open.
     /// </summary>
-    [DataField]
+    [DataField, AutoNetworkedField]
     public bool IsCollidableWhenOpen;
 
     /// <summary>
@@ -48,7 +67,7 @@ public sealed partial class EntityStorageComponent : Component, IGasMixtureHolde
     /// If false, it prevents the storage from opening when the entity inside of it moves.
     /// This is for objects that you want the player to move while inside, like large cardboard boxes, without opening the storage.
     /// </summary>
-    [DataField]
+    [DataField, AutoNetworkedField]
     public bool OpenOnMove = true;
 
     //The offset for where items are emptied/vacuumed for the EntityStorage.
@@ -60,62 +79,62 @@ public sealed partial class EntityStorageComponent : Component, IGasMixtureHolde
     public CollisionGroup EnteringOffsetCollisionFlags = CollisionGroup.Impassable | CollisionGroup.MidImpassable;
 
     /// <summary>
-    /// How close you have to be to the "entering" spot to be able to enter
+    /// How close you have to be to the "entering" spot to be able to enter.
     /// </summary>
-    [DataField]
+    [DataField, AutoNetworkedField]
     public float EnteringRange = 0.18f;
 
     /// <summary>
-    /// Whether or not to show the contents when the storage is closed
+    /// Whether or not to show the contents when the storage is closed.
     /// </summary>
     [DataField]
     public bool ShowContents;
 
     /// <summary>
-    /// Whether or not light is occluded by the storage
+    /// Whether or not light is occluded by the storage.
     /// </summary>
     [DataField]
     public bool OccludesLight = true;
 
     /// <summary>
-    /// Whether or not all the contents stored should be deleted with the entitystorage
+    /// Whether or not all the contents stored should be deleted with the entitystorage.
     /// </summary>
     [DataField]
     public bool DeleteContentsOnDestruction;
 
     /// <summary>
-    /// Whether or not the container is sealed and traps air inside of it
+    /// Whether or not the container is sealed and traps air inside of it.
     /// </summary>
     [DataField]
     public bool Airtight = true;
 
     /// <summary>
-    /// Whether or not the entitystorage is open or closed
+    /// Whether or not the entitystorage is open or closed.
     /// </summary>
-    [DataField]
+    [DataField, AutoNetworkedField]
     public bool Open;
 
     /// <summary>
-    /// The sound made when closed
+    /// The sound made when closed.
     /// </summary>
     [DataField]
     public SoundSpecifier CloseSound = new SoundPathSpecifier("/Audio/Effects/closetclose.ogg");
 
     /// <summary>
-    /// The sound made when open
+    /// The sound made when opened.
     /// </summary>
     [DataField]
     public SoundSpecifier OpenSound = new SoundPathSpecifier("/Audio/Effects/closetopen.ogg");
 
     /// <summary>
-    ///     Whitelist for what entities are allowed to be inserted into this container. If this is not null, the
-    ///     standard requirement that the entity must be an item or mob is waived.
+    /// Whitelist for what entities are allowed to be inserted into this container. If this is not null, the
+    /// standard requirement that the entity must be an item or mob is waived.
     /// </summary>
     [DataField]
     public EntityWhitelist? Whitelist;
 
     /// <summary>
-    /// The contents of the storage
+    /// The contents of the storage.
     /// </summary>
     [ViewVariables]
     public Container Contents = default!;
@@ -128,32 +147,6 @@ public sealed partial class EntityStorageComponent : Component, IGasMixtureHolde
     public GasMixture Air { get; set; } = new(200);
 }
 
-[Serializable, NetSerializable]
-public sealed class EntityStorageComponentState : ComponentState
-{
-    public bool Open;
-
-    public int Capacity;
-
-    public bool IsCollidableWhenOpen;
-
-    public bool OpenOnMove;
-
-    public float EnteringRange;
-
-    public TimeSpan NextInternalOpenAttempt;
-
-    public EntityStorageComponentState(bool open, int capacity, bool isCollidableWhenOpen, bool openOnMove, float enteringRange, TimeSpan nextInternalOpenAttempt)
-    {
-        Open = open;
-        Capacity = capacity;
-        IsCollidableWhenOpen = isCollidableWhenOpen;
-        OpenOnMove = openOnMove;
-        EnteringRange = enteringRange;
-        NextInternalOpenAttempt = nextInternalOpenAttempt;
-    }
-}
-
 /// <summary>
 /// Raised on the entity being inserted whenever checking if an entity can be inserted into an entity storage.
 /// </summary>
index 258ea07ec65fd1f65ea79c0389073bbf28309091..8d0b45a4a2520dea955a9a05682286b710722279 100644 (file)
@@ -1,10 +1,16 @@
-namespace Content.Shared.Storage.Components;
+using Robust.Shared.GameStates;
+
+namespace Content.Shared.Storage.Components;
 
 /// <summary>
-///     Added to entities contained within entity storage, for directed event purposes.
+/// Added to entities contained within entity storage, for directed event purposes.
 /// </summary>
-[RegisterComponent]
+[RegisterComponent, NetworkedComponent, AutoGenerateComponentState]
 public sealed partial class InsideEntityStorageComponent : Component
 {
+    /// <summary>
+    /// The entity storage this entity is inside.
+    /// </summary>
+    [DataField, AutoNetworkedField]
     public EntityUid Storage;
 }
index dd6f1a223e8afe01e3b3395c677f4eed7a7acab1..93a534843a0983b63e760e83b249e4079e6f0c44 100644 (file)
@@ -1,10 +1,9 @@
-using System.Diagnostics.CodeAnalysis;
 using System.Linq;
 using System.Numerics;
-using Content.Shared.Body.Components;
 using Content.Shared.Destructible;
 using Content.Shared.Foldable;
 using Content.Shared.Hands.Components;
+using Content.Shared.Explosion;
 using Content.Shared.Interaction;
 using Content.Shared.Item;
 using Content.Shared.Lock;
@@ -19,7 +18,6 @@ using Content.Shared.ActionBlocker;
 using Content.Shared.Mobs.Components;
 using Robust.Shared.Audio.Systems;
 using Robust.Shared.Containers;
-using Robust.Shared.GameStates;
 using Robust.Shared.Map;
 using Robust.Shared.Network;
 using Robust.Shared.Physics;
@@ -48,31 +46,23 @@ public abstract class SharedEntityStorageSystem : EntitySystem
 
     public const string ContainerName = "entity_storage";
 
-    protected void OnEntityUnpausedEvent(EntityUid uid, EntityStorageComponent component, EntityUnpausedEvent args)
+    public override void Initialize()
     {
-        component.NextInternalOpenAttempt += args.PausedTime;
-    }
+        base.Initialize();
 
-    protected void OnGetState(EntityUid uid, EntityStorageComponent component, ref ComponentGetState args)
-    {
-        args.State = new EntityStorageComponentState(component.Open,
-            component.Capacity,
-            component.IsCollidableWhenOpen,
-            component.OpenOnMove,
-            component.EnteringRange,
-            component.NextInternalOpenAttempt);
-    }
+        SubscribeLocalEvent<EntityStorageComponent, ComponentInit>(OnComponentInit);
+        SubscribeLocalEvent<EntityStorageComponent, ComponentStartup>(OnComponentStartup);
+        SubscribeLocalEvent<EntityStorageComponent, ActivateInWorldEvent>(OnInteract, after: new[] { typeof(LockSystem) });
+        SubscribeLocalEvent<EntityStorageComponent, LockToggleAttemptEvent>(OnLockToggleAttempt);
+        SubscribeLocalEvent<EntityStorageComponent, DestructionEventArgs>(OnDestruction);
+        SubscribeLocalEvent<EntityStorageComponent, GetVerbsEvent<InteractionVerb>>(AddToggleOpenVerb);
+        SubscribeLocalEvent<EntityStorageComponent, ContainerRelayMovementEntityEvent>(OnRelayMovement);
+        SubscribeLocalEvent<EntityStorageComponent, FoldAttemptEvent>(OnFoldAttempt);
 
-    protected void OnHandleState(EntityUid uid, EntityStorageComponent component, ref ComponentHandleState args)
-    {
-        if (args.Current is not EntityStorageComponentState state)
-            return;
-        component.Open = state.Open;
-        component.Capacity = state.Capacity;
-        component.IsCollidableWhenOpen = state.IsCollidableWhenOpen;
-        component.OpenOnMove = state.OpenOnMove;
-        component.EnteringRange = state.EnteringRange;
-        component.NextInternalOpenAttempt = state.NextInternalOpenAttempt;
+        SubscribeLocalEvent<EntityStorageComponent, WeldableAttemptEvent>(OnWeldableAttempt);
+        SubscribeLocalEvent<EntityStorageComponent, BeforeExplodeEvent>(OnExploded);
+
+        SubscribeLocalEvent<InsideEntityStorageComponent, EntGotRemovedFromContainerMessage>(OnRemoved);
     }
 
     protected virtual void OnComponentInit(EntityUid uid, EntityStorageComponent component, ComponentInit args)
@@ -82,12 +72,12 @@ public abstract class SharedEntityStorageSystem : EntitySystem
         component.Contents.OccludesLight = component.OccludesLight;
     }
 
-    protected virtual void OnComponentStartup(EntityUid uid, EntityStorageComponent component, ComponentStartup args)
+    private void OnComponentStartup(EntityUid uid, EntityStorageComponent component, ComponentStartup args)
     {
         _appearance.SetData(uid, StorageVisuals.Open, component.Open);
     }
 
-    protected void OnInteract(EntityUid uid, EntityStorageComponent component, ActivateInWorldEvent args)
+    private void OnInteract(EntityUid uid, EntityStorageComponent component, ActivateInWorldEvent args)
     {
         if (args.Handled || !args.Complex)
             return;
@@ -96,9 +86,7 @@ public abstract class SharedEntityStorageSystem : EntitySystem
         ToggleOpen(args.User, uid, component);
     }
 
-    public abstract bool ResolveStorage(EntityUid uid, [NotNullWhen(true)] ref EntityStorageComponent? component);
-
-    protected void OnLockToggleAttempt(EntityUid uid, EntityStorageComponent target, ref LockToggleAttemptEvent args)
+    private void OnLockToggleAttempt(EntityUid uid, EntityStorageComponent target, ref LockToggleAttemptEvent args)
     {
         // Cannot (un)lock open lockers.
         if (target.Open)
@@ -109,7 +97,7 @@ public abstract class SharedEntityStorageSystem : EntitySystem
             args.Cancelled = true;
     }
 
-    protected void OnDestruction(EntityUid uid, EntityStorageComponent component, DestructionEventArgs args)
+    private void OnDestruction(EntityUid uid, EntityStorageComponent component, DestructionEventArgs args)
     {
         component.Open = true;
         Dirty(uid, component);
@@ -125,7 +113,7 @@ public abstract class SharedEntityStorageSystem : EntitySystem
         }
     }
 
-    protected void OnRelayMovement(EntityUid uid, EntityStorageComponent component, ref ContainerRelayMovementEntityEvent args)
+    private void OnRelayMovement(EntityUid uid, EntityStorageComponent component, ref ContainerRelayMovementEntityEvent args)
     {
         if (!HasComp<HandsComponent>(args.Entity))
             return;
@@ -136,21 +124,54 @@ public abstract class SharedEntityStorageSystem : EntitySystem
         if (_timing.CurTime < component.NextInternalOpenAttempt)
             return;
 
-        component.NextInternalOpenAttempt = _timing.CurTime + EntityStorageComponent.InternalOpenAttemptDelay;
+        component.NextInternalOpenAttempt = _timing.CurTime + component.InternalOpenAttemptDelay;
         Dirty(uid, component);
 
         if (component.OpenOnMove)
             TryOpenStorage(args.Entity, uid);
     }
 
-    protected void OnFoldAttempt(EntityUid uid, EntityStorageComponent component, ref FoldAttemptEvent args)
+    private void OnFoldAttempt(EntityUid uid, EntityStorageComponent component, ref FoldAttemptEvent args)
     {
         if (args.Cancelled)
             return;
+
         args.Cancelled = component.Open || component.Contents.ContainedEntities.Count != 0;
     }
 
-    protected void AddToggleOpenVerb(EntityUid uid, EntityStorageComponent component, GetVerbsEvent<InteractionVerb> args)
+    private void OnWeldableAttempt(EntityUid uid, EntityStorageComponent component, WeldableAttemptEvent args)
+    {
+        if (component.Open)
+        {
+            args.Cancel();
+            return;
+        }
+
+        if (component.Contents.Contains(args.User))
+        {
+            var msg = Loc.GetString("entity-storage-component-already-contains-user-message");
+            Popup.PopupEntity(msg, args.User, args.User);
+            args.Cancel();
+        }
+    }
+
+    private void OnExploded(Entity<EntityStorageComponent> ent, ref BeforeExplodeEvent args)
+    {
+        args.Contents.AddRange(ent.Comp.Contents.ContainedEntities);
+    }
+
+    private void OnRemoved(EntityUid uid, InsideEntityStorageComponent component, EntGotRemovedFromContainerMessage args)
+    {
+        if (_timing.ApplyingState)
+            return; // the component removal is already networked on its own
+
+        if (args.Container.Owner != component.Storage)
+            return;
+
+        RemComp(uid, component);
+    }
+
+    private void AddToggleOpenVerb(EntityUid uid, EntityStorageComponent component, GetVerbsEvent<InteractionVerb> args)
     {
         if (!args.CanAccess || !args.CanInteract)
             return;
@@ -177,7 +198,7 @@ public abstract class SharedEntityStorageSystem : EntitySystem
 
     public void ToggleOpen(EntityUid user, EntityUid target, EntityStorageComponent? component = null)
     {
-        if (!ResolveStorage(target, ref component))
+        if (!Resolve(target, ref component))
             return;
 
         if (component.Open)
@@ -192,7 +213,7 @@ public abstract class SharedEntityStorageSystem : EntitySystem
 
     public void EmptyContents(EntityUid uid, EntityStorageComponent? component = null)
     {
-        if (!ResolveStorage(uid, ref component))
+        if (!Resolve(uid, ref component))
             return;
 
         var uidXform = Transform(uid);
@@ -205,7 +226,7 @@ public abstract class SharedEntityStorageSystem : EntitySystem
 
     public void OpenStorage(EntityUid uid, EntityStorageComponent? component = null)
     {
-        if (!ResolveStorage(uid, ref component))
+        if (!Resolve(uid, ref component))
             return;
 
         if (component.Open)
@@ -226,7 +247,7 @@ public abstract class SharedEntityStorageSystem : EntitySystem
 
     public void CloseStorage(EntityUid uid, EntityStorageComponent? component = null)
     {
-        if (!ResolveStorage(uid, ref component))
+        if (!Resolve(uid, ref component))
             return;
 
         if (!component.Open)
@@ -277,7 +298,7 @@ public abstract class SharedEntityStorageSystem : EntitySystem
 
     public bool Insert(EntityUid toInsert, EntityUid container, EntityStorageComponent? component = null)
     {
-        if (!ResolveStorage(container, ref component))
+        if (!Resolve(container, ref component))
             return false;
 
         if (component.Open)
@@ -286,12 +307,14 @@ public abstract class SharedEntityStorageSystem : EntitySystem
             return true;
         }
 
+        // TODO: This should be done automatically for all containers
         _joints.RecursiveClearJoints(toInsert);
         if (!_container.Insert(toInsert, component.Contents))
             return false;
 
         var inside = EnsureComp<InsideEntityStorageComponent>(toInsert);
         inside.Storage = container;
+        Dirty(toInsert, inside);
         return true;
     }
 
@@ -300,7 +323,7 @@ public abstract class SharedEntityStorageSystem : EntitySystem
         if (!Resolve(container, ref xform, false))
             return false;
 
-        if (!ResolveStorage(container, ref component))
+        if (!Resolve(container, ref component))
             return false;
 
         _container.Remove(toRemove, component.Contents);
@@ -327,7 +350,7 @@ public abstract class SharedEntityStorageSystem : EntitySystem
 
     public bool CanInsert(EntityUid toInsert, EntityUid container, EntityStorageComponent? component = null)
     {
-        if (!ResolveStorage(container, ref component))
+        if (!Resolve(container, ref component))
             return false;
 
         if (component.Open)
@@ -384,7 +407,7 @@ public abstract class SharedEntityStorageSystem : EntitySystem
 
     public bool IsOpen(EntityUid target, EntityStorageComponent? component = null)
     {
-        if (!ResolveStorage(target, ref component))
+        if (!Resolve(target, ref component))
             return false;
 
         return component.Open;
@@ -392,7 +415,7 @@ public abstract class SharedEntityStorageSystem : EntitySystem
 
     public bool CanOpen(EntityUid user, EntityUid target, bool silent = false, EntityStorageComponent? component = null)
     {
-        if (!ResolveStorage(target, ref component))
+        if (!Resolve(target, ref component))
             return false;
 
         if (!HasComp<HandsComponent>(user))
@@ -434,7 +457,7 @@ public abstract class SharedEntityStorageSystem : EntitySystem
 
     public bool AddToContents(EntityUid toAdd, EntityUid container, EntityStorageComponent? component = null)
     {
-        if (!ResolveStorage(container, ref component))
+        if (!Resolve(container, ref component))
             return false;
 
         if (toAdd == container)
@@ -445,7 +468,7 @@ public abstract class SharedEntityStorageSystem : EntitySystem
 
     private void ModifyComponents(EntityUid uid, EntityStorageComponent? component = null)
     {
-        if (!ResolveStorage(uid, ref component))
+        if (!Resolve(uid, ref component))
             return;
 
         if (!component.IsCollidableWhenOpen && TryComp<FixturesComponent>(uid, out var fixtures) &&
@@ -475,13 +498,7 @@ public abstract class SharedEntityStorageSystem : EntitySystem
         _appearance.SetData(uid, StorageVisuals.HasContents, component.Contents.ContainedEntities.Count > 0);
     }
 
-    protected virtual void TakeGas(EntityUid uid, EntityStorageComponent component)
-    {
-
-    }
-
-    public virtual void ReleaseGas(EntityUid uid, EntityStorageComponent component)
-    {
+    protected virtual void TakeGas(EntityUid uid, EntityStorageComponent component) { }
 
-    }
+    public virtual void ReleaseGas(EntityUid uid, EntityStorageComponent component) { }
 }