InventorySystem.Relay.cs 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167
  1. using Content.Shared.Armor;
  2. using Content.Shared.Chat;
  3. using Content.Shared.Chemistry;
  4. using Content.Shared.Chemistry.Hypospray.Events;
  5. using Content.Shared.Climbing.Events;
  6. using Content.Shared.Damage;
  7. using Content.Shared.Electrocution;
  8. using Content.Shared.Explosion;
  9. using Content.Shared.Eye.Blinding.Systems;
  10. using Content.Shared.Gravity;
  11. using Content.Shared.IdentityManagement.Components;
  12. using Content.Shared.Inventory.Events;
  13. using Content.Shared.Movement.Events;
  14. using Content.Shared.Movement.Systems;
  15. using Content.Shared.NameModifier.EntitySystems;
  16. using Content.Shared.Overlays;
  17. using Content.Shared.Radio;
  18. using Content.Shared.Slippery;
  19. using Content.Shared.Strip.Components;
  20. using Content.Shared.Temperature;
  21. using Content.Shared.Verbs;
  22. using Content.Shared.Weapons.Ranged.Events;
  23. namespace Content.Shared.Inventory;
  24. public partial class InventorySystem
  25. {
  26. public void InitializeRelay()
  27. {
  28. SubscribeLocalEvent<InventoryComponent, DamageModifyEvent>(RelayInventoryEvent);
  29. SubscribeLocalEvent<InventoryComponent, ElectrocutionAttemptEvent>(RelayInventoryEvent);
  30. SubscribeLocalEvent<InventoryComponent, SlipAttemptEvent>(RelayInventoryEvent);
  31. SubscribeLocalEvent<InventoryComponent, RefreshMovementSpeedModifiersEvent>(RelayInventoryEvent);
  32. SubscribeLocalEvent<InventoryComponent, BeforeStripEvent>(RelayInventoryEvent);
  33. SubscribeLocalEvent<InventoryComponent, SeeIdentityAttemptEvent>(RelayInventoryEvent);
  34. SubscribeLocalEvent<InventoryComponent, ModifyChangedTemperatureEvent>(RelayInventoryEvent);
  35. SubscribeLocalEvent<InventoryComponent, GetDefaultRadioChannelEvent>(RelayInventoryEvent);
  36. SubscribeLocalEvent<InventoryComponent, RefreshNameModifiersEvent>(RelayInventoryEvent);
  37. SubscribeLocalEvent<InventoryComponent, TransformSpeakerNameEvent>(RelayInventoryEvent);
  38. SubscribeLocalEvent<InventoryComponent, SelfBeforeHyposprayInjectsEvent>(RelayInventoryEvent);
  39. SubscribeLocalEvent<InventoryComponent, TargetBeforeHyposprayInjectsEvent>(RelayInventoryEvent);
  40. SubscribeLocalEvent<InventoryComponent, SelfBeforeGunShotEvent>(RelayInventoryEvent);
  41. SubscribeLocalEvent<InventoryComponent, SelfBeforeClimbEvent>(RelayInventoryEvent);
  42. SubscribeLocalEvent<InventoryComponent, CoefficientQueryEvent>(RelayInventoryEvent);
  43. // by-ref events
  44. SubscribeLocalEvent<InventoryComponent, GetExplosionResistanceEvent>(RefRelayInventoryEvent);
  45. SubscribeLocalEvent<InventoryComponent, IsWeightlessEvent>(RefRelayInventoryEvent);
  46. SubscribeLocalEvent<InventoryComponent, GetSpeedModifierContactCapEvent>(RefRelayInventoryEvent);
  47. SubscribeLocalEvent<InventoryComponent, GetSlowedOverSlipperyModifierEvent>(RefRelayInventoryEvent);
  48. SubscribeLocalEvent<InventoryComponent, ModifySlowOnDamageSpeedEvent>(RefRelayInventoryEvent);
  49. // Eye/vision events
  50. SubscribeLocalEvent<InventoryComponent, CanSeeAttemptEvent>(RelayInventoryEvent);
  51. SubscribeLocalEvent<InventoryComponent, GetEyeProtectionEvent>(RelayInventoryEvent);
  52. SubscribeLocalEvent<InventoryComponent, GetBlurEvent>(RelayInventoryEvent);
  53. SubscribeLocalEvent<InventoryComponent, SolutionScanEvent>(RelayInventoryEvent);
  54. // ComponentActivatedClientSystems
  55. SubscribeLocalEvent<InventoryComponent, RefreshEquipmentHudEvent<ShowJobIconsComponent>>(RefRelayInventoryEvent);
  56. SubscribeLocalEvent<InventoryComponent, RefreshEquipmentHudEvent<ShowHealthBarsComponent>>(RefRelayInventoryEvent);
  57. SubscribeLocalEvent<InventoryComponent, RefreshEquipmentHudEvent<ShowHealthIconsComponent>>(RefRelayInventoryEvent);
  58. SubscribeLocalEvent<InventoryComponent, RefreshEquipmentHudEvent<ShowHungerIconsComponent>>(RefRelayInventoryEvent);
  59. SubscribeLocalEvent<InventoryComponent, RefreshEquipmentHudEvent<ShowThirstIconsComponent>>(RefRelayInventoryEvent);
  60. SubscribeLocalEvent<InventoryComponent, RefreshEquipmentHudEvent<ShowMindShieldIconsComponent>>(RefRelayInventoryEvent);
  61. SubscribeLocalEvent<InventoryComponent, RefreshEquipmentHudEvent<ShowSyndicateIconsComponent>>(RefRelayInventoryEvent);
  62. SubscribeLocalEvent<InventoryComponent, RefreshEquipmentHudEvent<ShowCriminalRecordIconsComponent>>(RefRelayInventoryEvent);
  63. SubscribeLocalEvent<InventoryComponent, RefreshEquipmentHudEvent<ShowFactionIconsComponent>>(RefRelayInventoryEvent);
  64. SubscribeLocalEvent<InventoryComponent, RefreshEquipmentHudEvent<ShowFrenchFactionIconsComponent>>(RefRelayInventoryEvent);
  65. SubscribeLocalEvent<InventoryComponent, RefreshEquipmentHudEvent<ShowEnglishFactionIconsComponent>>(RefRelayInventoryEvent);
  66. SubscribeLocalEvent<InventoryComponent, GetVerbsEvent<EquipmentVerb>>(OnGetEquipmentVerbs);
  67. }
  68. protected void RefRelayInventoryEvent<T>(EntityUid uid, InventoryComponent component, ref T args) where T : IInventoryRelayEvent
  69. {
  70. RelayEvent((uid, component), ref args);
  71. }
  72. protected void RelayInventoryEvent<T>(EntityUid uid, InventoryComponent component, T args) where T : IInventoryRelayEvent
  73. {
  74. RelayEvent((uid, component), args);
  75. }
  76. public void RelayEvent<T>(Entity<InventoryComponent> inventory, ref T args) where T : IInventoryRelayEvent
  77. {
  78. if (args.TargetSlots == SlotFlags.NONE)
  79. return;
  80. // this copies the by-ref event if it is a struct
  81. var ev = new InventoryRelayedEvent<T>(args);
  82. var enumerator = new InventorySlotEnumerator(inventory, args.TargetSlots);
  83. while (enumerator.NextItem(out var item))
  84. {
  85. RaiseLocalEvent(item, ev);
  86. }
  87. // and now we copy it back
  88. args = ev.Args;
  89. }
  90. public void RelayEvent<T>(Entity<InventoryComponent> inventory, T args) where T : IInventoryRelayEvent
  91. {
  92. if (args.TargetSlots == SlotFlags.NONE)
  93. return;
  94. var ev = new InventoryRelayedEvent<T>(args);
  95. var enumerator = new InventorySlotEnumerator(inventory, args.TargetSlots);
  96. while (enumerator.NextItem(out var item))
  97. {
  98. RaiseLocalEvent(item, ev);
  99. }
  100. }
  101. private void OnGetEquipmentVerbs(EntityUid uid, InventoryComponent component, GetVerbsEvent<EquipmentVerb> args)
  102. {
  103. // Automatically relay stripping related verbs to all equipped clothing.
  104. var ev = new InventoryRelayedEvent<GetVerbsEvent<EquipmentVerb>>(args);
  105. var enumerator = new InventorySlotEnumerator(component);
  106. while (enumerator.NextItem(out var item, out var slotDef))
  107. {
  108. if (!_strippable.IsStripHidden(slotDef, args.User) || args.User == uid)
  109. RaiseLocalEvent(item, ev);
  110. }
  111. }
  112. }
  113. /// <summary>
  114. /// Event wrapper for relayed events.
  115. /// </summary>
  116. /// <remarks>
  117. /// This avoids nested inventory relays, and makes it easy to have certain events only handled by the initial
  118. /// target entity. E.g. health based movement speed modifiers should not be handled by a hat, even if that hat
  119. /// happens to be a dead mouse. Clothing that wishes to modify movement speed must subscribe to
  120. /// InventoryRelayedEvent&lt;RefreshMovementSpeedModifiersEvent&gt;
  121. /// </remarks>
  122. public sealed class InventoryRelayedEvent<TEvent> : EntityEventArgs
  123. {
  124. public TEvent Args;
  125. public InventoryRelayedEvent(TEvent args)
  126. {
  127. Args = args;
  128. }
  129. }
  130. public interface IClothingSlots
  131. {
  132. SlotFlags Slots { get; }
  133. }
  134. /// <summary>
  135. /// Events that should be relayed to inventory slots should implement this interface.
  136. /// </summary>
  137. public interface IInventoryRelayEvent
  138. {
  139. /// <summary>
  140. /// What inventory slots should this event be relayed to, if any?
  141. /// </summary>
  142. /// <remarks>
  143. /// In general you may want to exclude <see cref="SlotFlags.POCKET"/>, given that those items are not truly
  144. /// "equipped" by the user.
  145. /// </remarks>
  146. public SlotFlags TargetSlots { get; }
  147. }