using Fusion.Sockets; using Fusion.XR.Host.Grabbing; using System; using System.Collections; using System.Collections.Generic; using UnityEngine; using System.Threading.Tasks; using BNG; namespace Fusion.XR.Host.Rig { /** * * Hardware rig gives access to the various rig parts: head, left hand, right hand, and the play area, represented by the hardware rig itself * * Can be moved, either instantanesously, or with a camera fade * **/ public class FusionRig : MonoBehaviour, INetworkRunnerCallbacks { public HardwareHand leftHand; public HardwareHand rightHand; public HardwareHeadset headset; public NetworkRunner runner; public static FusionRig instance; public enum RunnerExpectations { NoRunner, // For offline usages PresetRunner, DetectRunner // should not be used in multipeer scenario } public RunnerExpectations runnerExpectations = RunnerExpectations.DetectRunner; bool searchingForRunner = false; [Header("Input interpolation")] public bool useInputInterpolation = false; public float interpolationDelay = 0.008f; XRHeadsetInputDevice headsetInputDevice; XRControllerInputDevice leftHandInputDevice; XRControllerInputDevice rightHandInputDevice; public float InterpolationDelay => interpolationDelay; public async Task FindRunner() { while (searchingForRunner) await Task.Delay(10); searchingForRunner = true; if (runner == null && runnerExpectations != RunnerExpectations.NoRunner) { if (runnerExpectations == RunnerExpectations.PresetRunner || NetworkProjectConfig.Global.PeerMode == NetworkProjectConfig.PeerModes.Multiple) { Debug.LogWarning("Runner has to be set in the inspector to forward the input"); } else { // Try to detect the runner runner = FindObjectOfType(true); var searchStart = Time.time; while (searchingForRunner && runner == null) { if (NetworkRunner.Instances.Count > 0) { runner = NetworkRunner.Instances[0]; } if (runner == null) { await System.Threading.Tasks.Task.Delay(10); } } } } searchingForRunner = false; return runner; } protected virtual void Awake() { instance = this; if (leftHand) leftHandInputDevice = leftHand.GetComponentInChildren(); if (rightHand) rightHandInputDevice = rightHand.GetComponentInChildren(); if (headset) headsetInputDevice = headset.GetComponentInChildren(); if (leftHandInputDevice == null || rightHandInputDevice == null || headsetInputDevice == null) { useInputInterpolation = false; } } protected virtual async void Start() { await FindRunner(); if (runner) { runner.AddCallbacks(this); } } private void OnDestroy() { if (searchingForRunner) Debug.LogError("Cancel searching for runner in HardwareRig"); searchingForRunner = false; if (runner) runner.RemoveCallbacks(this); } public void Update() { GetComponentInChildren().MovementForce = runner.IsConnectedToServer?1.25f: 0; } #region INetworkRunnerCallbacks // Prepare the input, that will be read by NetworkRig in the FixedUpdateNetwork public void OnInput(NetworkRunner runner, NetworkInput input) { RigInput rigInput = new RigInput(); rigInput.playAreaPosition = transform.position; rigInput.playAreaRotation = transform.rotation; if (useInputInterpolation) { var leftHandInterpolationPose = leftHandInputDevice.InterpolatedPose(InterpolationDelay); var rightHandInterpolationPose = rightHandInputDevice.InterpolatedPose(InterpolationDelay); var headsetInterpolationPose = headsetInputDevice.InterpolatedPose(InterpolationDelay); rigInput.leftHandPosition = leftHandInterpolationPose.position; rigInput.leftHandRotation = leftHandInterpolationPose.rotation; rigInput.rightHandPosition = rightHandInterpolationPose.position; rigInput.rightHandRotation = rightHandInterpolationPose.rotation; rigInput.headsetPosition = headsetInterpolationPose.position; rigInput.headsetRotation = headsetInterpolationPose.rotation; } else { rigInput.leftHandPosition = leftHand.transform.position; rigInput.leftHandRotation = leftHand.transform.rotation; rigInput.rightHandPosition = rightHand.transform.position; rigInput.rightHandRotation = rightHand.transform.rotation; rigInput.headsetPosition = headset.transform.position; rigInput.headsetRotation = headset.transform.rotation; } rigInput.leftHandCommand = leftHand.handCommand; rigInput.rightHandCommand = rightHand.handCommand; rigInput.leftGrabInfo = leftHand.grabber.GrabInfo; rigInput.rightGrabInfo = rightHand.grabber.GrabInfo; input.Set(rigInput); } #endregion #region INetworkRunnerCallbacks (unused) public void OnPlayerJoined(NetworkRunner runner, PlayerRef player) { } public void OnPlayerLeft(NetworkRunner runner, PlayerRef player) { } public void OnInputMissing(NetworkRunner runner, PlayerRef player, NetworkInput input) { } public void OnShutdown(NetworkRunner runner, ShutdownReason shutdownReason) { } public void OnConnectedToServer(NetworkRunner runner) { } public void OnDisconnectedFromServer(NetworkRunner runner, NetDisconnectReason reason) { } public void OnConnectRequest(NetworkRunner runner, NetworkRunnerCallbackArgs.ConnectRequest request, byte[] token) { } public void OnConnectFailed(NetworkRunner runner, NetAddress remoteAddress, NetConnectFailedReason reason) { } public void OnUserSimulationMessage(NetworkRunner runner, SimulationMessagePtr message) { } public void OnSessionListUpdated(NetworkRunner runner, List sessionList) { } public void OnCustomAuthenticationResponse(NetworkRunner runner, Dictionary data) { } public void OnHostMigration(NetworkRunner runner, HostMigrationToken hostMigrationToken) { } public void OnReliableDataReceived(NetworkRunner runner, PlayerRef player, ArraySegment data) { } public void OnSceneLoadDone(NetworkRunner runner) { } public void OnSceneLoadStart(NetworkRunner runner) { } public void OnObjectEnterAOI(NetworkRunner runner, NetworkObject obj, PlayerRef player) { } public void OnObjectExitAOI(NetworkRunner runner, NetworkObject obj, PlayerRef player) { } public void OnReliableDataReceived(NetworkRunner runner, PlayerRef player, ReliableKey key, ArraySegment data) { } public void OnReliableDataProgress(NetworkRunner runner, PlayerRef player, ReliableKey key, float progress) { } #endregion } }