1
0

ConveyorController.cs 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146
  1. using Content.Server.DeviceLinking.Events;
  2. using Content.Server.DeviceLinking.Systems;
  3. using Content.Server.Materials;
  4. using Content.Server.Power.Components;
  5. using Content.Shared.Conveyor;
  6. using Content.Shared.Destructible;
  7. using Content.Shared.Maps;
  8. using Content.Shared.Physics;
  9. using Content.Shared.Physics.Controllers;
  10. using Content.Shared.Power;
  11. using Robust.Shared.Physics;
  12. using Robust.Shared.Physics.Collision.Shapes;
  13. using Robust.Shared.Physics.Components;
  14. using Robust.Shared.Physics.Systems;
  15. namespace Content.Server.Physics.Controllers;
  16. public sealed class ConveyorController : SharedConveyorController
  17. {
  18. [Dependency] private readonly FixtureSystem _fixtures = default!;
  19. [Dependency] private readonly DeviceLinkSystem _signalSystem = default!;
  20. [Dependency] private readonly MaterialReclaimerSystem _materialReclaimer = default!;
  21. [Dependency] private readonly SharedBroadphaseSystem _broadphase = default!;
  22. [Dependency] private readonly SharedAppearanceSystem _appearance = default!;
  23. public override void Initialize()
  24. {
  25. UpdatesAfter.Add(typeof(MoverController));
  26. SubscribeLocalEvent<ConveyorComponent, ComponentInit>(OnInit);
  27. SubscribeLocalEvent<ConveyorComponent, ComponentShutdown>(OnConveyorShutdown);
  28. SubscribeLocalEvent<ConveyorComponent, BreakageEventArgs>(OnBreakage);
  29. SubscribeLocalEvent<ConveyorComponent, SignalReceivedEvent>(OnSignalReceived);
  30. SubscribeLocalEvent<ConveyorComponent, PowerChangedEvent>(OnPowerChanged);
  31. base.Initialize();
  32. }
  33. private void OnInit(EntityUid uid, ConveyorComponent component, ComponentInit args)
  34. {
  35. _signalSystem.EnsureSinkPorts(uid, component.ReversePort, component.ForwardPort, component.OffPort);
  36. if (TryComp<PhysicsComponent>(uid, out var physics))
  37. {
  38. var shape = new PolygonShape();
  39. shape.SetAsBox(0.55f, 0.55f);
  40. _fixtures.TryCreateFixture(uid, shape, ConveyorFixture,
  41. collisionLayer: (int) (CollisionGroup.LowImpassable | CollisionGroup.MidImpassable |
  42. CollisionGroup.Impassable), hard: false, body: physics);
  43. }
  44. }
  45. private void OnConveyorShutdown(EntityUid uid, ConveyorComponent component, ComponentShutdown args)
  46. {
  47. if (MetaData(uid).EntityLifeStage >= EntityLifeStage.Terminating)
  48. return;
  49. if (!TryComp<PhysicsComponent>(uid, out var physics))
  50. return;
  51. _fixtures.DestroyFixture(uid, ConveyorFixture, body: physics);
  52. }
  53. private void OnBreakage(Entity<ConveyorComponent> ent, ref BreakageEventArgs args)
  54. {
  55. SetState(ent, ConveyorState.Off, ent);
  56. }
  57. private void OnPowerChanged(EntityUid uid, ConveyorComponent component, ref PowerChangedEvent args)
  58. {
  59. component.Powered = args.Powered;
  60. UpdateAppearance(uid, component);
  61. Dirty(uid, component);
  62. }
  63. private void UpdateAppearance(EntityUid uid, ConveyorComponent component)
  64. {
  65. _appearance.SetData(uid, ConveyorVisuals.State, component.Powered ? component.State : ConveyorState.Off);
  66. }
  67. private void OnSignalReceived(EntityUid uid, ConveyorComponent component, ref SignalReceivedEvent args)
  68. {
  69. if (args.Port == component.OffPort)
  70. SetState(uid, ConveyorState.Off, component);
  71. else if (args.Port == component.ForwardPort)
  72. {
  73. AwakenEntities(uid, component);
  74. SetState(uid, ConveyorState.Forward, component);
  75. }
  76. else if (args.Port == component.ReversePort)
  77. {
  78. AwakenEntities(uid, component);
  79. SetState(uid, ConveyorState.Reverse, component);
  80. }
  81. }
  82. private void SetState(EntityUid uid, ConveyorState state, ConveyorComponent? component = null)
  83. {
  84. if (!Resolve(uid, ref component))
  85. return;
  86. if (!_materialReclaimer.SetReclaimerEnabled(uid, state != ConveyorState.Off))
  87. return;
  88. component.State = state;
  89. if (TryComp<PhysicsComponent>(uid, out var physics))
  90. _broadphase.RegenerateContacts((uid, physics));
  91. UpdateAppearance(uid, component);
  92. Dirty(uid, component);
  93. }
  94. /// <summary>
  95. /// Awakens sleeping entities on the conveyor belt's tile when it's turned on.
  96. /// Fixes an issue where non-hard/sleeping entities refuse to wake up + collide if a belt is turned off and on again.
  97. /// </summary>
  98. private void AwakenEntities(EntityUid uid, ConveyorComponent component)
  99. {
  100. var xformQuery = GetEntityQuery<TransformComponent>();
  101. var bodyQuery = GetEntityQuery<PhysicsComponent>();
  102. if (!xformQuery.TryGetComponent(uid, out var xform))
  103. return;
  104. var beltTileRef = xform.Coordinates.GetTileRef(EntityManager, MapManager);
  105. if (beltTileRef != null)
  106. {
  107. var intersecting = Lookup.GetLocalEntitiesIntersecting(beltTileRef.Value, 0f);
  108. foreach (var entity in intersecting)
  109. {
  110. if (!bodyQuery.TryGetComponent(entity, out var physics))
  111. continue;
  112. if (physics.BodyType != BodyType.Static)
  113. Physics.WakeBody(entity, body: physics);
  114. }
  115. }
  116. }
  117. }