VaporSystem.cs 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145
  1. using Content.Server.Chemistry.Components;
  2. using Content.Shared.Chemistry;
  3. using Content.Shared.Chemistry.Components;
  4. using Content.Shared.Chemistry.Components.SolutionManager;
  5. using Content.Shared.Chemistry.Reagent;
  6. using Content.Shared.FixedPoint;
  7. using Content.Shared.Physics;
  8. using Content.Shared.Throwing;
  9. using Content.Shared.Chemistry.EntitySystems;
  10. using JetBrains.Annotations;
  11. using Robust.Shared.Map;
  12. using Robust.Shared.Map.Components;
  13. using Robust.Shared.Physics.Components;
  14. using Robust.Shared.Physics.Events;
  15. using Robust.Shared.Physics.Systems;
  16. using Robust.Shared.Prototypes;
  17. using Robust.Shared.Spawners;
  18. using System.Numerics;
  19. namespace Content.Server.Chemistry.EntitySystems
  20. {
  21. [UsedImplicitly]
  22. internal sealed class VaporSystem : EntitySystem
  23. {
  24. [Dependency] private readonly IPrototypeManager _protoManager = default!;
  25. [Dependency] private readonly SharedMapSystem _map = default!;
  26. [Dependency] private readonly SharedPhysicsSystem _physics = default!;
  27. [Dependency] private readonly SharedSolutionContainerSystem _solutionContainerSystem = default!;
  28. [Dependency] private readonly ThrowingSystem _throwing = default!;
  29. [Dependency] private readonly ReactiveSystem _reactive = default!;
  30. [Dependency] private readonly SharedTransformSystem _transformSystem = default!;
  31. private const float ReactTime = 0.125f;
  32. public override void Initialize()
  33. {
  34. base.Initialize();
  35. SubscribeLocalEvent<VaporComponent, StartCollideEvent>(HandleCollide);
  36. }
  37. private void HandleCollide(Entity<VaporComponent> entity, ref StartCollideEvent args)
  38. {
  39. if (!EntityManager.TryGetComponent(entity.Owner, out SolutionContainerManagerComponent? contents)) return;
  40. foreach (var (_, soln) in _solutionContainerSystem.EnumerateSolutions((entity.Owner, contents)))
  41. {
  42. var solution = soln.Comp.Solution;
  43. _reactive.DoEntityReaction(args.OtherEntity, solution, ReactionMethod.Touch);
  44. }
  45. // Check for collision with a impassable object (e.g. wall) and stop
  46. if ((args.OtherFixture.CollisionLayer & (int) CollisionGroup.Impassable) != 0 && args.OtherFixture.Hard)
  47. {
  48. EntityManager.QueueDeleteEntity(entity);
  49. }
  50. }
  51. public void Start(Entity<VaporComponent> vapor, TransformComponent vaporXform, Vector2 dir, float speed, MapCoordinates target, float aliveTime, EntityUid? user = null)
  52. {
  53. vapor.Comp.Active = true;
  54. var despawn = EnsureComp<TimedDespawnComponent>(vapor);
  55. despawn.Lifetime = aliveTime;
  56. // Set Move
  57. if (EntityManager.TryGetComponent(vapor, out PhysicsComponent? physics))
  58. {
  59. _physics.SetLinearDamping(vapor, physics, 0f);
  60. _physics.SetAngularDamping(vapor, physics, 0f);
  61. _throwing.TryThrow(vapor, dir, speed, user: user);
  62. var distance = (target.Position - _transformSystem.GetWorldPosition(vaporXform)).Length();
  63. var time = (distance / physics.LinearVelocity.Length());
  64. despawn.Lifetime = MathF.Min(aliveTime, time);
  65. }
  66. }
  67. internal bool TryAddSolution(Entity<VaporComponent> vapor, Solution solution)
  68. {
  69. if (solution.Volume == 0)
  70. {
  71. return false;
  72. }
  73. if (!_solutionContainerSystem.TryGetSolution(vapor.Owner, VaporComponent.SolutionName, out var vaporSolution))
  74. {
  75. return false;
  76. }
  77. return _solutionContainerSystem.TryAddSolution(vaporSolution.Value, solution);
  78. }
  79. public override void Update(float frameTime)
  80. {
  81. var query = EntityQueryEnumerator<VaporComponent, SolutionContainerManagerComponent, TransformComponent>();
  82. while (query.MoveNext(out var uid, out var vaporComp, out var container, out var xform))
  83. {
  84. foreach (var (_, soln) in _solutionContainerSystem.EnumerateSolutions((uid, container)))
  85. {
  86. Update(frameTime, (uid, vaporComp), soln, xform);
  87. }
  88. }
  89. }
  90. private void Update(float frameTime, Entity<VaporComponent> ent, Entity<SolutionComponent> soln, TransformComponent xform)
  91. {
  92. var (entity, vapor) = ent;
  93. if (!vapor.Active)
  94. return;
  95. vapor.ReactTimer += frameTime;
  96. var contents = soln.Comp.Solution;
  97. if (vapor.ReactTimer >= ReactTime && TryComp(xform.GridUid, out MapGridComponent? gridComp))
  98. {
  99. vapor.ReactTimer = 0;
  100. var tile = _map.GetTileRef(xform.GridUid.Value, gridComp, xform.Coordinates);
  101. foreach (var reagentQuantity in contents.Contents.ToArray())
  102. {
  103. if (reagentQuantity.Quantity == FixedPoint2.Zero) continue;
  104. var reagent = _protoManager.Index<ReagentPrototype>(reagentQuantity.Reagent.Prototype);
  105. var reaction =
  106. reagent.ReactionTile(tile, (reagentQuantity.Quantity / vapor.TransferAmount) * 0.25f, EntityManager, reagentQuantity.Reagent.Data);
  107. if (reaction > reagentQuantity.Quantity)
  108. {
  109. Log.Error($"Tried to tile react more than we have for reagent {reagentQuantity}. Found {reaction} and we only have {reagentQuantity.Quantity}");
  110. reaction = reagentQuantity.Quantity;
  111. }
  112. _solutionContainerSystem.RemoveReagent(soln, reagentQuantity.Reagent, reaction);
  113. }
  114. }
  115. if (contents.Volume == 0)
  116. {
  117. // Delete this
  118. EntityManager.QueueDeleteEntity(entity);
  119. }
  120. }
  121. }
  122. }