namespace VRTK.Prefabs.Interactions.Interactables.Grab { using UnityEngine; using UnityEngine.Events; using System; using System.Linq; using System.Collections.Generic; using Malimbe.XmlDocumentationAttribute; using Malimbe.PropertySerializationAttribute; using Malimbe.BehaviourStateRequirementMethod; using VRTK.Prefabs.Interactions.Interactors; /// /// Registers listeners to the initial grab and final ungrab states of an and emits the as the event payload. /// public class InteractableGrabStateRegistrar : MonoBehaviour { /// /// Defines the event with the specified . /// [Serializable] public class UnityEvent : UnityEvent { } /// /// Determines whether to unsubscribe all registered listeners when the component is disabled. /// [Serialized] [field: DocumentedByXml] public bool UnsubscribeOnDisable { get; set; } = true; /// /// Emitted when the is grabbed. /// public UnityEvent Grabbed = new UnityEvent(); /// /// Emitted when the is ungrabbed. /// public UnityEvent Ungrabbed = new UnityEvent(); /// /// s that unsubscribe the added grab event listeners. /// protected readonly Dictionary unsubscribeGrabActions = new Dictionary(); /// /// s that unsubscribe the added ungrab event listeners. /// protected readonly Dictionary unsubscribeUngrabActions = new Dictionary(); /// /// Registers a listener on the given Ungrabbed event. /// /// The interactable to register the ungrab event on. [RequiresBehaviourState] public virtual void RegisterUngrabbed(InteractableFacade ungrabbable) { if (ungrabbable == null || unsubscribeUngrabActions.ContainsKey(ungrabbable)) { return; } void OnUngrabbed(InteractorFacade _) => InteractableUngrabbed(ungrabbable); ungrabbable.LastUngrabbed.AddListener(OnUngrabbed); unsubscribeUngrabActions[ungrabbable] = () => ungrabbable.LastUngrabbed.RemoveListener(OnUngrabbed); } /// /// Registers a listener on the given 's Ungrabbed event. /// /// The to get the from to register the ungrab event on. [RequiresBehaviourState] public virtual void RegisterUngrabbed(GameObject ungrabbable) { if (ungrabbable == null) { return; } RegisterUngrabbed(ungrabbable.GetComponent()); } /// /// Registers a listener on the given Grabbed event. /// /// The interactable to register the grab event on. [RequiresBehaviourState] public virtual void RegisterGrabbed(InteractableFacade grabbable) { if (grabbable == null || unsubscribeGrabActions.ContainsKey(grabbable)) { return; } void OnGrabbed(InteractorFacade _) => InteractableGrabbed(grabbable); grabbable.FirstGrabbed.AddListener(OnGrabbed); unsubscribeGrabActions[grabbable] = () => grabbable.FirstGrabbed.RemoveListener(OnGrabbed); } /// /// Registers a listener on the given 's Grabbed event. /// /// The to get the from to register the grab event on. [RequiresBehaviourState] public virtual void RegisterGrabbed(GameObject grabbable) { if (grabbable == null) { return; } RegisterGrabbed(grabbable.GetComponent()); } /// /// Unregisters a listener from the given Ungrabbed event. /// /// The interactable to unregister the ungrab event from. public virtual void UnregisterUngrabbed(InteractableFacade ungrabbable) { if (ungrabbable == null || !unsubscribeUngrabActions.TryGetValue(ungrabbable, out System.Action unsubscribeAction)) { return; } unsubscribeAction(); unsubscribeUngrabActions.Remove(ungrabbable); } /// /// Unregisters a listener from the given 's Ungrabbed event. /// /// The to get the from to unregister the ungrab event from. public virtual void UnregisterUngrabbed(GameObject ungrabbable) { if (ungrabbable == null) { return; } UnregisterUngrabbed(ungrabbable.GetComponent()); } /// /// Unregisters a listener from the given Grabbed event. /// /// The interactable to unregister the grab event from. public virtual void UnregisterGrabbed(InteractableFacade grabbable) { if (grabbable == null || !unsubscribeGrabActions.TryGetValue(grabbable, out System.Action unsubscribeAction)) { return; } unsubscribeAction(); unsubscribeGrabActions.Remove(grabbable); } /// /// Unregisters a listener from the given 's Grabbed event. /// /// The to get the from to unregister the grab event from. public virtual void UnregisterGrabbed(GameObject grabbable) { if (grabbable == null) { return; } UnregisterGrabbed(grabbable.GetComponent()); } /// /// Unregisters all listeners for all ungrabbed events. /// public virtual void UnregisterAllUngrabbed() { foreach (InteractableFacade entry in unsubscribeUngrabActions.Keys.ToArray()) { UnregisterUngrabbed(entry); } unsubscribeUngrabActions.Clear(); } /// /// Unregisters all listeners for all grabbed events. /// public virtual void UnregisterAllGrabbed() { foreach (InteractableFacade entry in unsubscribeGrabActions.Keys.ToArray()) { UnregisterGrabbed(entry); } unsubscribeGrabActions.Clear(); } /// /// Unregisters all listeners for all events. /// public virtual void UnregisterAll() { UnregisterAllUngrabbed(); UnregisterAllGrabbed(); } protected virtual void OnDisable() { if (UnsubscribeOnDisable) { UnregisterAll(); } } /// /// Processes the grabbed event on the given Interactable. /// /// The Interactable to process the grab event for. protected virtual void InteractableGrabbed(InteractableFacade interactable) { Grabbed?.Invoke(interactable); } /// /// Processes the ungrabbed event on the given Interactable. /// /// The Interactable to process the ungrab event for. protected virtual void InteractableUngrabbed(InteractableFacade interactable) { Ungrabbed?.Invoke(interactable); } } }