1
0

InputMoverComponent.cs 3.6 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889
  1. using System.Numerics;
  2. using Content.Shared.Movement.Systems;
  3. using Robust.Shared.GameStates;
  4. using Robust.Shared.Serialization;
  5. using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom;
  6. using Robust.Shared.Timing;
  7. namespace Content.Shared.Movement.Components
  8. {
  9. [RegisterComponent, NetworkedComponent]
  10. public sealed partial class InputMoverComponent : Component
  11. {
  12. // This class has to be able to handle server TPS being lower than client FPS.
  13. // While still having perfectly responsive movement client side.
  14. // We do this by keeping track of the exact sub-tick values that inputs are pressed on the client,
  15. // and then building a total movement vector based on those sub-tick steps.
  16. //
  17. // We keep track of the last sub-tick a movement input came in,
  18. // Then when a new input comes in, we calculate the fraction of the tick the LAST input was active for
  19. // (new sub-tick - last sub-tick)
  20. // and then add to the total-this-tick movement vector
  21. // by multiplying that fraction by the movement direction for the last input.
  22. // This allows us to incrementally build the movement vector for the current tick,
  23. // without having to keep track of some kind of list of inputs and calculating it later.
  24. //
  25. // We have to keep track of a separate movement vector for walking and sprinting,
  26. // since we don't actually know our current movement speed while processing inputs.
  27. // We change which vector we write into based on whether we were sprinting after the previous input.
  28. // (well maybe we do but the code is designed such that MoverSystem applies movement speed)
  29. // (and I'm not changing that)
  30. /// <summary>
  31. /// Should our velocity be applied to our parent?
  32. /// </summary>
  33. [ViewVariables(VVAccess.ReadWrite), DataField("toParent")]
  34. public bool ToParent = false;
  35. public GameTick LastInputTick;
  36. public ushort LastInputSubTick;
  37. public Vector2 CurTickWalkMovement;
  38. public Vector2 CurTickSprintMovement;
  39. public MoveButtons HeldMoveButtons = MoveButtons.None;
  40. /// <summary>
  41. /// Entity our movement is relative to.
  42. /// </summary>
  43. public EntityUid? RelativeEntity;
  44. /// <summary>
  45. /// Although our movement might be relative to a particular entity we may have an additional relative rotation
  46. /// e.g. if we've snapped to a different cardinal direction
  47. /// </summary>
  48. [ViewVariables]
  49. public Angle TargetRelativeRotation = Angle.Zero;
  50. /// <summary>
  51. /// The current relative rotation. This will lerp towards the <see cref="TargetRelativeRotation"/>.
  52. /// </summary>
  53. [ViewVariables]
  54. public Angle RelativeRotation;
  55. /// <summary>
  56. /// If we traverse on / off a grid then set a timer to update our relative inputs.
  57. /// </summary>
  58. [DataField(customTypeSerializer: typeof(TimeOffsetSerializer))]
  59. [ViewVariables(VVAccess.ReadWrite)]
  60. public TimeSpan LerpTarget;
  61. public const float LerpTime = 1.0f;
  62. public bool Sprinting => (HeldMoveButtons & MoveButtons.Walk) == 0x0;
  63. [ViewVariables(VVAccess.ReadWrite)]
  64. public bool CanMove = true;
  65. }
  66. [Serializable, NetSerializable]
  67. public sealed class InputMoverComponentState : ComponentState
  68. {
  69. public MoveButtons HeldMoveButtons;
  70. public NetEntity? RelativeEntity;
  71. public Angle TargetRelativeRotation;
  72. public Angle RelativeRotation;
  73. public TimeSpan LerpTarget;
  74. public bool CanMove;
  75. }
  76. }