1
0

UseDelaySystem.cs 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184
  1. using System.Diagnostics.CodeAnalysis;
  2. using Robust.Shared.GameStates;
  3. using Robust.Shared.Timing;
  4. namespace Content.Shared.Timing;
  5. public sealed class UseDelaySystem : EntitySystem
  6. {
  7. [Dependency] private readonly IGameTiming _gameTiming = default!;
  8. [Dependency] private readonly MetaDataSystem _metadata = default!;
  9. private const string DefaultId = "default";
  10. public override void Initialize()
  11. {
  12. base.Initialize();
  13. SubscribeLocalEvent<UseDelayComponent, MapInitEvent>(OnMapInit);
  14. SubscribeLocalEvent<UseDelayComponent, EntityUnpausedEvent>(OnUnpaused);
  15. SubscribeLocalEvent<UseDelayComponent, ComponentGetState>(OnDelayGetState);
  16. SubscribeLocalEvent<UseDelayComponent, ComponentHandleState>(OnDelayHandleState);
  17. }
  18. private void OnDelayHandleState(Entity<UseDelayComponent> ent, ref ComponentHandleState args)
  19. {
  20. if (args.Current is not UseDelayComponentState state)
  21. return;
  22. ent.Comp.Delays.Clear();
  23. // At time of writing sourcegen networking doesn't deep copy so this will mispredict if you try.
  24. foreach (var (key, delay) in state.Delays)
  25. {
  26. ent.Comp.Delays[key] = new UseDelayInfo(delay.Length, delay.StartTime, delay.EndTime);
  27. }
  28. }
  29. private void OnDelayGetState(Entity<UseDelayComponent> ent, ref ComponentGetState args)
  30. {
  31. args.State = new UseDelayComponentState()
  32. {
  33. Delays = ent.Comp.Delays
  34. };
  35. }
  36. private void OnMapInit(Entity<UseDelayComponent> ent, ref MapInitEvent args)
  37. {
  38. // Set default delay length from the prototype
  39. // This makes it easier for simple use cases that only need a single delay
  40. SetLength((ent, ent.Comp), ent.Comp.Delay, DefaultId);
  41. }
  42. private void OnUnpaused(Entity<UseDelayComponent> ent, ref EntityUnpausedEvent args)
  43. {
  44. // We have to do this manually, since it's not just a single field.
  45. foreach (var entry in ent.Comp.Delays.Values)
  46. {
  47. entry.EndTime += args.PausedTime;
  48. }
  49. }
  50. /// <summary>
  51. /// Sets the length of the delay with the specified ID.
  52. /// </summary>
  53. /// <remarks>
  54. /// This will add a UseDelay component to the entity if it doesn't have one.
  55. /// </remarks>
  56. public bool SetLength(Entity<UseDelayComponent?> ent, TimeSpan length, string id = DefaultId)
  57. {
  58. EnsureComp<UseDelayComponent>(ent.Owner, out var comp);
  59. if (comp.Delays.TryGetValue(id, out var entry))
  60. {
  61. if (entry.Length == length)
  62. return true;
  63. entry.Length = length;
  64. }
  65. else
  66. {
  67. comp.Delays.Add(id, new UseDelayInfo(length));
  68. }
  69. Dirty(ent);
  70. return true;
  71. }
  72. /// <summary>
  73. /// Returns true if the entity has a currently active UseDelay with the specified ID.
  74. /// </summary>
  75. public bool IsDelayed(Entity<UseDelayComponent?> ent, string id = DefaultId)
  76. {
  77. if (!Resolve(ent, ref ent.Comp, false))
  78. return false;
  79. if (!ent.Comp.Delays.TryGetValue(id, out var entry))
  80. return false;
  81. return entry.EndTime >= _gameTiming.CurTime;
  82. }
  83. /// <summary>
  84. /// Cancels the delay with the specified ID.
  85. /// </summary>
  86. public void CancelDelay(Entity<UseDelayComponent> ent, string id = DefaultId)
  87. {
  88. if (!ent.Comp.Delays.TryGetValue(id, out var entry))
  89. return;
  90. entry.EndTime = _gameTiming.CurTime;
  91. Dirty(ent);
  92. }
  93. /// <summary>
  94. /// Tries to get info about the delay with the specified ID. See <see cref="UseDelayInfo"/>.
  95. /// </summary>
  96. /// <param name="ent"></param>
  97. /// <param name="info"></param>
  98. /// <param name="id"></param>
  99. /// <returns></returns>
  100. public bool TryGetDelayInfo(Entity<UseDelayComponent> ent, [NotNullWhen(true)] out UseDelayInfo? info, string id = DefaultId)
  101. {
  102. return ent.Comp.Delays.TryGetValue(id, out info);
  103. }
  104. /// <summary>
  105. /// Returns info for the delay that will end farthest in the future.
  106. /// </summary>
  107. public UseDelayInfo GetLastEndingDelay(Entity<UseDelayComponent> ent)
  108. {
  109. if (!ent.Comp.Delays.TryGetValue(DefaultId, out var last))
  110. return new UseDelayInfo(TimeSpan.Zero);
  111. foreach (var entry in ent.Comp.Delays)
  112. {
  113. if (entry.Value.EndTime > last.EndTime)
  114. last = entry.Value;
  115. }
  116. return last;
  117. }
  118. /// <summary>
  119. /// Resets the delay with the specified ID for this entity if possible.
  120. /// </summary>
  121. /// <param name="checkDelayed">Check if the entity has an ongoing delay with the specified ID.
  122. /// If it does, return false and don't reset it.
  123. /// Otherwise reset it and return true.</param>
  124. public bool TryResetDelay(Entity<UseDelayComponent> ent, bool checkDelayed = false, string id = DefaultId)
  125. {
  126. if (checkDelayed && IsDelayed((ent.Owner, ent.Comp), id))
  127. return false;
  128. if (!ent.Comp.Delays.TryGetValue(id, out var entry))
  129. return false;
  130. var curTime = _gameTiming.CurTime;
  131. entry.StartTime = curTime;
  132. entry.EndTime = curTime - _metadata.GetPauseTime(ent) + entry.Length;
  133. Dirty(ent);
  134. return true;
  135. }
  136. public bool TryResetDelay(EntityUid uid, bool checkDelayed = false, UseDelayComponent? component = null, string id = DefaultId)
  137. {
  138. if (!Resolve(uid, ref component, false))
  139. return false;
  140. return TryResetDelay((uid, component), checkDelayed, id);
  141. }
  142. /// <summary>
  143. /// Resets all delays on the entity.
  144. /// </summary>
  145. public void ResetAllDelays(Entity<UseDelayComponent> ent)
  146. {
  147. var curTime = _gameTiming.CurTime;
  148. foreach (var entry in ent.Comp.Delays.Values)
  149. {
  150. entry.StartTime = curTime;
  151. entry.EndTime = curTime - _metadata.GetPauseTime(ent) + entry.Length;
  152. }
  153. Dirty(ent);
  154. }
  155. }