AirtightSystem.cs 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161
  1. using Content.Server.Atmos.Components;
  2. using Content.Server.Explosion.EntitySystems;
  3. using Content.Shared.Atmos;
  4. using JetBrains.Annotations;
  5. using Robust.Shared.Map.Components;
  6. namespace Content.Server.Atmos.EntitySystems
  7. {
  8. [UsedImplicitly]
  9. public sealed class AirtightSystem : EntitySystem
  10. {
  11. [Dependency] private readonly SharedTransformSystem _transform = default!;
  12. [Dependency] private readonly AtmosphereSystem _atmosphereSystem = default!;
  13. [Dependency] private readonly ExplosionSystem _explosionSystem = default!;
  14. [Dependency] private readonly SharedMapSystem _mapSystem = default!;
  15. public override void Initialize()
  16. {
  17. SubscribeLocalEvent<AirtightComponent, ComponentInit>(OnAirtightInit);
  18. SubscribeLocalEvent<AirtightComponent, ComponentShutdown>(OnAirtightShutdown);
  19. SubscribeLocalEvent<AirtightComponent, AnchorStateChangedEvent>(OnAirtightPositionChanged);
  20. SubscribeLocalEvent<AirtightComponent, ReAnchorEvent>(OnAirtightReAnchor);
  21. SubscribeLocalEvent<AirtightComponent, MoveEvent>(OnAirtightMoved);
  22. }
  23. private void OnAirtightInit(Entity<AirtightComponent> airtight, ref ComponentInit args)
  24. {
  25. // TODO AIRTIGHT what FixAirBlockedDirectionInitialize even for?
  26. if (!airtight.Comp.FixAirBlockedDirectionInitialize)
  27. {
  28. UpdatePosition(airtight);
  29. return;
  30. }
  31. var xform = Transform(airtight);
  32. airtight.Comp.CurrentAirBlockedDirection =
  33. (int) Rotate((AtmosDirection) airtight.Comp.InitialAirBlockedDirection, xform.LocalRotation);
  34. UpdatePosition(airtight, xform);
  35. var airtightEv = new AirtightChanged(airtight, airtight, false, default);
  36. RaiseLocalEvent(airtight, ref airtightEv, true);
  37. }
  38. private void OnAirtightShutdown(Entity<AirtightComponent> airtight, ref ComponentShutdown args)
  39. {
  40. var xform = Transform(airtight);
  41. // If the grid is deleting no point updating atmos.
  42. if (xform.GridUid != null && LifeStage(xform.GridUid.Value) <= EntityLifeStage.MapInitialized)
  43. SetAirblocked(airtight, false, xform);
  44. }
  45. private void OnAirtightPositionChanged(EntityUid uid, AirtightComponent airtight, ref AnchorStateChangedEvent args)
  46. {
  47. var xform = args.Transform;
  48. if (!TryComp(xform.GridUid, out MapGridComponent? grid))
  49. return;
  50. var gridId = xform.GridUid;
  51. var coords = xform.Coordinates;
  52. var tilePos = _mapSystem.TileIndicesFor(gridId.Value, grid, coords);
  53. // Update and invalidate new position.
  54. airtight.LastPosition = (gridId.Value, tilePos);
  55. InvalidatePosition(gridId.Value, tilePos);
  56. var airtightEv = new AirtightChanged(uid, airtight, false, (gridId.Value, tilePos));
  57. RaiseLocalEvent(uid, ref airtightEv, true);
  58. }
  59. private void OnAirtightReAnchor(EntityUid uid, AirtightComponent airtight, ref ReAnchorEvent args)
  60. {
  61. foreach (var gridId in new[] { args.OldGrid, args.Grid })
  62. {
  63. // Update and invalidate new position.
  64. airtight.LastPosition = (gridId, args.TilePos);
  65. InvalidatePosition(gridId, args.TilePos);
  66. var airtightEv = new AirtightChanged(uid, airtight, false, (gridId, args.TilePos));
  67. RaiseLocalEvent(uid, ref airtightEv, true);
  68. }
  69. }
  70. private void OnAirtightMoved(Entity<AirtightComponent> ent, ref MoveEvent ev)
  71. {
  72. var (owner, airtight) = ent;
  73. airtight.CurrentAirBlockedDirection = (int) Rotate((AtmosDirection)airtight.InitialAirBlockedDirection, ev.NewRotation);
  74. var pos = airtight.LastPosition;
  75. UpdatePosition(ent, ev.Component);
  76. var airtightEv = new AirtightChanged(owner, airtight, false, pos);
  77. RaiseLocalEvent(owner, ref airtightEv, true);
  78. }
  79. public void SetAirblocked(Entity<AirtightComponent> airtight, bool airblocked, TransformComponent? xform = null)
  80. {
  81. if (airtight.Comp.AirBlocked == airblocked)
  82. return;
  83. if (!Resolve(airtight, ref xform))
  84. return;
  85. var pos = airtight.Comp.LastPosition;
  86. airtight.Comp.AirBlocked = airblocked;
  87. UpdatePosition(airtight, xform);
  88. var airtightEv = new AirtightChanged(airtight, airtight, true, pos);
  89. RaiseLocalEvent(airtight, ref airtightEv, true);
  90. }
  91. public void UpdatePosition(Entity<AirtightComponent> ent, TransformComponent? xform = null)
  92. {
  93. var (owner, airtight) = ent;
  94. if (!Resolve(owner, ref xform))
  95. return;
  96. if (!xform.Anchored || !TryComp(xform.GridUid, out MapGridComponent? grid))
  97. return;
  98. var indices = _transform.GetGridTilePositionOrDefault((ent, xform), grid);
  99. airtight.LastPosition = (xform.GridUid.Value, indices);
  100. InvalidatePosition((xform.GridUid.Value, grid), indices);
  101. }
  102. public void InvalidatePosition(Entity<MapGridComponent?> grid, Vector2i pos)
  103. {
  104. var query = EntityManager.GetEntityQuery<AirtightComponent>();
  105. _explosionSystem.UpdateAirtightMap(grid, pos, grid, query);
  106. _atmosphereSystem.InvalidateTile(grid.Owner, pos);
  107. }
  108. private AtmosDirection Rotate(AtmosDirection myDirection, Angle myAngle)
  109. {
  110. var newAirBlockedDirs = AtmosDirection.Invalid;
  111. if (myAngle == Angle.Zero)
  112. return myDirection;
  113. // TODO ATMOS MULTIZ: When we make multiZ atmos, special case this.
  114. for (var i = 0; i < Atmospherics.Directions; i++)
  115. {
  116. var direction = (AtmosDirection) (1 << i);
  117. if (!myDirection.IsFlagSet(direction))
  118. continue;
  119. var angle = direction.ToAngle();
  120. angle += myAngle;
  121. newAirBlockedDirs |= angle.ToAtmosDirectionCardinal();
  122. }
  123. return newAirBlockedDirs;
  124. }
  125. }
  126. /// <summary>
  127. /// Raised upon the airtight status being changed via anchoring, movement, etc.
  128. /// </summary>
  129. /// <param name="Entity"></param>
  130. /// <param name="Airtight"></param>
  131. /// <param name="AirBlockedChanged">Whether the <see cref="AirtightComponent.AirBlocked"/> changed</param>
  132. /// <param name="Position"></param>
  133. [ByRefEvent]
  134. public readonly record struct AirtightChanged(EntityUid Entity, AirtightComponent Airtight, bool AirBlockedChanged, (EntityUid Grid, Vector2i Tile) Position);
  135. }