1
0

PipeRestrictOverlapSystem.cs 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123
  1. using System.Linq;
  2. using Content.Server.Atmos.Components;
  3. using Content.Server.NodeContainer;
  4. using Content.Server.NodeContainer.Nodes;
  5. using Content.Server.Popups;
  6. using Content.Shared.Atmos;
  7. using Content.Shared.Construction.Components;
  8. using JetBrains.Annotations;
  9. using Robust.Server.GameObjects;
  10. using Robust.Shared.Map.Components;
  11. namespace Content.Server.Atmos.EntitySystems;
  12. /// <summary>
  13. /// This handles restricting pipe-based entities from overlapping outlets/inlets with other entities.
  14. /// </summary>
  15. public sealed class PipeRestrictOverlapSystem : EntitySystem
  16. {
  17. [Dependency] private readonly MapSystem _map = default!;
  18. [Dependency] private readonly PopupSystem _popup = default!;
  19. [Dependency] private readonly TransformSystem _xform = default!;
  20. private readonly List<EntityUid> _anchoredEntities = new();
  21. private EntityQuery<NodeContainerComponent> _nodeContainerQuery;
  22. /// <inheritdoc/>
  23. public override void Initialize()
  24. {
  25. SubscribeLocalEvent<PipeRestrictOverlapComponent, AnchorStateChangedEvent>(OnAnchorStateChanged);
  26. SubscribeLocalEvent<PipeRestrictOverlapComponent, AnchorAttemptEvent>(OnAnchorAttempt);
  27. _nodeContainerQuery = GetEntityQuery<NodeContainerComponent>();
  28. }
  29. private void OnAnchorStateChanged(Entity<PipeRestrictOverlapComponent> ent, ref AnchorStateChangedEvent args)
  30. {
  31. if (!args.Anchored)
  32. return;
  33. if (HasComp<AnchorableComponent>(ent) && CheckOverlap(ent))
  34. {
  35. _popup.PopupEntity(Loc.GetString("pipe-restrict-overlap-popup-blocked", ("pipe", ent.Owner)), ent);
  36. _xform.Unanchor(ent, Transform(ent));
  37. }
  38. }
  39. private void OnAnchorAttempt(Entity<PipeRestrictOverlapComponent> ent, ref AnchorAttemptEvent args)
  40. {
  41. if (args.Cancelled)
  42. return;
  43. if (!_nodeContainerQuery.TryComp(ent, out var node))
  44. return;
  45. var xform = Transform(ent);
  46. if (CheckOverlap((ent, node, xform)))
  47. {
  48. _popup.PopupEntity(Loc.GetString("pipe-restrict-overlap-popup-blocked", ("pipe", ent.Owner)), ent, args.User);
  49. args.Cancel();
  50. }
  51. }
  52. [PublicAPI]
  53. public bool CheckOverlap(EntityUid uid)
  54. {
  55. if (!_nodeContainerQuery.TryComp(uid, out var node))
  56. return false;
  57. return CheckOverlap((uid, node, Transform(uid)));
  58. }
  59. public bool CheckOverlap(Entity<NodeContainerComponent, TransformComponent> ent)
  60. {
  61. if (ent.Comp2.GridUid is not { } grid || !TryComp<MapGridComponent>(grid, out var gridComp))
  62. return false;
  63. var indices = _map.TileIndicesFor(grid, gridComp, ent.Comp2.Coordinates);
  64. _anchoredEntities.Clear();
  65. _map.GetAnchoredEntities((grid, gridComp), indices, _anchoredEntities);
  66. foreach (var otherEnt in _anchoredEntities)
  67. {
  68. // this should never actually happen but just for safety
  69. if (otherEnt == ent.Owner)
  70. continue;
  71. if (!_nodeContainerQuery.TryComp(otherEnt, out var otherComp))
  72. continue;
  73. if (PipeNodesOverlap(ent, (otherEnt, otherComp, Transform(otherEnt))))
  74. return true;
  75. }
  76. return false;
  77. }
  78. public bool PipeNodesOverlap(Entity<NodeContainerComponent, TransformComponent> ent, Entity<NodeContainerComponent, TransformComponent> other)
  79. {
  80. var entDirs = GetAllDirections(ent).ToList();
  81. var otherDirs = GetAllDirections(other).ToList();
  82. foreach (var dir in entDirs)
  83. {
  84. foreach (var otherDir in otherDirs)
  85. {
  86. if ((dir & otherDir) != 0)
  87. return true;
  88. }
  89. }
  90. return false;
  91. IEnumerable<PipeDirection> GetAllDirections(Entity<NodeContainerComponent, TransformComponent> pipe)
  92. {
  93. foreach (var node in pipe.Comp1.Nodes.Values)
  94. {
  95. // we need to rotate the pipe manually like this because the rotation doesn't update for pipes that are unanchored.
  96. if (node is PipeNode pipeNode)
  97. yield return pipeNode.OriginalPipeDirection.RotatePipeDirection(pipe.Comp2.LocalRotation);
  98. }
  99. }
  100. }
  101. }