using System.Collections.Generic; using Photon.VR; using UnityEngine; using UnityEngine.InputSystem.XR; using UnityEngine.XR; using UnityEngine.XR.Interaction.Toolkit.Locomotion; using UnityEngine.XR.Interaction.Toolkit.Locomotion.Jump; using UnityEngine.XR.Interaction.Toolkit.Locomotion.Movement; using UnityEngine.XR.Interaction.Toolkit.Locomotion.Turning; namespace BlockSpace.Voxels { [DisallowMultipleComponent] public sealed class DesktopRigController : MonoBehaviour { [SerializeField] private Transform rigRoot; [SerializeField] private Transform headTransform; [SerializeField] private Transform leftHandTransform; [SerializeField] private Transform rightHandTransform; [SerializeField] private CharacterController characterController; [SerializeField] private float mouseSensitivity = 2.25f; [SerializeField] private float defaultMoveSpeed = 5f; [SerializeField] private float defaultJumpHeight = 1.1f; [SerializeField] private float handHorizontalOffset = 0.22f; [SerializeField] private float handVerticalOffset = -0.18f; [SerializeField] private float handForwardOffset = 0.35f; [SerializeField] private float maxLookPitch = 85f; [SerializeField] private float nonCreatorMoveSmoothing = 12f; [SerializeField] private float creatorMoveSmoothing = 40f; private readonly List vrLocomotionProviders = new List(); private readonly Dictionary vrLocomotionStates = new Dictionary(); private readonly List trackedPoseDrivers = new List(); private readonly Dictionary trackedPoseDriverStates = new Dictionary(); private readonly Dictionary phaseColliderStates = new Dictionary(); private ContinuousMoveProvider moveProvider; private JumpProvider jumpProvider; private ContinuousTurnProvider turnProvider; private float verticalVelocity; private float pitch; private bool pitchInitialized; private bool pcModeActive; private Vector3 smoothedHorizontalVelocity; private bool characterControllerCollisionCached; private bool cachedCharacterControllerEnabled; private bool cachedCharacterControllerDetectCollisions; public void Configure(Transform trackingOrigin, Transform head, Transform leftHand, Transform rightHand) { if (trackingOrigin != null) { rigRoot = trackingOrigin; } if (head != null) { headTransform = head; } if (leftHand != null) { leftHandTransform = leftHand; } if (rightHand != null) { rightHandTransform = rightHand; } ResolveReferences(); } private void Awake() { ResolveReferences(); RefreshLocomotionProviders(); RefreshTrackedPoseDrivers(); } private void OnEnable() { ResolveReferences(); } private void OnDisable() { SetPcModeActive(active: false); RestoreCharacterControllerCollisions(); UnlockCursor(); } private void Update() { ResolveReferences(); bool flag = DetectXRInputActive(); SetPcModeActive(!flag); if (!flag) { EnsureCursorLocked(); HandleLook(); HandleMovement(); UpdateProxyHands(); } } private void ResolveReferences() { if (rigRoot == null) { rigRoot = base.transform; } if (headTransform == null) { headTransform = ((Camera.main != null) ? Camera.main.transform : null); if (headTransform == null && PhotonVRManager.Manager != null) { headTransform = PhotonVRManager.Manager.Head; } } if (leftHandTransform == null && PhotonVRManager.Manager != null) { leftHandTransform = PhotonVRManager.Manager.LeftHand; } if (rightHandTransform == null && PhotonVRManager.Manager != null) { rightHandTransform = PhotonVRManager.Manager.RightHand; } if (characterController == null && rigRoot != null) { characterController = rigRoot.GetComponent(); if (characterController == null) { characterController = rigRoot.GetComponentInParent(); } if (characterController == null) { characterController = rigRoot.GetComponentInChildren(includeInactive: true); } } if (characterController != null) { rigRoot = characterController.transform; } if (!pitchInitialized && headTransform != null) { pitch = NormalizeAngle(headTransform.localEulerAngles.x); pitchInitialized = true; } if (moveProvider == null) { ContinuousMoveProvider[] array = Object.FindObjectsByType(FindObjectsInactive.Include, FindObjectsSortMode.None); if (array.Length != 0) { moveProvider = array[0]; } } if (jumpProvider == null) { JumpProvider[] array2 = Object.FindObjectsByType(FindObjectsInactive.Include, FindObjectsSortMode.None); if (array2.Length != 0) { jumpProvider = array2[0]; } } if (turnProvider == null) { ContinuousTurnProvider[] array3 = Object.FindObjectsByType(FindObjectsInactive.Include, FindObjectsSortMode.None); if (array3.Length != 0) { turnProvider = array3[0]; } } } private void RefreshLocomotionProviders() { vrLocomotionProviders.Clear(); LocomotionProvider[] array = Object.FindObjectsByType(FindObjectsInactive.Include, FindObjectsSortMode.None); foreach (LocomotionProvider locomotionProvider in array) { if (!(locomotionProvider == null) && !vrLocomotionProviders.Contains(locomotionProvider)) { vrLocomotionProviders.Add(locomotionProvider); } } } private void RefreshTrackedPoseDrivers() { trackedPoseDrivers.Clear(); TrackedPoseDriver[] array = Object.FindObjectsByType(FindObjectsInactive.Include, FindObjectsSortMode.None); foreach (TrackedPoseDriver trackedPoseDriver in array) { if (!(trackedPoseDriver == null) && !trackedPoseDrivers.Contains(trackedPoseDriver)) { trackedPoseDrivers.Add(trackedPoseDriver); } } } private void SetPcModeActive(bool active) { if (pcModeActive == active) { return; } pcModeActive = active; if (pcModeActive) { RefreshLocomotionProviders(); RefreshTrackedPoseDrivers(); for (int i = 0; i < vrLocomotionProviders.Count; i++) { LocomotionProvider locomotionProvider = vrLocomotionProviders[i]; if (!(locomotionProvider == null)) { if (!vrLocomotionStates.ContainsKey(locomotionProvider)) { vrLocomotionStates.Add(locomotionProvider, locomotionProvider.enabled); } locomotionProvider.enabled = false; } } for (int j = 0; j < trackedPoseDrivers.Count; j++) { TrackedPoseDriver trackedPoseDriver = trackedPoseDrivers[j]; if (!(trackedPoseDriver == null)) { if (!trackedPoseDriverStates.ContainsKey(trackedPoseDriver)) { trackedPoseDriverStates.Add(trackedPoseDriver, trackedPoseDriver.enabled); } trackedPoseDriver.enabled = false; } } return; } foreach (KeyValuePair vrLocomotionState in vrLocomotionStates) { if (vrLocomotionState.Key != null) { vrLocomotionState.Key.enabled = vrLocomotionState.Value; } } vrLocomotionStates.Clear(); foreach (KeyValuePair trackedPoseDriverState in trackedPoseDriverStates) { if (trackedPoseDriverState.Key != null) { trackedPoseDriverState.Key.enabled = trackedPoseDriverState.Value; } } trackedPoseDriverStates.Clear(); verticalVelocity = 0f; } private void HandleLook() { if (!(rigRoot == null) && !(headTransform == null)) { float angle = Input.GetAxisRaw("Mouse X") * GetMouseLookSpeed(); float num = Input.GetAxisRaw("Mouse Y") * GetMouseLookSpeed(); rigRoot.Rotate(Vector3.up, angle, Space.World); pitch = Mathf.Clamp(pitch - num, 0f - maxLookPitch, maxLookPitch); headTransform.localRotation = Quaternion.Euler(pitch, 0f, 0f); } } private void HandleMovement() { if (rigRoot == null || headTransform == null) { return; } bool flag = VoxelGroupManager.Instance != null && !VoxelGroupManager.Instance.EditingLocked && VoxelGroupManager.Instance.CreatorMode; ApplyCharacterControllerPhase(flag); Vector2 zero = Vector2.zero; if (Input.GetKey(KeyCode.W)) { zero.y += 1f; } if (Input.GetKey(KeyCode.S)) { zero.y -= 1f; } if (Input.GetKey(KeyCode.D)) { zero.x += 1f; } if (Input.GetKey(KeyCode.A)) { zero.x -= 1f; } if (zero.sqrMagnitude > 1f) { zero.Normalize(); } Vector3 forward = headTransform.forward; Vector3 right = headTransform.right; if (!flag) { forward.y = 0f; right.y = 0f; } forward = ((forward.sqrMagnitude > 0.0001f) ? forward.normalized : Vector3.forward); right = ((right.sqrMagnitude > 0.0001f) ? right.normalized : Vector3.right); Vector3 b = (forward * zero.y + right * zero.x) * GetMoveSpeed(); float b2 = ((VoxelGroupManager.Instance != null && !VoxelGroupManager.Instance.CreatorMode) ? nonCreatorMoveSmoothing : creatorMoveSmoothing); float t = 1f - Mathf.Exp((0f - Mathf.Max(0.01f, b2)) * Time.deltaTime); smoothedHorizontalVelocity = Vector3.Lerp(smoothedHorizontalVelocity, b, t); if (characterController != null) { if (flag) { verticalVelocity = 0f; rigRoot.position += smoothedHorizontalVelocity * Time.deltaTime; return; } if (characterController.isGrounded && verticalVelocity < 0f) { verticalVelocity = -2f; } if (characterController.isGrounded && Input.GetKeyDown(KeyCode.Space)) { verticalVelocity = Mathf.Sqrt(GetJumpHeight() * -2f * Physics.gravity.y); } verticalVelocity += Physics.gravity.y * Time.deltaTime; Vector3 vector = smoothedHorizontalVelocity + Vector3.up * verticalVelocity; characterController.Move(vector * Time.deltaTime); } else { if (Input.GetKeyDown(KeyCode.Space) && Mathf.Abs(verticalVelocity) < 0.001f) { verticalVelocity = Mathf.Sqrt(GetJumpHeight() * -2f * Physics.gravity.y); } verticalVelocity += Physics.gravity.y * Time.deltaTime; rigRoot.position += (smoothedHorizontalVelocity + Vector3.up * verticalVelocity) * Time.deltaTime; } } private void UpdateProxyHands() { if (!(headTransform == null)) { Quaternion rotation = headTransform.rotation; Vector3 position = headTransform.TransformPoint(new Vector3(0f - handHorizontalOffset, handVerticalOffset, handForwardOffset)); Vector3 position2 = headTransform.TransformPoint(new Vector3(handHorizontalOffset, handVerticalOffset, handForwardOffset)); if (leftHandTransform != null) { leftHandTransform.SetPositionAndRotation(position, rotation); } if (rightHandTransform != null) { rightHandTransform.SetPositionAndRotation(position2, rotation); } } } private float GetMoveSpeed() { if (!(moveProvider != null)) { return defaultMoveSpeed; } return moveProvider.moveSpeed; } private float GetJumpHeight() { if (!(jumpProvider != null)) { return defaultJumpHeight; } return jumpProvider.jumpHeight; } private float GetMouseLookSpeed() { if (turnProvider == null) { return mouseSensitivity; } return turnProvider.turnSpeed / 180f * mouseSensitivity; } private void ApplyCharacterControllerPhase(bool phaseThrough) { if (phaseThrough) { ApplyRigColliderPhase(); if (characterController != null && !characterControllerCollisionCached) { cachedCharacterControllerEnabled = characterController.enabled; cachedCharacterControllerDetectCollisions = characterController.detectCollisions; characterControllerCollisionCached = true; } if (characterController != null) { characterController.enabled = false; characterController.detectCollisions = false; } } else { RestoreCharacterControllerCollisions(); } } private void ApplyRigColliderPhase() { Collider[] componentsInChildren = ((rigRoot != null) ? rigRoot : base.transform).GetComponentsInChildren(includeInactive: true); foreach (Collider collider in componentsInChildren) { if (!(collider == null) && !collider.isTrigger && !(collider is CharacterController)) { if (!phaseColliderStates.ContainsKey(collider)) { phaseColliderStates.Add(collider, collider.enabled); } collider.enabled = false; } } } private void RestoreCharacterControllerCollisions() { if (!characterControllerCollisionCached || characterController == null) { characterControllerCollisionCached = false; RestoreRigColliderPhase(); RestoreCharacterControllerForPcMovement(); } else { characterController.enabled = cachedCharacterControllerEnabled; characterController.detectCollisions = cachedCharacterControllerDetectCollisions; characterControllerCollisionCached = false; RestoreRigColliderPhase(); RestoreCharacterControllerForPcMovement(); } } private void RestoreCharacterControllerForPcMovement() { if (pcModeActive && !(characterController == null)) { characterController.enabled = true; characterController.detectCollisions = true; } } private void RestoreRigColliderPhase() { foreach (KeyValuePair phaseColliderState in phaseColliderStates) { if (phaseColliderState.Key != null) { phaseColliderState.Key.enabled = phaseColliderState.Value; } } phaseColliderStates.Clear(); } private void EnsureCursorLocked() { if (Application.isFocused) { Cursor.lockState = CursorLockMode.Locked; Cursor.visible = false; } } private static void UnlockCursor() { Cursor.lockState = CursorLockMode.None; Cursor.visible = true; } private static float NormalizeAngle(float angle) { if (angle > 180f) { angle -= 360f; } return angle; } private static bool DetectXRInputActive() { if (!InputDevices.GetDeviceAtXRNode(XRNode.Head).isValid && !InputDevices.GetDeviceAtXRNode(XRNode.LeftHand).isValid) { return InputDevices.GetDeviceAtXRNode(XRNode.RightHand).isValid; } return true; } } }