using System.Collections.Generic;
using System.Linq;
using UnityEngine;
namespace VIVE.OpenXR.Toolkits.RealisticHandInteraction
{
///
/// This class is designed to manage all Grabbers and Grabbables.
///
public static class GrabManager
{
private static List m_GrabberRegistry = new List();
public static IReadOnlyList handGrabbers => m_GrabberRegistry.OfType().ToList().AsReadOnly();
private static List m_GrabbableRegistry = new List();
public static IReadOnlyList handGrabbables => m_GrabbableRegistry.OfType().ToList().AsReadOnly();
#region IGrabber
///
/// Register the grabber in the grabber registry.
///
/// The grabber to register.
/// True if the grabber is successfully registered; otherwise, false.
public static bool RegisterGrabber(IGrabber grabber)
{
if (!m_GrabberRegistry.Contains(grabber))
{
m_GrabberRegistry.Add(grabber);
}
return m_GrabberRegistry.Contains(grabber);
}
///
/// Remove the grabber from the grabber registry.
///
/// The grabber to remove.
/// True if the grabber is successfully removed; otherwise, false.
public static bool UnregisterGrabber(IGrabber grabber)
{
if (m_GrabberRegistry.Contains(grabber))
{
m_GrabberRegistry.Remove(grabber);
}
return !m_GrabberRegistry.Contains(grabber);
}
///
/// Get the first hand grabber component found in the child hierarchy of the GameObject.
///
/// The target whose child hierarchy to search.
/// The output parameter to store the first hand grabber component found.
/// True if a hand grabber component is found; otherwise, false.
public static bool GetFirstHandGrabberFromChild(GameObject target, out HandGrabInteractor grabber)
{
grabber = TopDownFind(target.transform);
return grabber != null;
}
///
/// Get the first hand grabber component found in the parent hierarchy of the GameObject.
///
/// The target whose parent hierarchy to search.
/// The output parameter to store the first hand grabber component found.
/// True if a hand grabber component is found; otherwise, false.
public static bool GetFirstHandGrabberFromParent(GameObject target, out HandGrabInteractor grabber)
{
grabber = BottomUpFind(target.transform);
return grabber != null;
}
#endregion
#region GrabInteractable
///
/// Register the grabbable in the grabbable registry.
///
/// The grabbable to register.
/// True if the grabbable is successfully registered; otherwise, false.
public static bool RegisterGrabbable(IGrabbable grabbable)
{
if (!m_GrabbableRegistry.Contains(grabbable))
{
m_GrabbableRegistry.Add(grabbable);
}
return m_GrabbableRegistry.Contains(grabbable);
}
///
/// Remove the grabbable from the grabbable registry.
///
/// The grabbable to remove.
/// True if the grabbable is successfully removed; otherwise, false.
public static bool UnregisterGrabbable(IGrabbable grabbable)
{
if (m_GrabbableRegistry.Contains(grabbable))
{
m_GrabbableRegistry.Remove(grabbable);
}
return !m_GrabbableRegistry.Contains(grabbable);
}
///
/// Get the first hand grabbable component found in the child hierarchy of the GameObject.
///
/// The target whose child hierarchy to search.
/// The output parameter to store the first hand grabbable component found.
/// True if a hand grabbable component is found; otherwise, false.
public static bool GetFirstHandGrabbableFromChild(GameObject target, out HandGrabInteractable grabbable)
{
grabbable = TopDownFind(target.transform);
return grabbable != null;
}
///
/// Get the first hand grabbable component found in the parent hierarchy of the GameObject.
///
/// The target whose parent hierarchy to search.
/// The output parameter to store the first hand grabbable component found.
/// True if a hand grabbable component is found; otherwise, false.
public static bool GetFirstHandGrabbableFromParent(GameObject target, out HandGrabInteractable grabbable)
{
grabbable = BottomUpFind(target.transform);
return grabbable != null;
}
#endregion
///
/// Find available components from self to children nodes.
///
/// The transform of the gameobject.
/// Value for available component.
private static T TopDownFind(Transform transform) where T : Component
{
T component = transform.GetComponent();
if (component != null)
{
return component;
}
if (transform.childCount > 0)
{
for (int i = 0; i < transform.childCount; i++)
{
T childComponent = TopDownFind(transform.GetChild(i));
if (childComponent != null)
{
return childComponent;
}
}
}
return null;
}
///
/// Find available components from self to parent node.
///
/// The transform of the gameobject.
/// Value for available component.
private static T BottomUpFind(Transform transform) where T : Component
{
T component = transform.GetComponent();
if (component != null)
{
return component;
}
if (transform.parent != null)
{
return BottomUpFind(transform.parent);
}
return null;
}
}
}