// -------------------------------------------------------------------------------------------------------------------- // // Copyright (c) VRMADA, All rights reserved. // // -------------------------------------------------------------------------------------------------------------------- using System; using System.Collections.Generic; using UltimateXR.Avatar; using UltimateXR.Core; using UltimateXR.Core.Components.Singleton; using UltimateXR.Core.Settings; using UltimateXR.Extensions.Unity; using UltimateXR.Manipulation; using UnityEngine; #pragma warning disable 414 // Unused values namespace UltimateXR.Networking { /// /// Network Manager. This singleton will take care of all communication between the different users to keep them in /// sync. /// public partial class UxrNetworkManager : UxrSingleton { #region Inspector Properties/Serialized Fields [SerializeField] private UxrNetworkImplementation _networkImplementation; [SerializeField] private UxrNetworkVoiceImplementation _networkVoiceImplementation; [SerializeField] private bool _useSameSdkVoice = true; [SerializeField] private List _createdGlobalGameObjects = new List(); [SerializeField] private List _createdGlobalComponents = new List(); [SerializeField] private List _createdGlobalVoiceGameObjects = new List(); [SerializeField] private List _createdGlobalVoiceComponents = new List(); [SerializeField] private List _createdGlobalGameObjectPaths = new List(); [SerializeField] private List _createdGlobalComponentPaths = new List(); [SerializeField] private List _createdGlobalVoiceGameObjectPaths = new List(); [SerializeField] private List _createdGlobalVoiceComponentPaths = new List(); [SerializeField] private List _registeredAvatars = new List(); [SerializeField] private bool _grabbablePhysicsAddProjectScenes; [SerializeField] private bool _grabbablePhysicsAddPathPrefabs; [SerializeField] private string _grabbablePhysicsPathRoot; [SerializeField] private bool _grabbablePhysicsOnlyLog; [SerializeField] private GrabbablePhysicsSetup _grabbablePhysicsSetupInfo = new GrabbablePhysicsSetup(); #endregion #region Public Types & Data /// /// Event called right after the authority of the local user over a GameObject was requested. /// public event Action LocalAuthorityRequested; /// /// Event called right after a NetworkTransform component was enabled or disabled. /// public event Action NetworkTransformEnabled; /// /// Event called right after a NetworkRigidbody component was enabled or disabled. /// public event Action NetworkRigidbodyEnabled; /// /// Gets whether there is a network session active. /// public static bool IsSessionActive => IsServer || IsClient; /// /// Gets whether the current user is owner of the session. This can be either because there is no multiplayer session /// active or because the local user is the server. /// public static bool NoSessionOrSessionOwner => Instance == null || Instance._networkImplementation == null || Instance._networkImplementation.IsServer; /// /// Gets whether there is a network session active and the local user is the host (client and server at the same time). /// public static bool IsHost => IsServer && IsClient; /// /// Gets whether there is a network session active and the local user is the server. /// public static bool IsServer => HasInstance && Instance._networkImplementation != null && Instance._networkImplementation.IsServer; /// /// Gets whether there is a network session active and the local user is the server. /// public static bool IsClient => HasInstance && Instance._networkImplementation != null && Instance._networkImplementation.IsClient; /// /// Gets the network implementation. /// public UxrNetworkImplementation NetworkImplementation => _networkImplementation; /// /// Gets the network voice implementation. /// public UxrNetworkVoiceImplementation NetworkVoiceImplementation => _networkVoiceImplementation; /// /// Gets the global GameObjects created to add support for the given network SDK. /// public IEnumerable CreatedGlobalGameObjects => _createdGlobalGameObjects; /// /// Gets the global Components created to add support for the given network SDK. /// public IEnumerable CreatedGlobalComponents => _createdGlobalComponents; /// /// Gets the global GameObjects created to add support for the given network voice SDK. /// public IEnumerable CreatedGlobalVoiceGameObjects => _createdGlobalVoiceGameObjects; /// /// Gets the global Components created to add support for the given network voice SDK. /// public IEnumerable CreatedGlobalVoiceComponents => _createdGlobalVoiceComponents; /// /// Gets the registered avatar prefabs. /// public IEnumerable RegisteredAvatarPrefabs { get { foreach (var avatar in _registeredAvatars) { yield return avatar.AvatarPrefab; } } } #endregion #region Public Methods /// /// Requests authority of the local avatar over the given target object. The target object should have a valid network /// component using any given SDK, such as NetworkObject. /// /// GameObject with networking component public void RequestAuthority(GameObject gameObject) { NetworkImplementation.RequestAuthority(gameObject); OnAuthorityRequested(gameObject); } /// /// Enables or disables the NetworkTransform on the given object and all its children. /// /// Target /// Enabled state public void SetNetworkTransformEnabled(GameObject target, bool enabled) { NetworkImplementation.EnableNetworkTransform(gameObject, enabled); OnNetworkTransformEnabled(gameObject, enabled); } /// /// Enables or disables the NetworkRigidbody on the given object and all its children. /// /// Target /// Enabled state public void SetNetworkRigidbodyEnabled(GameObject target, bool enabled) { NetworkImplementation.EnableNetworkRigidbody(target, enabled); OnNetworkRigidbodyEnabled(target, enabled); } #endregion #region Unity /// /// Subscribes to events. /// protected override void OnEnable() { base.OnEnable(); if (NetworkImplementation) { UxrGrabManager.Instance.ObjectGrabbed += GrabManager_ObjectGrabbed; UxrGrabManager.Instance.ObjectReleased += GrabManager_ObjectReleased; UxrGrabManager.Instance.ObjectPlaced += GrabManager_ObjectPlaced; } } /// /// Unsubscribes from events. /// protected override void OnDisable() { base.OnDisable(); if (NetworkImplementation) { UxrGrabManager.Instance.ObjectGrabbed -= GrabManager_ObjectGrabbed; UxrGrabManager.Instance.ObjectReleased -= GrabManager_ObjectReleased; UxrGrabManager.Instance.ObjectPlaced -= GrabManager_ObjectPlaced; } } #endregion #region Event Handling Methods /// /// Called when an object was grabbed. Checks if the grabbed object's authority or a NetworkRigidbody enabled /// state need to change. A free object that was grabbed will now belong to the grabbing avatar and have its /// NetworkRigidbody disabled because it is not driven by physics anymore, but by the avatar's tracked hand. /// /// Event sender /// Event parameters private void GrabManager_ObjectGrabbed(object sender, UxrManipulationEventArgs e) { if (e.IsGrabbedStateChanged && e.GrabbableObject.RigidBodySource != null && e.GrabbableObject.RigidBodyDynamicOnRelease && e.GrabbableObject.CanUseRigidBody) { // From not grabbed to grabbed. Switch authority to local avatar if it's the one that grabbed it. if (e.Grabber != null && e.Grabber.Avatar == UxrAvatar.LocalAvatar && !NetworkImplementation.HasAuthority(e.GrabbableObject.gameObject)) { RequestAuthority(e.GrabbableObject.gameObject); } // Disable network rigidbody because avatar will drive the grabbed object's transform. SetNetworkRigidbodyEnabled(e.GrabbableObject.gameObject, false); } } /// /// Called when an object was released. Checks if the avatar that had the authority needs to give it to another avatar /// that keeps the grab or if the object was thrown and the NetworkRigidbody needs to be enabled. /// /// Event sender /// Event parameters private void GrabManager_ObjectReleased(object sender, UxrManipulationEventArgs e) { if (e.GrabbableObject.RigidBodySource != null && e.GrabbableObject.RigidBodyDynamicOnRelease && e.GrabbableObject.CanUseRigidBody) { if (e.IsGrabbedStateChanged) { // From grabbed to released. Enable network rigidbody. SetNetworkRigidbodyEnabled(e.GrabbableObject.gameObject, true); } else if (e.Grabber != null && !UxrGrabManager.Instance.IsBeingGrabbedBy(e.GrabbableObject, e.Grabber.Avatar)) { // An avatar released its last grip, check if we need to reassign the network authority NetworkImplementation.CheckReassignGrabAuthority(e.GrabbableObject.gameObject); } } } /// /// Called when an object was placed to disable the NetworkRigidbody. Checks if the place call comes from a user Place /// instead of a manipulation event, because manipulation events come from a grab where the rigidbody was already /// disabled at the time of the grab. /// /// Event sender /// Event parameters private void GrabManager_ObjectPlaced(object sender, UxrManipulationEventArgs e) { if (e.GrabbableObject.RigidBodySource != null && e.GrabbableObject.RigidBodyDynamicOnRelease && e.GrabbableObject.CanUseRigidBody) { if (e.Grabber == null) { // Source is a "manual" place SetNetworkRigidbodyEnabled(e.GrabbableObject.gameObject, false); } } } #endregion #region Event Trigger Methods /// /// Event trigger for . /// /// The GameObject with the NetworkRigidbody /// Whether the component was enabled or disabled private void OnNetworkRigidbodyEnabled(GameObject gameObject, bool enabled) { if (UxrGlobalSettings.Instance.LogLevelNetworking >= UxrLogLevel.Relevant) { Debug.Log($"{UxrConstants.NetworkingModule} NetworkRigidbody {(enabled ? "enabled" : "disabled")} on GameObject {gameObject.GetPathUnderScene()}."); } NetworkRigidbodyEnabled?.Invoke(gameObject, enabled); } /// /// Event trigger for . /// /// The GameObject with the NetworkRigidbody /// Whether the component was enabled or disabled private void OnNetworkTransformEnabled(GameObject gameObject, bool enabled) { if (UxrGlobalSettings.Instance.LogLevelNetworking >= UxrLogLevel.Relevant) { Debug.Log($"{UxrConstants.NetworkingModule} NetworkTransform {(enabled ? "enabled" : "disabled")} on GameObject {gameObject.GetPathUnderScene()}."); } NetworkTransformEnabled?.Invoke(gameObject, enabled); } /// /// Event trigger for . /// /// The GameObject to get the authority for private void OnAuthorityRequested(GameObject gameObject) { if (UxrGlobalSettings.Instance.LogLevelNetworking >= UxrLogLevel.Relevant) { Debug.Log($"{UxrConstants.NetworkingModule} Authority requested of local avatar over GameObject {gameObject.GetPathUnderScene()}."); } LocalAuthorityRequested?.Invoke(gameObject); } #endregion } } #pragma warning restore 414