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!;
_xformQuery = GetEntityQuery<TransformComponent>();
_prototype.PrototypesReloaded += OnPrototypesReloaded;
+ SubscribeLocalEvent<StorageComponent, ComponentGetState>(OnStorageGetState);
+ SubscribeLocalEvent<StorageComponent, ComponentHandleState>(OnStorageHandleState);
SubscribeLocalEvent<StorageComponent, ComponentInit>(OnComponentInit, before: new[] { typeof(SharedContainerSystem) });
SubscribeLocalEvent<StorageComponent, GetVerbsEvent<UtilityVerb>>(AddTransferVerbs);
SubscribeLocalEvent<StorageComponent, InteractUsingEvent>(OnInteractUsing, after: new[] { typeof(ItemSlotsSystem) });
UpdatePrototypeCache();
}
+ private void OnStorageGetState(EntityUid uid, StorageComponent component, ref ComponentGetState args)
+ {
+ var storedItems = new Dictionary<NetEntity, ItemStorageLocation>();
+
+ 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<StorageComponent>(nent, uid);
+ component.StoredItems[ent] = location;
+ }
+ }
+
public override void Shutdown()
{
_prototype.PrototypesReloaded -= OnPrototypesReloaded;
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))
{
return;
}
- entity.Comp.StoredItems[GetNetEntity(args.Entity)] = location.Value;
+ entity.Comp.StoredItems[args.Entity] = location.Value;
Dirty(entity, entity.Comp);
}
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));
return false;
}
- if (!ignoreLocation && !storageComp.StoredItems.ContainsKey(GetNetEntity(insertEnt)))
+ if (!ignoreLocation && !storageComp.StoredItems.ContainsKey(insertEnt))
{
if (!TryGetAvailableGridSpace((uid, storageComp), (insertEnt, item), out _))
{
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,
return true;
}
- uid.Comp.StoredItems.Remove(GetNetEntity(insertEnt));
+ uid.Comp.StoredItems.Remove(insertEnt);
return false;
}
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;
}
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;
/// </summary>
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<NetEntity, ItemStorageLocation> StoredItems = new();
+
+ public List<Box2i> Grid = new();
+
+ public ProtoId<ItemSizePrototype>? MaxItemSize;
+ }
}
/// <summary>
/// Handles generic storage with window, such as backpacks.
/// </summary>
- [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]
/// <summary>
/// A dictionary storing each entity to its position within the storage grid.
/// </summary>
- [DataField, ViewVariables(VVAccess.ReadWrite), AutoNetworkedField]
- public Dictionary<NetEntity, ItemStorageLocation> StoredItems = new();
+ [DataField, ViewVariables(VVAccess.ReadWrite)]
+ public Dictionary<EntityUid, ItemStorageLocation> StoredItems = new();
/// <summary>
/// A list of boxes that comprise a combined grid that determines the location that items can be stored.
/// </summary>
- [DataField, ViewVariables(VVAccess.ReadWrite), AutoNetworkedField]
+ [DataField, ViewVariables(VVAccess.ReadWrite)]
public List<Box2i> Grid = new();
/// <summary>
/// The maximum size item that can be inserted into this storage,
/// </summary>
- [DataField, ViewVariables(VVAccess.ReadWrite), AutoNetworkedField]
+ [DataField, ViewVariables(VVAccess.ReadWrite)]
[Access(typeof(SharedStorageSystem))]
public ProtoId<ItemSizePrototype>? 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;
/// <summary>
/// Whitelist for entities that can go into the storage.
/// </summary>
- [DataField("whitelist")]
+ [DataField]
public EntityWhitelist? Whitelist;
/// <summary>
/// Blacklist for entities that can go into storage.
/// </summary>
- [DataField("blacklist")]
+ [DataField]
public EntityWhitelist? Blacklist;
/// <summary>
/// Sound played whenever an entity is inserted into storage.
/// </summary>
- [DataField("storageInsertSound")]
+ [DataField]
public SoundSpecifier? StorageInsertSound = new SoundCollectionSpecifier("storageRustle");
/// <summary>
/// Sound played whenever an entity is removed from storage.
/// </summary>
- [DataField("storageRemoveSound")]
+ [DataField]
public SoundSpecifier? StorageRemoveSound;
/// <summary>
/// Sound played whenever the storage window is opened.
/// </summary>
- [DataField("storageOpenSound")]
+ [DataField]
public SoundSpecifier? StorageOpenSound = new SoundCollectionSpecifier("storageRustle");
/// <summary>
/// Sound played whenever the storage window is closed.
/// </summary>
- [DataField("storageCloseSound")]
+ [DataField]
public SoundSpecifier? StorageCloseSound;
/// <summary>
public StorageDefaultOrientation? DefaultStorageOrientation;
[Serializable, NetSerializable]
- public enum StorageUiKey
+ public enum StorageUiKey : byte
{
Key,
}