EyeCursorOffsetSystem.cs 3.7 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091
  1. using System.Numerics;
  2. using Content.Client.Movement.Components;
  3. using Content.Shared.Camera;
  4. using Content.Shared.Inventory;
  5. using Content.Shared.Movement.Systems;
  6. using Robust.Client.Graphics;
  7. using Robust.Client.Input;
  8. using Robust.Shared.Map;
  9. using Robust.Client.Player;
  10. namespace Content.Client.Movement.Systems;
  11. public sealed partial class EyeCursorOffsetSystem : EntitySystem
  12. {
  13. [Dependency] private readonly IEyeManager _eyeManager = default!;
  14. [Dependency] private readonly IInputManager _inputManager = default!;
  15. [Dependency] private readonly IPlayerManager _player = default!;
  16. [Dependency] private readonly SharedTransformSystem _transform = default!;
  17. [Dependency] private readonly SharedContentEyeSystem _contentEye = default!;
  18. [Dependency] private readonly IMapManager _mapManager = default!;
  19. [Dependency] private readonly IClyde _clyde = default!;
  20. // This value is here to make sure the user doesn't have to move their mouse
  21. // all the way out to the edge of the screen to get the full offset.
  22. static private float _edgeOffset = 0.9f;
  23. public override void Initialize()
  24. {
  25. base.Initialize();
  26. SubscribeLocalEvent<EyeCursorOffsetComponent, GetEyeOffsetEvent>(OnGetEyeOffsetEvent);
  27. }
  28. private void OnGetEyeOffsetEvent(EntityUid uid, EyeCursorOffsetComponent component, ref GetEyeOffsetEvent args)
  29. {
  30. var offset = OffsetAfterMouse(uid, component);
  31. if (offset == null)
  32. return;
  33. args.Offset += offset.Value;
  34. }
  35. public Vector2? OffsetAfterMouse(EntityUid uid, EyeCursorOffsetComponent? component)
  36. {
  37. var localPlayer = _player.LocalPlayer?.ControlledEntity;
  38. var mousePos = _inputManager.MouseScreenPosition;
  39. var screenSize = _clyde.MainWindow.Size;
  40. var minValue = MathF.Min(screenSize.X / 2, screenSize.Y / 2) * _edgeOffset;
  41. var mouseNormalizedPos = new Vector2(-(mousePos.X - screenSize.X / 2) / minValue, (mousePos.Y - screenSize.Y / 2) / minValue); // X needs to be inverted here for some reason, otherwise it ends up flipped.
  42. if (localPlayer == null)
  43. return null;
  44. var playerPos = _transform.GetWorldPosition(localPlayer.Value);
  45. if (component == null)
  46. {
  47. component = EnsureComp<EyeCursorOffsetComponent>(uid);
  48. }
  49. // Doesn't move the offset if the mouse has left the game window!
  50. if (mousePos.Window != WindowId.Invalid)
  51. {
  52. // The offset must account for the in-world rotation.
  53. var eyeRotation = _eyeManager.CurrentEye.Rotation;
  54. var mouseActualRelativePos = Vector2.Transform(mouseNormalizedPos, System.Numerics.Quaternion.CreateFromAxisAngle(-System.Numerics.Vector3.UnitZ, (float)(eyeRotation.Opposite().Theta))); // I don't know, it just works.
  55. // Caps the offset into a circle around the player.
  56. mouseActualRelativePos *= component.MaxOffset;
  57. if (mouseActualRelativePos.Length() > component.MaxOffset)
  58. {
  59. mouseActualRelativePos = mouseActualRelativePos.Normalized() * component.MaxOffset;
  60. }
  61. component.TargetPosition = mouseActualRelativePos;
  62. //Makes the view not jump immediately when moving the cursor fast.
  63. if (component.CurrentPosition != component.TargetPosition)
  64. {
  65. Vector2 vectorOffset = component.TargetPosition - component.CurrentPosition;
  66. if (vectorOffset.Length() > component.OffsetSpeed)
  67. {
  68. vectorOffset = vectorOffset.Normalized() * component.OffsetSpeed;
  69. }
  70. component.CurrentPosition += vectorOffset;
  71. }
  72. }
  73. return component.CurrentPosition;
  74. }
  75. }