@@ -14,6 +14,8 @@ internal class PlayerBodyPosition : NomaiVRModule<PlayerBodyPosition.Behaviour,
1414
1515 public class Behaviour : MonoBehaviour
1616 {
17+ public static Action OnSnapTurn ;
18+
1719 private Transform cameraParent ;
1820 private static Transform playArea ;
1921 private static OWCamera playerCamera ;
@@ -22,6 +24,10 @@ public class Behaviour : MonoBehaviour
2224 private static PlayerCharacterController playerController ;
2325 private static Autopilot autopilot ;
2426 private readonly SteamVR_Action_Boolean recenterAction = SteamVR_Actions . _default . Recenter ;
27+ private static readonly SteamVR_Action_Vector2 turnAction = SteamVR_Actions . _default . Look ;
28+ private static readonly float snapTurnInputThreshold = 0.15f ;
29+ private static bool isSnapTurnInCooldown = false ;
30+ private float lastTurnTime ;
2531
2632 internal void Start ( )
2733 {
@@ -95,12 +101,23 @@ internal void Update()
95101 }
96102
97103 UpdateRecenter ( ) ;
104+
105+ if ( ModSettings . SnapTurning )
106+ {
107+ // Check if time has passed and input stick was returned to neutral
108+ if ( isSnapTurnInCooldown && Time . time - lastTurnTime > 0.05f && Mathf . Abs ( turnAction . axis . x ) < snapTurnInputThreshold )
109+ {
110+ isSnapTurnInCooldown = false ;
111+ lastTurnTime = Time . time ;
112+ }
113+ }
98114 }
99115
100116 public class Patch : NomaiVRPatch
101117 {
102118 public override void ApplyPatches ( )
103119 {
120+ Postfix < OWInput > ( nameof ( OWInput . GetAxisValue ) , nameof ( PostGetAxisValue ) ) ;
104121 Postfix < PlayerCharacterController > ( nameof ( PlayerCharacterController . UpdateTurning ) , nameof ( PostCharacterTurning ) ) ;
105122 Postfix < JetpackThrusterController > ( nameof ( JetpackThrusterController . FixedUpdate ) , nameof ( PostThrusterUpdate ) ) ;
106123 Prefix < OWCamera > ( "set_" + nameof ( OWCamera . fieldOfView ) , nameof ( PatchOwCameraFOV ) ) ;
@@ -136,11 +153,25 @@ private static void PatchTurning(Action<Quaternion> rotationSetter)
136153 return ;
137154 }
138155
156+ if ( ModSettings . SnapTurning && ! PlayerState . InZeroG ( ) )
157+ {
158+ float turnInput = turnAction . axis . x ;
139159
140- var rotationSource = isControllerOriented ? LaserPointer . Behaviour . MovementLaser : playerCamera . transform ;
160+ // If snap turning, only do the snap turn, skip reorienting the play area
161+ if ( ! isSnapTurnInCooldown && Mathf . Abs ( turnInput ) > snapTurnInputThreshold )
162+ {
163+ isSnapTurnInCooldown = true ;
164+ float sign = Mathf . Sign ( turnInput ) ;
165+ Quaternion snapRotation = Quaternion . AngleAxis ( GetSnapTurnIncrement ( ) * sign , playerBody . transform . up ) ;
166+ var fromToSnap = Quaternion . FromToRotation ( playerBody . transform . forward , snapRotation * playerBody . transform . forward ) ;
141167
142- var fromTo = Quaternion . FromToRotation ( playerBody . transform . forward , Vector3 . ProjectOnPlane ( rotationSource . transform . forward , playerBody . transform . up ) ) ;
168+ rotationSetter ( fromToSnap * playerBody . transform . rotation ) ;
169+ OnSnapTurn ? . Invoke ( ) ;
170+ return ;
171+ }
172+ }
143173
174+ var rotationSource = isControllerOriented ? LaserPointer . Behaviour . MovementLaser : playerCamera . transform ;
144175 var magnitude = 0f ;
145176 if ( ! isControllerOriented )
146177 {
@@ -154,6 +185,7 @@ private static void PatchTurning(Action<Quaternion> rotationSetter)
154185 }
155186 }
156187
188+ var fromTo = Quaternion . FromToRotation ( playerBody . transform . forward , Vector3 . ProjectOnPlane ( rotationSource . transform . forward , playerBody . transform . up ) ) ;
157189 var targetRotation = fromTo * playerBody . transform . rotation ;
158190 var inverseRotation = Quaternion . Inverse ( fromTo ) * playArea . rotation ;
159191
@@ -170,6 +202,20 @@ private static void PatchTurning(Action<Quaternion> rotationSetter)
170202 }
171203 }
172204
205+ // Override vanilla input handling for disabling turning while snap turning is enabled
206+ private static void PostGetAxisValue ( ref Vector2 __result , IInputCommands command , InputMode mask )
207+ {
208+ if ( ! ModSettings . SnapTurning || ( OWInput . GetInputMode ( ) != InputMode . Character ) )
209+ {
210+ return ;
211+ }
212+
213+ if ( command . CommandType == InputConsts . InputCommandType . LOOK )
214+ {
215+ __result = Vector2 . zero ;
216+ }
217+ }
218+
173219 private static bool PatchOwCameraFOV ( OWCamera __instance )
174220 {
175221 //Prevents changing the fov of VR cameras
@@ -183,6 +229,25 @@ private static bool GetOwCameraFOVScaled(OWCamera __instance, ref float __result
183229 if ( __instance . mainCamera . stereoEnabled ) __result = CameraHelper . GetScaledFieldOfView ( __instance . mainCamera ) ;
184230 return ! __instance . mainCamera . stereoEnabled ;
185231 }
232+
233+ private static float GetSnapTurnIncrement ( )
234+ {
235+ switch ( ModSettings . SnapTurnIncrement )
236+ {
237+ case "15" :
238+ return 15f ;
239+ case "30" :
240+ return 30f ;
241+ case "45" :
242+ return 45f ;
243+ case "60" :
244+ return 60f ;
245+ case "90" :
246+ return 90f ;
247+ default :
248+ return 45f ;
249+ }
250+ }
186251 }
187252
188253 }
0 commit comments