1
0

StorageSystem.cs 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183
  1. using System.Linq;
  2. using System.Numerics;
  3. using Content.Client.Animations;
  4. using Content.Shared.Hands;
  5. using Content.Shared.Storage;
  6. using Content.Shared.Storage.EntitySystems;
  7. using Robust.Client.Player;
  8. using Robust.Shared.GameStates;
  9. using Robust.Shared.Map;
  10. using Robust.Shared.Timing;
  11. namespace Content.Client.Storage.Systems;
  12. public sealed class StorageSystem : SharedStorageSystem
  13. {
  14. [Dependency] private readonly IGameTiming _timing = default!;
  15. [Dependency] private readonly IPlayerManager _player = default!;
  16. [Dependency] private readonly EntityPickupAnimationSystem _entityPickupAnimation = default!;
  17. private Dictionary<EntityUid, ItemStorageLocation> _oldStoredItems = new();
  18. private List<(StorageBoundUserInterface Bui, bool Value)> _queuedBuis = new();
  19. public override void Initialize()
  20. {
  21. base.Initialize();
  22. SubscribeLocalEvent<StorageComponent, ComponentHandleState>(OnStorageHandleState);
  23. SubscribeNetworkEvent<PickupAnimationEvent>(HandlePickupAnimation);
  24. SubscribeAllEvent<AnimateInsertingEntitiesEvent>(HandleAnimatingInsertingEntities);
  25. }
  26. private void OnStorageHandleState(EntityUid uid, StorageComponent component, ref ComponentHandleState args)
  27. {
  28. if (args.Current is not StorageComponentState state)
  29. return;
  30. component.Grid.Clear();
  31. component.Grid.AddRange(state.Grid);
  32. component.MaxItemSize = state.MaxItemSize;
  33. component.Whitelist = state.Whitelist;
  34. component.Blacklist = state.Blacklist;
  35. _oldStoredItems.Clear();
  36. foreach (var item in component.StoredItems)
  37. {
  38. _oldStoredItems.Add(item.Key, item.Value);
  39. }
  40. component.StoredItems.Clear();
  41. foreach (var (nent, location) in state.StoredItems)
  42. {
  43. var ent = EnsureEntity<StorageComponent>(nent, uid);
  44. component.StoredItems[ent] = location;
  45. }
  46. component.SavedLocations.Clear();
  47. foreach (var loc in state.SavedLocations)
  48. {
  49. component.SavedLocations[loc.Key] = new(loc.Value);
  50. }
  51. var uiDirty = !component.StoredItems.SequenceEqual(_oldStoredItems);
  52. if (uiDirty && UI.TryGetOpenUi<StorageBoundUserInterface>(uid, StorageComponent.StorageUiKey.Key, out var storageBui))
  53. {
  54. storageBui.Refresh();
  55. // Make sure nesting still updated.
  56. var player = _player.LocalEntity;
  57. if (NestedStorage && player != null && ContainerSystem.TryGetContainingContainer((uid, null, null), out var container) &&
  58. UI.TryGetOpenUi<StorageBoundUserInterface>(container.Owner, StorageComponent.StorageUiKey.Key, out var containerBui))
  59. {
  60. _queuedBuis.Add((containerBui, false));
  61. }
  62. }
  63. }
  64. public override void UpdateUI(Entity<StorageComponent?> entity)
  65. {
  66. if (UI.TryGetOpenUi<StorageBoundUserInterface>(entity.Owner, StorageComponent.StorageUiKey.Key, out var sBui))
  67. {
  68. sBui.Refresh();
  69. }
  70. }
  71. protected override void HideStorageWindow(EntityUid uid, EntityUid actor)
  72. {
  73. if (UI.TryGetOpenUi<StorageBoundUserInterface>(uid, StorageComponent.StorageUiKey.Key, out var storageBui))
  74. {
  75. _queuedBuis.Add((storageBui, false));
  76. }
  77. }
  78. protected override void ShowStorageWindow(EntityUid uid, EntityUid actor)
  79. {
  80. if (UI.TryGetOpenUi<StorageBoundUserInterface>(uid, StorageComponent.StorageUiKey.Key, out var storageBui))
  81. {
  82. _queuedBuis.Add((storageBui, true));
  83. }
  84. }
  85. /// <inheritdoc />
  86. public override void PlayPickupAnimation(EntityUid uid, EntityCoordinates initialCoordinates, EntityCoordinates finalCoordinates,
  87. Angle initialRotation, EntityUid? user = null)
  88. {
  89. if (!_timing.IsFirstTimePredicted)
  90. return;
  91. PickupAnimation(uid, initialCoordinates, finalCoordinates, initialRotation);
  92. }
  93. private void HandlePickupAnimation(PickupAnimationEvent msg)
  94. {
  95. PickupAnimation(GetEntity(msg.ItemUid), GetCoordinates(msg.InitialPosition), GetCoordinates(msg.FinalPosition), msg.InitialAngle);
  96. }
  97. public void PickupAnimation(EntityUid item, EntityCoordinates initialCoords, EntityCoordinates finalCoords, Angle initialAngle)
  98. {
  99. if (!_timing.IsFirstTimePredicted)
  100. return;
  101. if (TransformSystem.InRange(finalCoords, initialCoords, 0.1f) ||
  102. !Exists(initialCoords.EntityId) || !Exists(finalCoords.EntityId))
  103. {
  104. return;
  105. }
  106. var finalMapPos = TransformSystem.ToMapCoordinates(finalCoords).Position;
  107. var finalPos = Vector2.Transform(finalMapPos, TransformSystem.GetInvWorldMatrix(initialCoords.EntityId));
  108. _entityPickupAnimation.AnimateEntityPickup(item, initialCoords, finalPos, initialAngle);
  109. }
  110. /// <summary>
  111. /// Animate the newly stored entities in <paramref name="msg"/> flying towards this storage's position
  112. /// </summary>
  113. /// <param name="msg"></param>
  114. public void HandleAnimatingInsertingEntities(AnimateInsertingEntitiesEvent msg)
  115. {
  116. TryComp(GetEntity(msg.Storage), out TransformComponent? transformComp);
  117. for (var i = 0; msg.StoredEntities.Count > i; i++)
  118. {
  119. var entity = GetEntity(msg.StoredEntities[i]);
  120. var initialPosition = msg.EntityPositions[i];
  121. if (Exists(entity) && transformComp != null)
  122. {
  123. _entityPickupAnimation.AnimateEntityPickup(entity, GetCoordinates(initialPosition), transformComp.LocalPosition, msg.EntityAngles[i]);
  124. }
  125. }
  126. }
  127. public override void Update(float frameTime)
  128. {
  129. base.Update(frameTime);
  130. if (!_timing.IsFirstTimePredicted)
  131. {
  132. return;
  133. }
  134. // This update loop exists just to synchronize with UISystem and avoid 1-tick delays.
  135. // If deferred opens / closes ever get removed you can dump this.
  136. foreach (var (bui, open) in _queuedBuis)
  137. {
  138. if (open)
  139. {
  140. bui.Show();
  141. }
  142. else
  143. {
  144. bui.Hide();
  145. }
  146. }
  147. _queuedBuis.Clear();
  148. }
  149. }