Add ultimate xr
This commit is contained in:
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 342bbee74e734c30970bd3ce59da488b
|
||||
timeCreated: 1644566116
|
||||
@@ -0,0 +1,155 @@
|
||||
// --------------------------------------------------------------------------------------------------------------------
|
||||
// <copyright file="UxrAvatarComponent.cs" company="VRMADA">
|
||||
// Copyright (c) VRMADA, All rights reserved.
|
||||
// </copyright>
|
||||
// --------------------------------------------------------------------------------------------------------------------
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using UltimateXR.Avatar;
|
||||
using UltimateXR.Extensions.Unity;
|
||||
using UnityEngine;
|
||||
|
||||
namespace UltimateXR.Core.Components.Composite
|
||||
{
|
||||
/// <summary>
|
||||
/// Generic base class for components that are added to an <see cref="UxrAvatar" /> and we want to keep track of.
|
||||
/// It allows to enumerate components using static methods.
|
||||
/// This class could have instead inherited from <see cref="UxrComponent{TP,TC}" /> but we avoided
|
||||
/// this to not have redundancy between Avatar/Parent properties and methods.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">Component type</typeparam>
|
||||
public abstract class UxrAvatarComponent<T> : UxrComponent<T> where T : UxrAvatarComponent<T>
|
||||
{
|
||||
#region Public Types & Data
|
||||
|
||||
/// <summary>
|
||||
/// Gets all the components, enabled or not, of this specific type that belong to the local avatar.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Components that have never been enabled are not returned. Components are automatically registered through their
|
||||
/// Awake() call, which is never called if the object has never been enabled. In this case it is recommended to resort
|
||||
/// to <see cref="UnityEngine.GameObject.GetComponentsInChildren{T}(bool)">GetComponentsInChildren</see>.
|
||||
/// </remarks>
|
||||
public static IEnumerable<T> AllComponentsInLocalAvatar => AllComponents.Where(c => c.Avatar != null && c.Avatar.AvatarMode == UxrAvatarMode.Local);
|
||||
|
||||
/// <summary>
|
||||
/// Gets all the enabled components of this specific type that belong to the local avatar.
|
||||
/// </summary>
|
||||
public static IEnumerable<T> EnabledComponentsInLocalAvatar => AllComponents.Where(c => c.Avatar != null && c.Avatar.AvatarMode == UxrAvatarMode.Local && c.isActiveAndEnabled);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the local avatar or null if there is none.
|
||||
/// </summary>
|
||||
public static UxrAvatar LocalAvatar
|
||||
{
|
||||
get
|
||||
{
|
||||
T component = AllComponents.FirstOrDefault(c => c.Avatar != null && c.Avatar.AvatarMode == UxrAvatarMode.Local);
|
||||
return component == null ? null : component.Avatar;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets all the components, enabled of not, of this specific type that belong to this instance of the avatar.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Components that have never been enabled are not returned. Components are automatically registered through their
|
||||
/// Awake() call, which is never called if the object has never been enabled. In this case it is recommended to resort
|
||||
/// to <see cref="GameObject.GetComponentsInChildren{T}(bool)" />.
|
||||
/// </remarks>
|
||||
public IEnumerable<T> AllComponentsInAvatar => GetComponents(Avatar, true);
|
||||
|
||||
/// <summary>
|
||||
/// Gets only the enabled components of this specific type that belong to this instance of the avatar.
|
||||
/// </summary>
|
||||
public IEnumerable<T> EnabledComponentsInAvatar => GetComponents(Avatar);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the <see cref="UxrAvatar" /> the component belongs to.
|
||||
/// </summary>
|
||||
public UxrAvatar Avatar
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_avatar == null)
|
||||
{
|
||||
_avatar = this.SafeGetComponentInParent<UxrAvatar>();
|
||||
}
|
||||
|
||||
return _avatar;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Public Methods
|
||||
|
||||
/// <summary>
|
||||
/// Gets the components of a specific avatar.
|
||||
/// </summary>
|
||||
/// <param name="avatar">Avatar to get the components from</param>
|
||||
/// <param name="includeDisabled">Whether to include disabled components or not</param>
|
||||
/// <returns>Components meeting the criteria</returns>
|
||||
/// <remarks>
|
||||
/// When using the <paramref name="includeDisabled" /> parameter, components that have never been enabled are not
|
||||
/// returned. Components are automatically registered through their Awake() call, which is never called if the object
|
||||
/// has never been enabled. In this case it is recommended to resort to
|
||||
/// <see cref="GameObject.GetComponentsInChildren{T}(bool)" />.
|
||||
/// </remarks>
|
||||
public static IEnumerable<T> GetComponents(UxrAvatar avatar, bool includeDisabled = false)
|
||||
{
|
||||
if (includeDisabled)
|
||||
{
|
||||
return AllComponents.Where(c => c.Avatar == avatar);
|
||||
}
|
||||
return AllComponents.Where(c => c.Avatar == avatar && c.isActiveAndEnabled);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the components of a specific avatar.
|
||||
/// </summary>
|
||||
/// <param name="avatar">Avatar to get the components from</param>
|
||||
/// <param name="includeDisabled">Whether to include disabled components or not</param>
|
||||
/// <returns>Components meeting the criteria</returns>
|
||||
/// <remarks>
|
||||
/// When using the <paramref name="includeDisabled" /> parameter, components that have never been enabled are not
|
||||
/// returned. Components are automatically registered through their Awake() call, which is never called if the object
|
||||
/// has never been enabled. In this case it is recommended to resort to
|
||||
/// <see cref="GameObject.GetComponentsInChildren{T}(bool)" />.
|
||||
/// </remarks>
|
||||
public static IEnumerable<TC> GetComponents<TC>(UxrAvatar avatar, bool includeDisabled = false) where TC : T
|
||||
{
|
||||
if (includeDisabled)
|
||||
{
|
||||
return AllComponents.OfType<TC>().Where(c => c.Avatar == avatar);
|
||||
}
|
||||
|
||||
return AllComponents.OfType<TC>().Where(c => c.Avatar == avatar && c.isActiveAndEnabled);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Unity
|
||||
|
||||
/// <summary>
|
||||
/// Pre-caches the avatar component.
|
||||
/// </summary>
|
||||
protected override void Awake()
|
||||
{
|
||||
base.Awake();
|
||||
|
||||
if (_avatar == null)
|
||||
{
|
||||
_avatar = GetComponentInParent<UxrAvatar>();
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Private Types & Data
|
||||
|
||||
private UxrAvatar _avatar;
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 73f120c94e676034eaa2f80d76c32e85
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,320 @@
|
||||
// --------------------------------------------------------------------------------------------------------------------
|
||||
// <copyright file="UxrGrabbableObjectComponent.cs" company="VRMADA">
|
||||
// Copyright (c) VRMADA, All rights reserved.
|
||||
// </copyright>
|
||||
// --------------------------------------------------------------------------------------------------------------------
|
||||
using UltimateXR.Core.Settings;
|
||||
using UltimateXR.Manipulation;
|
||||
using UltimateXR.Extensions.Unity;
|
||||
using UnityEngine;
|
||||
|
||||
namespace UltimateXR.Core.Components.Composite
|
||||
{
|
||||
/// <summary>
|
||||
/// Generic base class for components belonging to an object that also has a <see cref="UxrGrabbableObject" />
|
||||
/// or in any of its parents. It allows to leverage some of the work related to accessing the
|
||||
/// <see cref="UxrGrabbableObject" /> component and processing the events without the need to subscribe or
|
||||
/// unsubscribe to them. Instead, events can be processed by overriding the different event triggers
|
||||
/// (OnXXX methods).
|
||||
/// <para>
|
||||
/// The component has also all the benefits derived from <see cref="UxrComponent" />.
|
||||
/// </para>
|
||||
/// </summary>
|
||||
/// <typeparam name="T">Component type</typeparam>
|
||||
public abstract class UxrGrabbableObjectComponent<T> : UxrComponent<T> where T : UxrGrabbableObjectComponent<T>
|
||||
{
|
||||
#region Public Types & Data
|
||||
|
||||
/// <summary>
|
||||
/// Gets whether the grabbable object is currently being grabbed.
|
||||
/// </summary>
|
||||
public bool IsBeingGrabbed => GrabbableObject && GrabbableObject.IsBeingGrabbed;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the grabbable object component.
|
||||
/// </summary>
|
||||
public UxrGrabbableObject GrabbableObject
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_grabbableObject == null)
|
||||
{
|
||||
_grabbableObject = this.SafeGetComponentInParent<UxrGrabbableObject>();
|
||||
}
|
||||
|
||||
return _grabbableObject;
|
||||
}
|
||||
private set => _grabbableObject = value;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Unity
|
||||
|
||||
/// <summary>
|
||||
/// Caches the grabbable object component.
|
||||
/// </summary>
|
||||
protected override void Awake()
|
||||
{
|
||||
base.Awake();
|
||||
|
||||
GrabbableObject = GetComponentInParent<UxrGrabbableObject>();
|
||||
|
||||
if (GrabbableObject == null && IsGrabbableObjectRequired)
|
||||
{
|
||||
if (UxrGlobalSettings.Instance.LogLevelManipulation >= UxrLogLevel.Errors)
|
||||
{
|
||||
Debug.LogError($"Component {nameof(T)} requires a {nameof(UxrGrabbableObject)} component in the same object or any of its parents.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Subscribes to events.
|
||||
/// </summary>
|
||||
protected override void OnEnable()
|
||||
{
|
||||
base.OnEnable();
|
||||
|
||||
if (GrabbableObject)
|
||||
{
|
||||
GrabbableObject.Grabbing += GrabbableObject_Grabbing;
|
||||
GrabbableObject.Grabbed += GrabbableObject_Grabbed;
|
||||
GrabbableObject.Releasing += GrabbableObject_Releasing;
|
||||
GrabbableObject.Released += GrabbableObject_Released;
|
||||
GrabbableObject.Placing += GrabbableObject_Placing;
|
||||
GrabbableObject.Placed += GrabbableObject_Placed;
|
||||
GrabbableObject.ConstraintsApplying += GrabbableObject_ConstraintsApplying;
|
||||
GrabbableObject.ConstraintsApplied += GrabbableObject_ConstraintsApplied;
|
||||
GrabbableObject.ConstraintsFinished += GrabbableObject_ConstraintsFinished;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Unsubscribes from events.
|
||||
/// </summary>
|
||||
protected override void OnDisable()
|
||||
{
|
||||
base.OnDisable();
|
||||
|
||||
if (GrabbableObject)
|
||||
{
|
||||
GrabbableObject.Grabbing -= GrabbableObject_Grabbing;
|
||||
GrabbableObject.Grabbed -= GrabbableObject_Grabbed;
|
||||
GrabbableObject.Releasing -= GrabbableObject_Releasing;
|
||||
GrabbableObject.Released -= GrabbableObject_Released;
|
||||
GrabbableObject.Placing -= GrabbableObject_Placing;
|
||||
GrabbableObject.Placed -= GrabbableObject_Placed;
|
||||
GrabbableObject.ConstraintsApplying -= GrabbableObject_ConstraintsApplying;
|
||||
GrabbableObject.ConstraintsApplied -= GrabbableObject_ConstraintsApplied;
|
||||
GrabbableObject.ConstraintsFinished -= GrabbableObject_ConstraintsFinished;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Event Handling Methods
|
||||
|
||||
/// <summary>
|
||||
/// Event handling method for the <see cref="UxrGrabbableObject.Grabbing" /> event. It will call the overridable event
|
||||
/// trigger so that child classes don't need to subscribe to the event and can override the method instead.
|
||||
/// </summary>
|
||||
/// <param name="sender">The event sender</param>
|
||||
/// <param name="e">The event parameters</param>
|
||||
private void GrabbableObject_Grabbing(object sender, UxrManipulationEventArgs e)
|
||||
{
|
||||
OnObjectGrabbing(e);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Event handling method for the <see cref="UxrGrabbableObject.Grabbed" /> event. It will call the overridable event
|
||||
/// trigger so that child classes don't need to subscribe to the event and can override the method instead.
|
||||
/// </summary>
|
||||
/// <param name="sender">The event sender</param>
|
||||
/// <param name="e">The event parameters</param>
|
||||
private void GrabbableObject_Grabbed(object sender, UxrManipulationEventArgs e)
|
||||
{
|
||||
OnObjectGrabbed(e);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Event handling method for the <see cref="UxrGrabbableObject.Releasing" /> event. It will call the overridable event
|
||||
/// trigger so that child classes don't need to subscribe to the event and can override the method instead.
|
||||
/// </summary>
|
||||
/// <param name="sender">The event sender</param>
|
||||
/// <param name="e">The event parameters</param>
|
||||
private void GrabbableObject_Releasing(object sender, UxrManipulationEventArgs e)
|
||||
{
|
||||
OnObjectReleasing(e);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Event handling method for the <see cref="UxrGrabbableObject.Released" /> event. It will call the overridable event
|
||||
/// trigger so that child classes don't need to subscribe to the event and can override the method instead.
|
||||
/// </summary>
|
||||
/// <param name="sender">The event sender</param>
|
||||
/// <param name="e">The event parameters</param>
|
||||
private void GrabbableObject_Released(object sender, UxrManipulationEventArgs e)
|
||||
{
|
||||
OnObjectReleased(e);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Event handling method for the <see cref="UxrGrabbableObject.Placing" /> event. It will call the overridable event
|
||||
/// trigger so that child classes don't need to subscribe to the event and can override the method instead.
|
||||
/// </summary>
|
||||
/// <param name="sender">The event sender</param>
|
||||
/// <param name="e">The event parameters</param>
|
||||
private void GrabbableObject_Placing(object sender, UxrManipulationEventArgs e)
|
||||
{
|
||||
OnObjectPlacing(e);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Event handling method for the <see cref="UxrGrabbableObject.Placed" /> event. It will call the overridable event
|
||||
/// trigger so that child classes don't need to subscribe to the event and can override the method instead.
|
||||
/// </summary>
|
||||
/// <param name="sender">The event sender</param>
|
||||
/// <param name="e">The event parameters</param>
|
||||
private void GrabbableObject_Placed(object sender, UxrManipulationEventArgs e)
|
||||
{
|
||||
OnObjectPlaced(e);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Event handling method for the <see cref="UxrGrabbableObject.ConstraintsApplying" /> event. It will call the
|
||||
/// overridable event trigger so that child classes don't need to subscribe to the event and can override the method instead.
|
||||
/// </summary>
|
||||
/// <param name="sender">The event sender</param>
|
||||
/// <param name="e">The event parameters</param>
|
||||
private void GrabbableObject_ConstraintsApplying(object sender, UxrApplyConstraintsEventArgs e)
|
||||
{
|
||||
OnObjectConstraintsApplying(e);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Event handling method for the <see cref="UxrGrabbableObject.ConstraintsApplied" /> event. It will call the
|
||||
/// overridable event trigger so that child classes don't need to subscribe to the event and can override the method instead.
|
||||
/// </summary>
|
||||
/// <param name="sender">The event sender</param>
|
||||
/// <param name="e">The event parameters</param>
|
||||
private void GrabbableObject_ConstraintsApplied(object sender, UxrApplyConstraintsEventArgs e)
|
||||
{
|
||||
OnObjectConstraintsApplied(e);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Event handling method for the <see cref="UxrGrabbableObject.ConstraintsFinished" /> event. It will call the
|
||||
/// overridable event trigger so that child classes don't need to subscribe to the event and can override the method instead.
|
||||
/// </summary>
|
||||
/// <param name="sender">The event sender</param>
|
||||
/// <param name="e">The event parameters</param>
|
||||
private void GrabbableObject_ConstraintsFinished(object sender, UxrApplyConstraintsEventArgs e)
|
||||
{
|
||||
OnObjectConstraintsFinished(e);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Event Trigger Methods
|
||||
|
||||
/// <summary>
|
||||
/// Overridable event trigger method for the <see cref="UxrGrabbableObject.Grabbing" /> event that can be used to
|
||||
/// handle it without requiring to subscribe/unsubscribe.
|
||||
/// </summary>
|
||||
/// <param name="e">Event parameters</param>
|
||||
protected virtual void OnObjectGrabbing(UxrManipulationEventArgs e)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Overridable event trigger method for the <see cref="UxrGrabbableObject.Grabbed" /> event that can be used to
|
||||
/// handle it without requiring to subscribe/unsubscribe.
|
||||
/// </summary>
|
||||
/// <param name="e">Event parameters</param>
|
||||
protected virtual void OnObjectGrabbed(UxrManipulationEventArgs e)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Overridable event trigger method for the <see cref="UxrGrabbableObject.Releasing" /> event that can be used to
|
||||
/// handle it without requiring to subscribe/unsubscribe.
|
||||
/// </summary>
|
||||
/// <param name="e">Event parameters</param>
|
||||
protected virtual void OnObjectReleasing(UxrManipulationEventArgs e)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Overridable event trigger method for the <see cref="UxrGrabbableObject.Released" /> event that can be used to
|
||||
/// handle it without requiring to subscribe/unsubscribe.
|
||||
/// </summary>
|
||||
/// <param name="e">Event parameters</param>
|
||||
protected virtual void OnObjectReleased(UxrManipulationEventArgs e)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Overridable event trigger method for the <see cref="UxrGrabbableObject.Placing" /> event that can be used to
|
||||
/// handle it without requiring to subscribe/unsubscribe.
|
||||
/// </summary>
|
||||
/// <param name="e">Event parameters</param>
|
||||
protected virtual void OnObjectPlacing(UxrManipulationEventArgs e)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Overridable event trigger method for the <see cref="UxrGrabbableObject.Placed" /> event that can be used to
|
||||
/// handle it without requiring to subscribe/unsubscribe.
|
||||
/// </summary>
|
||||
/// <param name="e">Event parameters</param>
|
||||
protected virtual void OnObjectPlaced(UxrManipulationEventArgs e)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Overridable event trigger method for the <see cref="UxrGrabbableObject.ConstraintsApplying" /> event that can be
|
||||
/// used to handle it without requiring to subscribe/unsubscribe.
|
||||
/// </summary>
|
||||
/// <param name="e">Event parameters</param>
|
||||
protected virtual void OnObjectConstraintsApplying(UxrApplyConstraintsEventArgs e)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Overridable event trigger method for the <see cref="UxrGrabbableObject.ConstraintsApplied" /> event that can be
|
||||
/// used to handle it without requiring to subscribe/unsubscribe.
|
||||
/// </summary>
|
||||
/// <param name="e">Event parameters</param>
|
||||
protected virtual void OnObjectConstraintsApplied(UxrApplyConstraintsEventArgs e)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Overridable event trigger method for the <see cref="UxrGrabbableObject.ConstraintsFinished" /> event that can be
|
||||
/// used to handle it without requiring to subscribe/unsubscribe.
|
||||
/// </summary>
|
||||
/// <param name="e">Event parameters</param>
|
||||
protected virtual void OnObjectConstraintsFinished(UxrApplyConstraintsEventArgs e)
|
||||
{
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Protected Types & Data
|
||||
|
||||
/// <summary>
|
||||
/// Gets whether the grabbable object component is required or it's not. By default it is required but it can be
|
||||
/// overriden in child classes so that it is optional.
|
||||
/// </summary>
|
||||
protected virtual bool IsGrabbableObjectRequired => true;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Private Types & Data
|
||||
|
||||
private UxrGrabbableObject _grabbableObject;
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ea24cad3e26c6e740960c91340ca565b
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 8dbb0a618ef647dd974f5201e2e40347
|
||||
timeCreated: 1644249537
|
||||
@@ -0,0 +1,14 @@
|
||||
// --------------------------------------------------------------------------------------------------------------------
|
||||
// <copyright file="IUxrSingleton.cs" company="VRMADA">
|
||||
// Copyright (c) VRMADA, All rights reserved.
|
||||
// </copyright>
|
||||
// --------------------------------------------------------------------------------------------------------------------
|
||||
namespace UltimateXR.Core.Components.Singleton
|
||||
{
|
||||
/// <summary>
|
||||
/// Interface for all classes that are singletons.
|
||||
/// </summary>
|
||||
public interface IUxrSingleton
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 14ce13186a856264bb9788d2a2e4a1dc
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,36 @@
|
||||
// --------------------------------------------------------------------------------------------------------------------
|
||||
// <copyright file="UxrAbstractSingleton.cs" company="VRMADA">
|
||||
// Copyright (c) VRMADA, All rights reserved.
|
||||
// </copyright>
|
||||
// --------------------------------------------------------------------------------------------------------------------
|
||||
namespace UltimateXR.Core.Components.Singleton
|
||||
{
|
||||
/// <summary>
|
||||
/// Singleton base class.
|
||||
/// </summary>
|
||||
public abstract class UxrAbstractSingleton : UxrComponent
|
||||
{
|
||||
#region Protected Overrides UxrComponent
|
||||
|
||||
/// <summary>
|
||||
/// Singletons generate unique ID based on full type name. This ensures that the IDs are the same on all devices and
|
||||
/// message exchanges will work correctly.
|
||||
/// </summary>
|
||||
protected override bool UniqueIdIsTypeName => true;
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override int SerializationOrder => UxrConstants.Serialization.SerializationOrderSingleton;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Protected Types & Data
|
||||
|
||||
/// <summary>
|
||||
/// Whether the singleton requires <see cref="UnityEngine.Object.DontDestroyOnLoad" /> applied to the GameObject so
|
||||
/// that it doesn't get destroyed when a new scene is loaded.
|
||||
/// </summary>
|
||||
protected virtual bool NeedsDontDestroyOnLoad => true;
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e12d9e4e2a7b44819a93a23b5d53ddcc
|
||||
timeCreated: 1644249666
|
||||
@@ -0,0 +1,239 @@
|
||||
// --------------------------------------------------------------------------------------------------------------------
|
||||
// <copyright file="UxrAbstractSingleton.cs" company="VRMADA">
|
||||
// Copyright (c) VRMADA, All rights reserved.
|
||||
// </copyright>
|
||||
// --------------------------------------------------------------------------------------------------------------------
|
||||
using System;
|
||||
using System.Threading;
|
||||
using UltimateXR.Core.Settings;
|
||||
using UltimateXR.Core.Threading;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Assertions;
|
||||
|
||||
namespace UltimateXR.Core.Components.Singleton
|
||||
{
|
||||
/// <summary>
|
||||
/// <para>
|
||||
/// Base class for singletons that can be used with abstract classes.
|
||||
/// </para>
|
||||
/// <para>
|
||||
/// The difference with <see cref="UxrSingleton{T}" /> is that <see cref="UxrSingleton{T}" /> guarantees
|
||||
/// that an instance will always be available in the scene by instantiating the component if it's not found.
|
||||
/// This means <see cref="UxrSingleton{T}.Instance" /> will always be non-null and can be used with or
|
||||
/// without an instance available in the scene. <see cref="UxrSingleton{T}" /> also allows to use automatic
|
||||
/// prefab instantiation if a compatible singleton prefab is present in a special Resources folder.
|
||||
/// Since abstract classes can't be instantiated, <see cref="Instance" /> in <see cref="UxrAbstractSingleton{T}" />
|
||||
/// will be non-null only if a child component is available somewhere in the scene.
|
||||
/// </para>
|
||||
/// <para>
|
||||
/// For design purposes, a singleton may still be desirable when programming an abstract class, hence
|
||||
/// this <see cref="UxrAbstractSingleton{T}" /> component base class.
|
||||
/// </para>
|
||||
/// </summary>
|
||||
/// <typeparam name="T">Class the singleton is for</typeparam>
|
||||
/// <remarks>
|
||||
/// <list type="bullet">
|
||||
/// <item>Make sure to call base.Awake() first in child classes where <see cref="Awake" /> is used.</item>
|
||||
/// <item>Use <see cref="HasInstance" /> to check whether the instance exists.</item>
|
||||
/// </list>
|
||||
/// </remarks>
|
||||
public abstract class UxrAbstractSingleton<T> : UxrAbstractSingleton, IUxrSingleton where T : UxrAbstractSingleton<T>
|
||||
{
|
||||
#region Public Types & Data
|
||||
|
||||
/// <summary>
|
||||
/// Gets the unique, global instance of the given component.
|
||||
/// </summary>
|
||||
public static T Instance
|
||||
{
|
||||
get
|
||||
{
|
||||
if (s_instance is null)
|
||||
{
|
||||
UxrMonoDispatcher.RunOnMainThread(FindInstance);
|
||||
while (s_instance is null && !UxrMonoDispatcher.IsCurrentThreadMain)
|
||||
{
|
||||
Thread.Sleep(25);
|
||||
}
|
||||
}
|
||||
|
||||
return s_instance;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets whether there is a singleton instance available.
|
||||
/// </summary>
|
||||
public static bool HasInstance => s_instance != null;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets whether the singleton has been initialized.
|
||||
/// </summary>
|
||||
public bool IsInitialized { get; private set; }
|
||||
|
||||
#endregion
|
||||
|
||||
#region Unity
|
||||
|
||||
/// <summary>
|
||||
/// Tries to set the singleton instance.
|
||||
/// </summary>
|
||||
protected override void Awake()
|
||||
{
|
||||
base.Awake();
|
||||
|
||||
TrySetInstance(this);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Destroys the singleton instance.
|
||||
/// </summary>
|
||||
protected override void OnDestroy()
|
||||
{
|
||||
base.OnDestroy();
|
||||
|
||||
if (ReferenceEquals(this, s_instance))
|
||||
{
|
||||
Release();
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Protected Methods
|
||||
|
||||
/// <summary>
|
||||
/// Gets the singleton instance.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
protected static T GetInstance()
|
||||
{
|
||||
return s_instance;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tries to set the singleton instance.
|
||||
/// </summary>
|
||||
/// <param name="value">Candidate to set as singleton instance</param>
|
||||
/// <returns>Whether the instance was set</returns>
|
||||
protected static bool TrySetInstance(UxrAbstractSingleton<T> value)
|
||||
{
|
||||
if (value is null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (ReferenceEquals(s_instance, value))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!(s_instance is null))
|
||||
{
|
||||
if (UxrGlobalSettings.Instance.LogLevelCore >= UxrLogLevel.Warnings)
|
||||
{
|
||||
Debug.LogWarning($"{UxrConstants.CoreModule} {typeof(T).Name} singleton already added. Destroying second instance @ {value.gameObject}", value);
|
||||
}
|
||||
|
||||
Destroy(value);
|
||||
return false;
|
||||
}
|
||||
|
||||
Assert.IsTrue(value is T, $"Incoherent types: {value.GetType().Name} vs {typeof(T).Name}");
|
||||
|
||||
if (Application.isPlaying && value.NeedsDontDestroyOnLoad)
|
||||
{
|
||||
DontDestroyOnLoad(value.gameObject);
|
||||
}
|
||||
|
||||
s_instance = (T)value;
|
||||
s_instance.Init();
|
||||
|
||||
if (UxrGlobalSettings.Instance.LogLevelCore >= UxrLogLevel.Relevant)
|
||||
{
|
||||
Debug.Log($"{UxrConstants.CoreModule} {typeof(T).Name} singleton successfully initialized", s_instance);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The default internal initialization. Child classes can override this method if they require initialization code.
|
||||
/// </summary>
|
||||
/// <param name="initializedCallback">Callback called when the initialization finished.</param>
|
||||
protected virtual void InitInternal(Action initializedCallback)
|
||||
{
|
||||
initializedCallback?.Invoke();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The default internal release. Child classes can override this method if they required deallocation code.
|
||||
/// </summary>
|
||||
/// <param name="releasedCallback">Callback called when the releasing finished.</param>
|
||||
protected virtual void ReleaseInternal(Action releasedCallback)
|
||||
{
|
||||
releasedCallback?.Invoke();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Private Methods
|
||||
|
||||
/*
|
||||
/// <summary>
|
||||
/// Called by Unity before a scene is loaded. Calls <see cref="TryFindInstance" />.
|
||||
/// </summary>
|
||||
[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.BeforeSceneLoad)]
|
||||
private static void BeforeSceneLoad()
|
||||
{
|
||||
TryFindInstance();
|
||||
}
|
||||
*/
|
||||
/// <summary>
|
||||
/// Tries to find a pre-existing instance in the scene and set it as the singleton instance.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
private static bool TryFindInstance()
|
||||
{
|
||||
return TrySetInstance(FindObjectOfType<T>());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tries to find a pre-existing instance in the scene.
|
||||
/// </summary>
|
||||
private static void FindInstance()
|
||||
{
|
||||
TryFindInstance();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes the singleton.
|
||||
/// </summary>
|
||||
private void Init()
|
||||
{
|
||||
InitInternal(() => IsInitialized = true);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Releases any resources allocated by the singleton.
|
||||
/// </summary>
|
||||
private void Release()
|
||||
{
|
||||
ReleaseInternal(() =>
|
||||
{
|
||||
if (!IsApplicationQuitting)
|
||||
{
|
||||
s_instance = null;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Private Types & Data
|
||||
|
||||
private static T s_instance;
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 8e9a4c7a7122d8c419e61e67a6e8d4e0
|
||||
timeCreated: 1644249666
|
||||
@@ -0,0 +1,54 @@
|
||||
// --------------------------------------------------------------------------------------------------------------------
|
||||
// <copyright file="UxrAsyncInitAbstractSingleton.cs" company="VRMADA">
|
||||
// Copyright (c) VRMADA, All rights reserved.
|
||||
// </copyright>
|
||||
// --------------------------------------------------------------------------------------------------------------------
|
||||
using System;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using UltimateXR.Core.Threading.TaskControllers;
|
||||
|
||||
namespace UltimateXR.Core.Components.Singleton
|
||||
{
|
||||
/// <summary>
|
||||
/// Same as <see cref="UxrAsyncInitSingleton{T}" /> but allows asynchronous initialization.
|
||||
/// This can be useful where singletons require initialization through config files that are loaded asynchronously from
|
||||
/// disk or through network.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">Type the singleton is for</typeparam>
|
||||
public abstract class UxrAsyncInitAbstractSingleton<T> : UxrAbstractSingleton<T> where T : UxrAsyncInitAbstractSingleton<T>
|
||||
{
|
||||
#region Protected Overrides UxrAbstractSingleton<T>
|
||||
|
||||
/// <summary>
|
||||
/// Initializes the singleton asynchronously. Calls <see cref="InitAsync" /> which is required to be implemented in
|
||||
/// child classes.
|
||||
/// </summary>
|
||||
/// <param name="initializedCallback">Callback required to run when the initialization finished.</param>
|
||||
protected override void InitInternal(Action initializedCallback)
|
||||
{
|
||||
_initController = (UxrTaskController)InitAsync;
|
||||
_initController.Completed += (o, e) => initializedCallback?.Invoke();
|
||||
_initController.Start();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Protected Methods
|
||||
|
||||
/// <summary>
|
||||
/// Initializes the singleton asynchronously.
|
||||
/// </summary>
|
||||
/// <param name="ct">Allows to cancel the asynchronous process if necessary</param>
|
||||
/// <returns>Task representing the initialization</returns>
|
||||
protected abstract Task InitAsync(CancellationToken ct = default);
|
||||
|
||||
#endregion
|
||||
|
||||
#region Private Types & Data
|
||||
|
||||
private UxrTaskController _initController;
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 8353e634dcf55c542b8bfe6dc96a0e59
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,54 @@
|
||||
// --------------------------------------------------------------------------------------------------------------------
|
||||
// <copyright file="UxrAsyncInitSingleton.cs" company="VRMADA">
|
||||
// Copyright (c) VRMADA, All rights reserved.
|
||||
// </copyright>
|
||||
// --------------------------------------------------------------------------------------------------------------------
|
||||
using System;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using UltimateXR.Core.Threading.TaskControllers;
|
||||
|
||||
namespace UltimateXR.Core.Components.Singleton
|
||||
{
|
||||
/// <summary>
|
||||
/// Same as <see cref="UxrSingleton{T}" /> but allows asynchronous initialization.
|
||||
/// This can be useful where singletons require initialization through config files that are loaded asynchronously from
|
||||
/// disk or through network.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">Type the singleton is for</typeparam>
|
||||
public abstract class UxrAsyncInitSingleton<T> : UxrSingleton<T> where T : UxrAsyncInitSingleton<T>
|
||||
{
|
||||
#region Protected Overrides UxrAbstractSingleton<T>
|
||||
|
||||
/// <summary>
|
||||
/// Initializes the singleton asynchronously. Calls <see cref="InitAsync" /> which is required to be implemented in
|
||||
/// child classes.
|
||||
/// </summary>
|
||||
/// <param name="initializedCallback">Callback required to run when the initialization finished.</param>
|
||||
protected override void InitInternal(Action initializedCallback)
|
||||
{
|
||||
_initController = (UxrTaskController)InitAsync;
|
||||
_initController.Completed += (o, e) => initializedCallback?.Invoke();
|
||||
_initController.Start();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Protected Methods
|
||||
|
||||
/// <summary>
|
||||
/// Initializes the singleton asynchronously.
|
||||
/// </summary>
|
||||
/// <param name="ct">Allows to cancel the asynchronous process if necessary</param>
|
||||
/// <returns>Task representing the initialization</returns>
|
||||
protected abstract Task InitAsync(CancellationToken ct = default);
|
||||
|
||||
#endregion
|
||||
|
||||
#region Private Types & Data
|
||||
|
||||
private UxrTaskController _initController;
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 512ee11458e34e01ad20c7f127ee1b78
|
||||
timeCreated: 1611582011
|
||||
@@ -0,0 +1,185 @@
|
||||
// --------------------------------------------------------------------------------------------------------------------
|
||||
// <copyright file="UxrSingleton.cs" company="VRMADA">
|
||||
// Copyright (c) VRMADA, All rights reserved.
|
||||
// </copyright>
|
||||
// --------------------------------------------------------------------------------------------------------------------
|
||||
using System.IO;
|
||||
using System.Threading;
|
||||
using UltimateXR.Core.Settings;
|
||||
using UltimateXR.Core.Threading;
|
||||
using UltimateXR.Extensions.System.IO;
|
||||
using UnityEngine;
|
||||
|
||||
namespace UltimateXR.Core.Components.Singleton
|
||||
{
|
||||
/// <summary>
|
||||
/// <para>
|
||||
/// An improved singleton implementation over <see cref="UxrAbstractSingleton{T}" /> for non-abstract classes.
|
||||
/// <see cref="UxrSingleton{T}" /> guarantees that an <see cref="Instance" /> will always be available by
|
||||
/// instantiating the singleton if it wasn't found in the scene. Additionally, it can instantiate a prefab
|
||||
/// if there is one available in a well-known location.
|
||||
/// </para>
|
||||
/// <para>
|
||||
/// The steps followed by this singleton implementation to assign the instance are the:
|
||||
/// </para>
|
||||
/// <para>
|
||||
/// <list type="number">
|
||||
/// <item>
|
||||
/// The singleton component is searched in the scene to see if it was pre-instantiated or is already
|
||||
/// available.
|
||||
/// </item>
|
||||
/// <item>
|
||||
/// If not found, the component tries to be instantiated in the scene using a prefab in a well known
|
||||
/// Resources folder. The well known path is <see cref="UxrConstants.Paths.SingletonResources" /> in any
|
||||
/// Resources folder and the prefab name is the singleton class name.
|
||||
/// A prefab allows to assign initial properties to the component and also hang additional resources
|
||||
/// (meshes, textures) from the GameObject if needed.
|
||||
/// </item>
|
||||
/// <item>
|
||||
/// If not found, a new <see cref="GameObject" /> is instantiated and the singleton is added using
|
||||
/// <see cref="GameObject.AddComponent{T}" />.
|
||||
/// </item>
|
||||
/// </list>
|
||||
/// </para>
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The singleton can be a pre-existing component in a scene. If not, <see cref="Instance" /> takes care of
|
||||
/// instancing it and make it the singleton.
|
||||
/// This singleton can only be used in sealed classes. For use in abstract classes check
|
||||
/// <see cref="UxrAbstractSingleton{T}" /> instead.
|
||||
/// </remarks>
|
||||
/// <typeparam name="T">
|
||||
/// Type the singleton is for. This template can only be used with a hierarchy where <typeparamref name="T" /> is
|
||||
/// specified at its lowers level (sealed). For use in abstract classes, check <see cref="UxrAbstractSingleton{T}" />.
|
||||
/// </typeparam>
|
||||
public abstract class UxrSingleton<T> : UxrAbstractSingleton<T> where T : UxrSingleton<T>
|
||||
{
|
||||
#region Public Types & Data
|
||||
|
||||
/// <inheritdoc cref="UxrAbstractSingleton{T}.Instance" />
|
||||
public new static T Instance
|
||||
{
|
||||
get
|
||||
{
|
||||
if (GetInstance() is null)
|
||||
{
|
||||
UxrMonoDispatcher.RunOnMainThread(FindOrAddInstance);
|
||||
while (GetInstance() is null && !UxrMonoDispatcher.IsCurrentThreadMain)
|
||||
{
|
||||
Thread.Sleep(25);
|
||||
}
|
||||
}
|
||||
|
||||
return GetInstance();
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Public Methods
|
||||
|
||||
/// <summary>
|
||||
/// Dummy method forcing <see cref="Instance" /> to run the instance finding/creation process.
|
||||
/// </summary>
|
||||
public void Poke()
|
||||
{
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Private Methods
|
||||
|
||||
/// <summary>
|
||||
/// Tries to find a pre-existing instance in the scene and set it as the singleton instance.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
private static bool TryFindInstance()
|
||||
{
|
||||
return TrySetInstance(FindObjectOfType<T>());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// <para>
|
||||
/// Tries to find the singleton instance in the scene. If it was not found, a new singleton is instantiated
|
||||
/// and assigned as the singleton instance. The following steps are used:
|
||||
/// </para>
|
||||
/// <list type="number">
|
||||
/// <item>
|
||||
/// The singleton component is searched in the scene to see if it was pre-instantiated or is already
|
||||
/// available.
|
||||
/// </item>
|
||||
/// <item>
|
||||
/// If not found, the component tries to be instantiated in the scene using a prefab in a well known
|
||||
/// Resources folder. The well known path is <see cref="UxrConstants.Paths.SingletonResources" /> in any
|
||||
/// Resources
|
||||
/// folder and the prefab name is the singleton class name.
|
||||
/// A prefab can be used to assign initial properties to the component and also hang additional resources
|
||||
/// (meshes, textures) from the GameObject.
|
||||
/// </item>
|
||||
/// <item>
|
||||
/// If not found, a new <see cref="GameObject" /> is instantiated and the singleton is added using
|
||||
/// <see cref="GameObject.AddComponent{T}" />.
|
||||
/// </item>
|
||||
/// </list>
|
||||
/// </summary>
|
||||
private static void FindOrAddInstance()
|
||||
{
|
||||
// First: Try to find instance in scene
|
||||
|
||||
if (TryFindInstance())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Second: Try to instantiate it from Resources singleton folder
|
||||
|
||||
T prefab = Resources.Load<T>(ResourcesPrefabPath);
|
||||
T instance = null;
|
||||
|
||||
if (prefab != null)
|
||||
{
|
||||
if (UxrGlobalSettings.Instance.LogLevelCore >= UxrLogLevel.Relevant)
|
||||
{
|
||||
Debug.Log($"{UxrConstants.CoreModule} {typeof(T).Name} was able to load prefab from Resources folder: {ResourcesPrefabPath}");
|
||||
}
|
||||
|
||||
instance = Instantiate(prefab);
|
||||
|
||||
if (instance == null)
|
||||
{
|
||||
if (UxrGlobalSettings.Instance.LogLevelCore >= UxrLogLevel.Errors)
|
||||
{
|
||||
Debug.LogError($"{UxrConstants.CoreModule} {typeof(T).Name}: Unable to instantiate prefab. Instance is null. Path is {ResourcesPrefabPath}", prefab);
|
||||
}
|
||||
}
|
||||
|
||||
instance.name = prefab.name;
|
||||
}
|
||||
|
||||
// Third: Try to instantiate it by creating a GameObject and adding the component
|
||||
|
||||
if (instance == null)
|
||||
{
|
||||
instance = new GameObject(typeof(T).Name).AddComponent<T>();
|
||||
}
|
||||
|
||||
// Try to set it as the current singleton instance
|
||||
|
||||
if (!TrySetInstance(instance))
|
||||
{
|
||||
if (UxrGlobalSettings.Instance.LogLevelCore >= UxrLogLevel.Errors)
|
||||
{
|
||||
Debug.LogError($"{UxrConstants.CoreModule} {typeof(T).Name} singleton failed to initialize", instance);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Private Types & Data
|
||||
|
||||
private static string ResourcesPrefabPath => PathExt.Combine(UxrConstants.Paths.SingletonResources, typeof(T).Name);
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 9a6ca3fc203c1924db6eeaa1fb9cab40
|
||||
timeCreated: 1519373620
|
||||
licenseType: Pro
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
1203
Assets/UltimateXR/Runtime/Scripts/Core/Components/UxrComponent.cs
Normal file
1203
Assets/UltimateXR/Runtime/Scripts/Core/Components/UxrComponent.cs
Normal file
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 9cc18680f6e41d34bb63902248cd4cf9
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,221 @@
|
||||
// --------------------------------------------------------------------------------------------------------------------
|
||||
// <copyright file="UxrComponent_1.cs" company="VRMADA">
|
||||
// Copyright (c) VRMADA, All rights reserved.
|
||||
// </copyright>
|
||||
// --------------------------------------------------------------------------------------------------------------------
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using UltimateXR.Core.Components.Composite;
|
||||
using UnityEngine;
|
||||
|
||||
namespace UltimateXR.Core.Components
|
||||
{
|
||||
/// <summary>
|
||||
/// Like <see cref="UxrComponent"/> but it allows to enumerate all components of a specific type.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">Component type</typeparam>
|
||||
/// <remarks>
|
||||
/// Components get registered through their Awake() call. This means that components get registered
|
||||
/// the first time they are enabled. Disabled objects that have been enabled at some point are enumerated, but objects
|
||||
/// that have never been enabled don't get enumerated, which means that they will not appear in
|
||||
/// <see cref="AllComponents" />.
|
||||
/// </remarks>
|
||||
/// <seealso cref="UxrAvatarComponent{T}" />
|
||||
public abstract class UxrComponent<T> : UxrComponent where T : UxrComponent<T>
|
||||
{
|
||||
#region Public Types & Data
|
||||
|
||||
/// <summary>
|
||||
/// Called before registering a component.
|
||||
/// </summary>
|
||||
public new static event Action<T> GlobalRegistering;
|
||||
|
||||
/// <summary>
|
||||
/// Called when a component was registered.
|
||||
/// </summary>
|
||||
public new static event Action<T> GlobalRegistered;
|
||||
|
||||
/// <summary>
|
||||
/// Called before unregistering a component.
|
||||
/// </summary>
|
||||
public new static event Action<T> GlobalUnregistering;
|
||||
|
||||
/// <summary>
|
||||
/// Called when a component was unregistered.
|
||||
/// </summary>
|
||||
public new static event Action<T> GlobalUnregistered;
|
||||
|
||||
/// <summary>
|
||||
/// Called when a component was enabled.
|
||||
/// </summary>
|
||||
public new static event Action<T> GlobalEnabled;
|
||||
|
||||
/// <summary>
|
||||
/// Called when a component was disabled.
|
||||
/// </summary>
|
||||
public new static event Action<T> GlobalDisabled;
|
||||
|
||||
/// <summary>
|
||||
/// Gets all the components of this specific type, enabled or not, in all open scenes.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Components that have never been enabled are not returned. Components are automatically registered through their
|
||||
/// Awake() call, which is never called if the object has never been enabled. In this case it is recommended to resort
|
||||
/// to <see cref="GameObject.GetComponentsInChildren{T}(bool)" /> or
|
||||
/// <see cref="UnityEngine.Object.FindObjectsOfType{T}(bool)" />.
|
||||
/// </remarks>
|
||||
public new static IEnumerable<T> AllComponents => s_typeComponents;
|
||||
|
||||
/// <summary>
|
||||
/// Gets all components of this specific type that are enabled, in all open scenes.
|
||||
/// </summary>
|
||||
public new static IEnumerable<T> EnabledComponents => s_typeComponents.Where(c => c.isActiveAndEnabled);
|
||||
|
||||
#endregion
|
||||
|
||||
#region Public Methods
|
||||
|
||||
/// <summary>
|
||||
/// Sorts the internal list of components. This is useful if iterating over the components requires a certain order.
|
||||
/// </summary>
|
||||
/// <param name="comparison">Comparison to use for sorting</param>
|
||||
public static void SortComponents(Comparison<T> comparison)
|
||||
{
|
||||
s_typeComponents.Sort(comparison);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Destroys all components.
|
||||
/// </summary>
|
||||
public new static void DestroyAllComponents()
|
||||
{
|
||||
foreach (T component in s_typeComponents)
|
||||
{
|
||||
Destroy(component);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Destroys all gameObjects the components belong to.
|
||||
/// </summary>
|
||||
public new static void DestroyAllGameObjects()
|
||||
{
|
||||
foreach (T component in s_typeComponents)
|
||||
{
|
||||
Destroy(component.gameObject);
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Unity
|
||||
|
||||
/// <summary>
|
||||
/// Registers itself in the static list of components.
|
||||
/// </summary>
|
||||
protected override void Awake()
|
||||
{
|
||||
base.Awake();
|
||||
|
||||
OnRegistering();
|
||||
s_typeComponents.Add((T)this);
|
||||
OnRegistered();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes itself from the static list of components.
|
||||
/// </summary>
|
||||
protected override void OnDestroy()
|
||||
{
|
||||
base.OnDestroy();
|
||||
|
||||
OnUnregistering();
|
||||
s_typeComponents.Remove((T)this);
|
||||
OnUnregistered();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Triggers enabled events.
|
||||
/// </summary>
|
||||
protected override void OnEnable()
|
||||
{
|
||||
base.OnEnable();
|
||||
|
||||
OnEnabled();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Triggers disabled events.
|
||||
/// </summary>
|
||||
protected override void OnDisable()
|
||||
{
|
||||
base.OnDisable();
|
||||
|
||||
OnDisabled();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Event Trigger Methods
|
||||
|
||||
/// <summary>
|
||||
/// <see cref="GlobalRegistering" /> event trigger.
|
||||
/// </summary>
|
||||
private void OnRegistering()
|
||||
{
|
||||
GlobalRegistering?.Invoke(this as T);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// <see cref="GlobalRegistered" /> event trigger.
|
||||
/// </summary>
|
||||
private void OnRegistered()
|
||||
{
|
||||
GlobalRegistered?.Invoke(this as T);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// <see cref="GlobalUnregistering" /> event trigger.
|
||||
/// </summary>
|
||||
private void OnUnregistering()
|
||||
{
|
||||
GlobalUnregistering?.Invoke(this as T);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// <see cref="GlobalUnregistered" /> event trigger.
|
||||
/// </summary>
|
||||
private void OnUnregistered()
|
||||
{
|
||||
GlobalUnregistered?.Invoke(this as T);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// <see cref="GlobalEnabled" /> event trigger.
|
||||
/// </summary>
|
||||
private void OnEnabled()
|
||||
{
|
||||
GlobalEnabled?.Invoke(this as T);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// <see cref="GlobalDisabled" /> event trigger.
|
||||
/// </summary>
|
||||
private void OnDisabled()
|
||||
{
|
||||
GlobalDisabled?.Invoke(this as T);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Private Types & Data
|
||||
|
||||
/// <summary>
|
||||
/// Static list containing all registered components of this type.
|
||||
/// </summary>
|
||||
private static readonly List<T> s_typeComponents = new List<T>();
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 0c05b7b33de81624c87ffc921508809e
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,82 @@
|
||||
// --------------------------------------------------------------------------------------------------------------------
|
||||
// <copyright file="UxrComponent_2.cs" company="VRMADA">
|
||||
// Copyright (c) VRMADA, All rights reserved.
|
||||
// </copyright>
|
||||
// --------------------------------------------------------------------------------------------------------------------
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using UltimateXR.Avatar;
|
||||
using UltimateXR.Core.Components.Composite;
|
||||
using UltimateXR.Extensions.Unity;
|
||||
using UnityEngine;
|
||||
|
||||
namespace UltimateXR.Core.Components
|
||||
{
|
||||
/// <summary>
|
||||
/// <para>
|
||||
/// Like <see cref="UxrComponent{T}" /> but the component belongs to a hierarchy
|
||||
/// with a parent that has a component of a certain type <typeparamref name="TP" />.
|
||||
/// This allows to enumerate and keep track of only the components that hang from the hierarchy
|
||||
/// under each parent component separately.
|
||||
/// </para>
|
||||
/// <para>
|
||||
/// In the case of keeping track of all components of a same type that are in or hang from an avatar (
|
||||
/// <see cref="UxrAvatar" />) there is a special component for that in <see cref="UxrAvatarComponent{T}" />.
|
||||
/// </para>
|
||||
/// </summary>
|
||||
/// <typeparam name="TP">Parent component type</typeparam>
|
||||
/// <typeparam name="TC">Component type</typeparam>
|
||||
public abstract class UxrComponent<TP, TC> : UxrComponent<TC>
|
||||
where TP : Component
|
||||
where TC : UxrComponent<TC>
|
||||
{
|
||||
#region Public Types & Data
|
||||
|
||||
/// <summary>
|
||||
/// Gets all the components, enabled of not, of this specific type that hang from the same parent.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Components that have never been enabled are not returned. Components are automatically registered through their
|
||||
/// Awake() call, which is never called if the object has never been enabled. In this case it is recommended to resort
|
||||
/// to <see cref="GameObject.GetComponentsInChildren{T}(bool)" />.
|
||||
/// </remarks>
|
||||
public IEnumerable<TC> AllChildrenFromParent => GetParentChildren(Parent, true);
|
||||
|
||||
/// <summary>
|
||||
/// Gets only the enabled components of this specific type that hang from the same parent.
|
||||
/// </summary>
|
||||
public IEnumerable<TC> EnabledChildrenFromParent => GetParentChildren(Parent);
|
||||
|
||||
/// <summary>
|
||||
/// Parent the component belongs to.
|
||||
/// </summary>
|
||||
public TP Parent => gameObject.SafeGetComponentInParent<TP>();
|
||||
|
||||
#endregion
|
||||
|
||||
#region Public Methods
|
||||
|
||||
/// <summary>
|
||||
/// Gets the children from a specific parent.
|
||||
/// </summary>
|
||||
/// <param name="parent">Parent to get the components from</param>
|
||||
/// <param name="includeDisabled">Whether to include disabled components or not</param>
|
||||
/// <returns>Components meeting the criteria</returns>
|
||||
/// <remarks>
|
||||
/// When using the <paramref name="includeDisabled" /> parameter, components that have never been enabled are not
|
||||
/// returned. Components are automatically registered through their Awake() call, which is never called if the object
|
||||
/// has never been enabled. In this case it is recommended to resort to
|
||||
/// <see cref="GameObject.GetComponentsInChildren{T}(bool)" />.
|
||||
/// </remarks>
|
||||
public static IEnumerable<TC> GetParentChildren(TP parent, bool includeDisabled = false)
|
||||
{
|
||||
if (includeDisabled)
|
||||
{
|
||||
return AllComponents.Where(c => c is UxrComponent<TP, TC> child && child.Parent == parent);
|
||||
}
|
||||
return AllComponents.Where(c => c is UxrComponent<TP, TC> child && child.Parent == parent && c.isActiveAndEnabled);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 6cd7afe7a9ff9314c8ef1e7db3c16085
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,20 @@
|
||||
// --------------------------------------------------------------------------------------------------------------------
|
||||
// <copyright file="UxrSyncObject.StateSave.cs" company="VRMADA">
|
||||
// Copyright (c) VRMADA, All rights reserved.
|
||||
// </copyright>
|
||||
// --------------------------------------------------------------------------------------------------------------------
|
||||
namespace UltimateXR.Core.Components
|
||||
{
|
||||
public partial class UxrSyncObject
|
||||
{
|
||||
#region Protected Overrides UxrComponent
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override bool SaveStateWhenDisabled => _syncWhileDisabled;
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override bool SerializeActiveAndEnabledState => _syncActiveAndEnabled;
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 115582f99ade41d98a39ff08c14120ff
|
||||
timeCreated: 1715540449
|
||||
@@ -0,0 +1,56 @@
|
||||
// --------------------------------------------------------------------------------------------------------------------
|
||||
// <copyright file="UxrSyncObject.cs" company="VRMADA">
|
||||
// Copyright (c) VRMADA, All rights reserved.
|
||||
// </copyright>
|
||||
// --------------------------------------------------------------------------------------------------------------------
|
||||
using UltimateXR.Core.StateSave;
|
||||
using UltimateXR.Core.Unique;
|
||||
using UnityEngine;
|
||||
|
||||
namespace UltimateXR.Core.Components
|
||||
{
|
||||
/// <summary>
|
||||
/// Minimal <see cref="UxrComponent" /> component that can be used to identify GameObjects that don't have any other
|
||||
/// <see cref="UxrComponent" />. Additionally, it can control which Transform to sync, if any.
|
||||
/// This can be useful in multiplayer environments to reference objects. For example, an avatar might be parented to a
|
||||
/// moving platform and this operation needs to be executed in other client PCs.
|
||||
/// If there is no reference to this platform (it might be the result of performing a raycast and not because a script
|
||||
/// has a reference to it, for instance), there needs to be a way to get the same GameObject in the other PCS.
|
||||
/// Since <see cref="UxrComponent" /> has a way to identify and obtain components (<see cref="UxrComponent.UniqueId" />
|
||||
/// and <see cref="UxrUniqueIdImplementer.TryGetComponentById" />), a simple way to send references through the network
|
||||
/// is by using a <see cref="UxrSyncObject" /> component on the GameObject.
|
||||
/// </summary>
|
||||
public partial class UxrSyncObject : UxrComponent
|
||||
{
|
||||
#region Inspector Properties/Serialized Fields
|
||||
|
||||
[SerializeField] private bool _syncTransform;
|
||||
[SerializeField] private UxrTransformSpace _transformSpace = UxrTransformSpace.World;
|
||||
[SerializeField] private bool _syncActiveAndEnabled;
|
||||
[SerializeField] private bool _syncWhileDisabled;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Public Types & Data
|
||||
|
||||
/// <summary>
|
||||
/// Gets whether the transform should be synchronized.
|
||||
/// </summary>
|
||||
public bool SyncTransform => _syncTransform;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Protected Overrides UxrComponent
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override UxrTransformSpace TransformStateSaveSpace => _transformSpace;
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override bool RequiresTransformSerialization(UxrStateSaveLevel level)
|
||||
{
|
||||
return SyncTransform;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 1d87e695c3ef3c74b80a160f7594fd30
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Reference in New Issue
Block a user