Files
2026-06-01 17:19:55 +02:00

537 lines
14 KiB
C#

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<LocomotionProvider> vrLocomotionProviders = new List<LocomotionProvider>();
private readonly Dictionary<LocomotionProvider, bool> vrLocomotionStates = new Dictionary<LocomotionProvider, bool>();
private readonly List<TrackedPoseDriver> trackedPoseDrivers = new List<TrackedPoseDriver>();
private readonly Dictionary<TrackedPoseDriver, bool> trackedPoseDriverStates = new Dictionary<TrackedPoseDriver, bool>();
private readonly Dictionary<Collider, bool> phaseColliderStates = new Dictionary<Collider, bool>();
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<CharacterController>();
if (characterController == null)
{
characterController = rigRoot.GetComponentInParent<CharacterController>();
}
if (characterController == null)
{
characterController = rigRoot.GetComponentInChildren<CharacterController>(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<ContinuousMoveProvider>(FindObjectsInactive.Include, FindObjectsSortMode.None);
if (array.Length != 0)
{
moveProvider = array[0];
}
}
if (jumpProvider == null)
{
JumpProvider[] array2 = Object.FindObjectsByType<JumpProvider>(FindObjectsInactive.Include, FindObjectsSortMode.None);
if (array2.Length != 0)
{
jumpProvider = array2[0];
}
}
if (turnProvider == null)
{
ContinuousTurnProvider[] array3 = Object.FindObjectsByType<ContinuousTurnProvider>(FindObjectsInactive.Include, FindObjectsSortMode.None);
if (array3.Length != 0)
{
turnProvider = array3[0];
}
}
}
private void RefreshLocomotionProviders()
{
vrLocomotionProviders.Clear();
LocomotionProvider[] array = Object.FindObjectsByType<LocomotionProvider>(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<TrackedPoseDriver>(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<LocomotionProvider, bool> vrLocomotionState in vrLocomotionStates)
{
if (vrLocomotionState.Key != null)
{
vrLocomotionState.Key.enabled = vrLocomotionState.Value;
}
}
vrLocomotionStates.Clear();
foreach (KeyValuePair<TrackedPoseDriver, bool> 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<Collider>(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<Collider, bool> 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;
}
}
}