using System.Collections.Generic; using BlockSpace.Voxels; using Photon.Pun; using Photon.VR; using UnityEngine; using UnityEngine.XR; namespace BlockSpace.Worlds { [DisallowMultipleComponent] public sealed class CreatorFlightController : MonoBehaviour { [SerializeField] private float flySpeed = 3.5f; [SerializeField] private float deadZone = 0.15f; private InputDevice leftHand; private bool flightProvidersDisabled; private readonly Dictionary cachedProviderStates = new Dictionary(); private CharacterController phasedController; private bool controllerCollisionCached; private bool cachedControllerEnabled; private bool cachedControllerDetectCollisions; private void OnEnable() { leftHand = InputDevices.GetDeviceAtXRNode(XRNode.LeftHand); } private void OnDisable() { RestoreProviders(); } private void Update() { if (!PhotonNetwork.InRoom) { RestoreProviders(); return; } VoxelGroupManager instance = VoxelGroupManager.Instance; if (instance == null || instance.EditingLocked || !instance.CreatorMode) { RestoreProviders(); RestoreCharacterControllerCollisions(); return; } DisableNonFlightProviders(); if (!leftHand.isValid) { leftHand = InputDevices.GetDeviceAtXRNode(XRNode.LeftHand); } Vector2 value = Vector2.zero; if (leftHand.isValid) { leftHand.TryGetFeatureValue(CommonUsages.primary2DAxis, out value); } if (Mathf.Abs(value.x) < deadZone) { value.x = 0f; } if (Mathf.Abs(value.y) < deadZone) { value.y = 0f; } Transform transform = ((PhotonVRManager.Manager != null) ? PhotonVRManager.Manager.Head : null); Transform localVrTeleportRoot = PlayerTeleportUtil.GetLocalVrTeleportRoot(); if (!(transform == null) && !(localVrTeleportRoot == null)) { Vector3 obj = ((transform.forward.sqrMagnitude > 0.0001f) ? transform.forward.normalized : Vector3.forward); Vector3 vector = ((transform.right.sqrMagnitude > 0.0001f) ? transform.right.normalized : Vector3.right); Vector3 vector2 = obj * value.y + vector * value.x; if (vector2.sqrMagnitude > 1f) { vector2.Normalize(); } CharacterController component = localVrTeleportRoot.GetComponent(); if (component != null) { ApplyCharacterControllerPhase(component); } Vector3 vector3 = vector2 * flySpeed; if (!(vector3.sqrMagnitude <= 0.0001f)) { localVrTeleportRoot.position += vector3 * Time.deltaTime; } } } private void DisableNonFlightProviders() { if (flightProvidersDisabled) { return; } PhotonVRManager manager = PhotonVRManager.Manager; if (!(manager == null)) { cachedProviderStates.Clear(); cachedProviderStates.Clear(); DisableBehavioursUnder(manager.gameObject); if (manager.LocalPlayer != null) { DisableBehavioursUnder(manager.LocalPlayer.gameObject); } if (manager.transform.root != null) { DisableBehavioursUnder(manager.transform.root.gameObject); } flightProvidersDisabled = true; } } private void DisableBehavioursUnder(GameObject root) { if (root == null) { return; } Behaviour[] componentsInChildren = root.GetComponentsInChildren(includeInactive: true); foreach (Behaviour behaviour in componentsInChildren) { if (!(behaviour == null) && !(behaviour == this)) { string text = behaviour.GetType().Name; if (!string.IsNullOrEmpty(text) && !text.Contains("TurnProvider") && !text.Contains("SmoothTurn") && !text.Contains("SnapTurn") && (text.Contains("GravityProvider") || text.Contains("MoveProvider") || text.Contains("LocomotionProvider") || text.Contains("TeleportationProvider") || text.Contains("ClimbProvider") || text.Contains("ContinuousMove") || text.Contains("DynamicMove"))) { cachedProviderStates[behaviour] = behaviour.enabled; behaviour.enabled = false; } } } } private void RestoreProviders() { if (!flightProvidersDisabled) { RestoreCharacterControllerCollisions(); return; } foreach (KeyValuePair cachedProviderState in cachedProviderStates) { if (cachedProviderState.Key != null) { cachedProviderState.Key.enabled = cachedProviderState.Value; } } cachedProviderStates.Clear(); flightProvidersDisabled = false; RestoreCharacterControllerCollisions(); } private void ApplyCharacterControllerPhase(CharacterController controller) { if (!(controller == null)) { if (phasedController != controller) { RestoreCharacterControllerCollisions(); phasedController = controller; cachedControllerEnabled = controller.enabled; cachedControllerDetectCollisions = controller.detectCollisions; controllerCollisionCached = true; } controller.enabled = false; controller.detectCollisions = false; } } private void RestoreCharacterControllerCollisions() { if (controllerCollisionCached && phasedController != null) { phasedController.enabled = cachedControllerEnabled; phasedController.detectCollisions = cachedControllerDetectCollisions; EnsureControllerUsableAfterEdit(phasedController); } phasedController = null; controllerCollisionCached = false; } private static void EnsureControllerUsableAfterEdit(CharacterController controller) { if (!(controller == null)) { controller.enabled = true; controller.detectCollisions = true; } } } }