1
0

BinSystem.cs 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169
  1. using System.Linq;
  2. using Content.Shared.Administration.Logs;
  3. using Content.Shared.Database;
  4. using Content.Shared.Examine;
  5. using Content.Shared.Hands.EntitySystems;
  6. using Content.Shared.Interaction;
  7. using Content.Shared.Item;
  8. using Content.Shared.Storage.Components;
  9. using Content.Shared.Verbs;
  10. using Content.Shared.Whitelist;
  11. using Robust.Shared.Containers;
  12. using Robust.Shared.Network;
  13. namespace Content.Shared.Storage.EntitySystems;
  14. /// <summary>
  15. /// This handles <see cref="BinComponent"/>
  16. /// </summary>
  17. public sealed class BinSystem : EntitySystem
  18. {
  19. [Dependency] private readonly INetManager _net = default!;
  20. [Dependency] private readonly ISharedAdminLogManager _admin = default!;
  21. [Dependency] private readonly SharedContainerSystem _container = default!;
  22. [Dependency] private readonly SharedHandsSystem _hands = default!;
  23. [Dependency] private readonly EntityWhitelistSystem _whitelistSystem = default!;
  24. public const string BinContainerId = "bin-container";
  25. /// <inheritdoc/>
  26. public override void Initialize()
  27. {
  28. SubscribeLocalEvent<BinComponent, ComponentStartup>(OnStartup);
  29. SubscribeLocalEvent<BinComponent, MapInitEvent>(OnMapInit);
  30. SubscribeLocalEvent<BinComponent, EntRemovedFromContainerMessage>(OnEntRemoved);
  31. SubscribeLocalEvent<BinComponent, InteractHandEvent>(OnInteractHand, before: new[] { typeof(SharedItemSystem) });
  32. SubscribeLocalEvent<BinComponent, AfterInteractUsingEvent>(OnAfterInteractUsing);
  33. SubscribeLocalEvent<BinComponent, GetVerbsEvent<AlternativeVerb>>(OnAltInteractHand);
  34. SubscribeLocalEvent<BinComponent, ExaminedEvent>(OnExamined);
  35. }
  36. private void OnExamined(EntityUid uid, BinComponent component, ExaminedEvent args)
  37. {
  38. args.PushText(Loc.GetString("bin-component-on-examine-text", ("count", component.Items.Count)));
  39. }
  40. private void OnStartup(EntityUid uid, BinComponent component, ComponentStartup args)
  41. {
  42. component.ItemContainer = _container.EnsureContainer<Container>(uid, BinContainerId);
  43. }
  44. private void OnMapInit(EntityUid uid, BinComponent component, MapInitEvent args)
  45. {
  46. // don't spawn on the client.
  47. if (_net.IsClient)
  48. return;
  49. var xform = Transform(uid);
  50. foreach (var id in component.InitialContents)
  51. {
  52. var ent = Spawn(id, xform.Coordinates);
  53. if (!TryInsertIntoBin(uid, ent, component))
  54. {
  55. Log.Error($"Entity {ToPrettyString(ent)} was unable to be initialized into bin {ToPrettyString(uid)}");
  56. return;
  57. }
  58. }
  59. }
  60. private void OnEntRemoved(EntityUid uid, BinComponent component, EntRemovedFromContainerMessage args)
  61. {
  62. component.Items.Remove(args.Entity);
  63. }
  64. private void OnInteractHand(EntityUid uid, BinComponent component, InteractHandEvent args)
  65. {
  66. if (args.Handled)
  67. return;
  68. EntityUid? toGrab = component.Items.LastOrDefault();
  69. if (!TryRemoveFromBin(uid, toGrab, component))
  70. return;
  71. _hands.TryPickupAnyHand(args.User, toGrab.Value);
  72. _admin.Add(LogType.Pickup, LogImpact.Low,
  73. $"{ToPrettyString(uid):player} removed {ToPrettyString(toGrab.Value)} from bin {ToPrettyString(uid)}.");
  74. args.Handled = true;
  75. }
  76. /// <summary>
  77. /// Alt interact acts the same as interacting with your hands normally, but allows fallback interaction if the item
  78. /// has priority. E.g. a water cup on a water cooler fills itself on a normal click,
  79. /// but you can use alternative interactions to restock the cup bin
  80. /// </summary>
  81. private void OnAltInteractHand(EntityUid uid, BinComponent component, GetVerbsEvent<AlternativeVerb> args)
  82. {
  83. if (args.Using != null)
  84. {
  85. var canReach = args.CanAccess && args.CanInteract;
  86. InsertIntoBin(args.User, args.Target, (EntityUid) args.Using, component, false, canReach);
  87. }
  88. }
  89. private void OnAfterInteractUsing(EntityUid uid, BinComponent component, AfterInteractUsingEvent args)
  90. {
  91. InsertIntoBin(args.User, uid, args.Used, component, args.Handled, args.CanReach);
  92. args.Handled = true;
  93. }
  94. private void InsertIntoBin(EntityUid user, EntityUid target, EntityUid itemInHand, BinComponent component, bool handled, bool canReach)
  95. {
  96. if (handled || !canReach)
  97. return;
  98. if (!TryInsertIntoBin(target, itemInHand, component))
  99. return;
  100. _admin.Add(LogType.Pickup, LogImpact.Low, $"{ToPrettyString(target):player} inserted {ToPrettyString(user)} into bin {ToPrettyString(target)}.");
  101. }
  102. /// <summary>
  103. /// Inserts an entity at the top of the bin
  104. /// </summary>
  105. /// <param name="uid"></param>
  106. /// <param name="toInsert"></param>
  107. /// <param name="component"></param>
  108. /// <returns></returns>
  109. public bool TryInsertIntoBin(EntityUid uid, EntityUid toInsert, BinComponent? component = null)
  110. {
  111. if (!Resolve(uid, ref component))
  112. return false;
  113. if (component.Items.Count >= component.MaxItems)
  114. return false;
  115. if (_whitelistSystem.IsWhitelistFail(component.Whitelist, toInsert))
  116. return false;
  117. _container.Insert(toInsert, component.ItemContainer);
  118. component.Items.Add(toInsert);
  119. Dirty(uid, component);
  120. return true;
  121. }
  122. /// <summary>
  123. /// Tries to remove an entity from the top of the bin.
  124. /// </summary>
  125. /// <param name="uid"></param>
  126. /// <param name="toRemove"></param>
  127. /// <param name="component"></param>
  128. /// <returns></returns>
  129. public bool TryRemoveFromBin(EntityUid uid, EntityUid? toRemove, BinComponent? component = null)
  130. {
  131. if (!Resolve(uid, ref component))
  132. return false;
  133. if (component.Items.Count == 0)
  134. return false;
  135. if (toRemove == null || toRemove != component.Items.LastOrDefault())
  136. return false;
  137. if (!_container.Remove(toRemove.Value, component.ItemContainer))
  138. return false;
  139. component.Items.Remove(toRemove.Value);
  140. Dirty(uid, component);
  141. return true;
  142. }
  143. }