1
0

DoAfterSystem.cs 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111
  1. using System.Diagnostics.CodeAnalysis;
  2. using Content.Shared.DoAfter;
  3. using Content.Shared.Hands.Components;
  4. using Robust.Client.Graphics;
  5. using Robust.Client.Player;
  6. using Robust.Shared.Prototypes;
  7. namespace Content.Client.DoAfter;
  8. /// <summary>
  9. /// Handles events that need to happen after a certain amount of time where the event could be cancelled by factors
  10. /// such as moving.
  11. /// </summary>
  12. public sealed class DoAfterSystem : SharedDoAfterSystem
  13. {
  14. [Dependency] private readonly IOverlayManager _overlay = default!;
  15. [Dependency] private readonly IPlayerManager _player = default!;
  16. [Dependency] private readonly IPrototypeManager _prototype = default!;
  17. [Dependency] private readonly MetaDataSystem _metadata = default!;
  18. public override void Initialize()
  19. {
  20. base.Initialize();
  21. _overlay.AddOverlay(new DoAfterOverlay(EntityManager, _prototype, GameTiming, _player));
  22. }
  23. public override void Shutdown()
  24. {
  25. base.Shutdown();
  26. _overlay.RemoveOverlay<DoAfterOverlay>();
  27. }
  28. #pragma warning disable RA0028 // No base call in overriden function
  29. public override void Update(float frameTime)
  30. #pragma warning restore RA0028 // No base call in overriden function
  31. {
  32. // Currently this only predicts do afters initiated by the player.
  33. // TODO maybe predict do-afters if the local player is the target of some other players do-after? Specifically
  34. // ones that depend on the target not moving, because the cancellation of those do afters should be readily
  35. // predictable by clients.
  36. var playerEntity = _player.LocalEntity;
  37. if (!TryComp(playerEntity, out ActiveDoAfterComponent? active))
  38. return;
  39. if (_metadata.EntityPaused(playerEntity.Value))
  40. return;
  41. var time = GameTiming.CurTime;
  42. var comp = Comp<DoAfterComponent>(playerEntity.Value);
  43. var xformQuery = GetEntityQuery<TransformComponent>();
  44. var handsQuery = GetEntityQuery<HandsComponent>();
  45. Update(playerEntity.Value, active, comp, time, xformQuery, handsQuery);
  46. }
  47. /// <summary>
  48. /// Try to find an active do-after being executed by the local player.
  49. /// </summary>
  50. /// <param name="entity">The entity the do after must be targeting (<see cref="DoAfterArgs.Target"/>)</param>
  51. /// <param name="doAfter">The found do-after.</param>
  52. /// <param name="event">The event to be raised on the found do-after when it completes.</param>
  53. /// <param name="progress">The progress of the found do-after, from 0 to 1.</param>
  54. /// <typeparam name="T">The type of event that must be raised by the found do-after.</typeparam>
  55. /// <returns>True if a do-after was found.</returns>
  56. public bool TryFindActiveDoAfter<T>(
  57. EntityUid entity,
  58. [NotNullWhen(true)] out Shared.DoAfter.DoAfter? doAfter,
  59. [NotNullWhen(true)] out T? @event,
  60. out float progress)
  61. where T : DoAfterEvent
  62. {
  63. var playerEntity = _player.LocalEntity;
  64. doAfter = null;
  65. @event = null;
  66. progress = default;
  67. if (!TryComp(playerEntity, out ActiveDoAfterComponent? active))
  68. return false;
  69. if (_metadata.EntityPaused(playerEntity.Value))
  70. return false;
  71. var comp = Comp<DoAfterComponent>(playerEntity.Value);
  72. var time = GameTiming.CurTime;
  73. foreach (var candidate in comp.DoAfters.Values)
  74. {
  75. if (candidate.Cancelled)
  76. continue;
  77. if (candidate.Args.Target != entity)
  78. continue;
  79. if (candidate.Args.Event is not T candidateEvent)
  80. continue;
  81. @event = candidateEvent;
  82. doAfter = candidate;
  83. var elapsed = time - doAfter.StartTime;
  84. progress = (float) Math.Min(1, elapsed.TotalSeconds / doAfter.Args.Delay.TotalSeconds);
  85. return true;
  86. }
  87. return false;
  88. }
  89. }