RandomWalkController.cs 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596
  1. using System.Numerics;
  2. using Content.Server.Physics.Components;
  3. using Content.Shared.Follower.Components;
  4. using Content.Shared.Throwing;
  5. using Robust.Server.GameObjects;
  6. using Robust.Shared.Physics.Components;
  7. using Robust.Shared.Physics.Controllers;
  8. using Robust.Shared.Player;
  9. using Robust.Shared.Random;
  10. using Robust.Shared.Timing;
  11. namespace Content.Server.Physics.Controllers;
  12. /// <summary>
  13. /// The entity system responsible for managing <see cref="RandomWalkComponent"/>s.
  14. /// Handles updating the direction they move in when their cooldown elapses.
  15. /// </summary>
  16. internal sealed class RandomWalkController : VirtualController
  17. {
  18. #region Dependencies
  19. [Dependency] private readonly IGameTiming _timing = default!;
  20. [Dependency] private readonly IRobustRandom _random = default!;
  21. [Dependency] private readonly PhysicsSystem _physics = default!;
  22. #endregion Dependencies
  23. public override void Initialize()
  24. {
  25. base.Initialize();
  26. SubscribeLocalEvent<RandomWalkComponent, ComponentStartup>(OnRandomWalkStartup);
  27. }
  28. /// <summary>
  29. /// Updates the cooldowns of all random walkers.
  30. /// If each of them is off cooldown it updates their velocity and resets its cooldown.
  31. /// </summary>
  32. /// <param name="prediction">??? Not documented anywhere I can see ???</param> // TODO: Document this.
  33. /// <param name="frameTime">The amount of time that has elapsed since the last time random walk cooldowns were updated.</param>
  34. public override void UpdateBeforeSolve(bool prediction, float frameTime)
  35. {
  36. base.UpdateBeforeSolve(prediction, frameTime);
  37. var query = EntityQueryEnumerator<RandomWalkComponent, PhysicsComponent>();
  38. while (query.MoveNext(out var uid, out var randomWalk, out var physics))
  39. {
  40. if (EntityManager.HasComponent<ActorComponent>(uid)
  41. || EntityManager.HasComponent<ThrownItemComponent>(uid)
  42. || EntityManager.HasComponent<FollowerComponent>(uid))
  43. continue;
  44. var curTime = _timing.CurTime;
  45. if (randomWalk.NextStepTime <= curTime)
  46. Update(uid, randomWalk, physics);
  47. }
  48. }
  49. /// <summary>
  50. /// Updates the direction and speed a random walker is moving at.
  51. /// Also resets the random walker's cooldown.
  52. /// </summary>
  53. /// <param name="randomWalk">The random walker state.</param>
  54. /// <param name="physics">The physics body associated with the random walker.</param>
  55. public void Update(EntityUid uid, RandomWalkComponent? randomWalk = null, PhysicsComponent? physics = null)
  56. {
  57. if(!Resolve(uid, ref randomWalk))
  58. return;
  59. var curTime = _timing.CurTime;
  60. randomWalk.NextStepTime = curTime + TimeSpan.FromSeconds(_random.NextDouble(randomWalk.MinStepCooldown.TotalSeconds, randomWalk.MaxStepCooldown.TotalSeconds));
  61. if(!Resolve(uid, ref physics))
  62. return;
  63. var pushVec = _random.NextAngle().ToVec();
  64. pushVec += randomWalk.BiasVector;
  65. pushVec.Normalize();
  66. if (randomWalk.ResetBiasOnWalk)
  67. randomWalk.BiasVector *= 0f;
  68. var pushStrength = _random.NextFloat(randomWalk.MinSpeed, randomWalk.MaxSpeed);
  69. _physics.SetLinearVelocity(uid, physics.LinearVelocity * randomWalk.AccumulatorRatio + pushVec * pushStrength, body: physics);
  70. }
  71. /// <summary>
  72. /// Syncs up a random walker step timing when the component starts up.
  73. /// </summary>
  74. /// <param name="uid">The uid of the random walker to start up.</param>
  75. /// <param name="comp">The state of the random walker to start up.</param>
  76. /// <param name="args">The startup prompt arguments.</param>
  77. private void OnRandomWalkStartup(EntityUid uid, RandomWalkComponent comp, ComponentStartup args)
  78. {
  79. if (comp.StepOnStartup)
  80. Update(uid, comp);
  81. else
  82. comp.NextStepTime = _timing.CurTime + TimeSpan.FromSeconds(_random.NextDouble(comp.MinStepCooldown.TotalSeconds, comp.MaxStepCooldown.TotalSeconds));
  83. }
  84. }