// --------------------------------------------------------------------------------------------------------------------
//
// Copyright (c) VRMADA, All rights reserved.
//
// --------------------------------------------------------------------------------------------------------------------
using System;
using UltimateXR.Core.Serialization;
using UnityEngine;
namespace UltimateXR.Manipulation
{
///
///
/// Event parameters for most manipulation events:
///
/// :
///
/// -
///
///
/// -
///
///
/// -
///
///
/// -
///
///
/// -
///
///
/// -
///
///
/// -
///
///
/// -
///
///
/// -
///
///
/// -
///
///
/// -
///
///
/// -
///
///
/// -
///
///
///
/// :
///
/// -
///
///
/// -
///
///
/// -
///
///
/// -
///
///
/// -
///
///
/// -
///
///
///
/// :
///
/// -
///
///
/// -
///
///
/// -
///
///
/// -
///
///
/// -
///
///
///
///
public class UxrManipulationEventArgs : EventArgs, IUxrSerializable
{
#region Public Types & Data
///
/// Gets whether the manipulation changed an object from not being grabbed at all to being grabbed or vice-versa.
/// This is useful to filter out grabs or releases on an object that is still being grabbed using another hand.
/// is true if and are
/// both false.
///
public bool IsGrabbedStateChanged => !IsMultiHands && !IsSwitchHands;
///
/// The type of event.
///
public UxrManipulationEventType EventType
{
get => _eventType;
private set => _eventType = value;
}
///
/// Gets the grabbable object related to the event. Can be null if the event doesn't use this property. Check the event
/// documentation to see how the property is used.
///
public UxrGrabbableObject GrabbableObject
{
get => _grabbableObject;
private set => _grabbableObject = value;
}
///
/// Gets the grabbable object anchor related to the event. Can be null if the event doesn't use this property. Check
/// the event documentation to see how the property is used.
///
public UxrGrabbableObjectAnchor GrabbableAnchor
{
get => _grabbableAnchor;
private set => _grabbableAnchor = value;
}
///
/// Gets the grabber related to the event. Can be null if the event doesn't use this property. Check the event
/// documentation to see how the property is used.
///
public UxrGrabber Grabber
{
get => _grabber;
private set => _grabber = value;
}
///
/// Gets the grabbable object's grab point index related to the event. Can be meaningless if the event doesn't use this
/// property. Check the event documentation to see how the property is used.
///
public int GrabPointIndex
{
get => _grabPointIndex;
private set => _grabPointIndex = value;
}
///
/// Gets whether the manipulation used more than one hand. Can be meaningless if the event doesn't use this property.
/// Check the event documentation to see how the property is used.
///
public bool IsMultiHands
{
get => _isMultiHands;
private set => _isMultiHands = value;
}
///
/// Gets whether the event was the result of passing the object from one hand to the other. Can be meaningless if the
/// event doesn't use this property. Check the event documentation to see how the property is used.
///
public bool IsSwitchHands
{
get => _isSwitchHands;
private set => _isSwitchHands = value;
}
///
/// Gets the release velocity for release events.
///
public Vector3 ReleaseVelocity
{
get => _releaseVelocity;
private set => _releaseVelocity = value;
}
///
/// Gets the release angular velocity for release events.
///
public Vector3 ReleaseAngularVelocity
{
get => _releaseAngularVelocity;
private set => _releaseAngularVelocity = value;
}
///
/// Gets the placement flags in place events.
///
public UxrPlacementOptions PlacementOptions
{
get => _placementOptions;
private set => _placementOptions = value;
}
#endregion
#region Internal Types & Data
///
/// Gets the UxrGrabbableObject position in local UxrGrabber space at the moment of grabbing.
/// This is used in multi-player environments to make sure to reproduce the same grab action.
///
internal Vector3 GrabberLocalObjectPosition
{
get => _grabberLocalObjectPosition;
private set => _grabberLocalObjectPosition = value;
}
///
/// Gets the UxrGrabbableObject rotation in local UxrGrabber space at the moment of grabbing.
/// This is used in multi-player environments to make sure to reproduce the same grab action.
///
internal Quaternion GrabberLocalObjectRotation
{
get => _grabberLocalObjectRotation;
private set => _grabberLocalObjectRotation = value;
}
///
/// Gets the grab snap position in local UxrGrabber space at the moment of grabbing.
/// This is used in multi-player environments to make sure to reproduce the same grab action.
///
internal Vector3 GrabberLocalSnapPosition
{
get => _grabberLocalSnapPosition;
private set => _grabberLocalSnapPosition = value;
}
///
/// Gets the grab snap rotation in local UxrGrabber space at the moment of grabbing.
/// This is used in multi-player environments to make sure to reproduce the same grab action.
///
internal Quaternion GrabberLocalSnapRotation
{
get => _grabberLocalSnapRotation;
private set => _grabberLocalSnapRotation = value;
}
///
/// Gets the release start position for release events.
///
internal Vector3 ReleaseStartPosition
{
get => _releaseStartPosition;
private set => _releaseStartPosition = value;
}
///
/// Gets the release start rotation for release events.
///
internal Quaternion ReleaseStartRotation
{
get => _releaseStartRotation;
private set => _releaseStartRotation = value;
}
#endregion
#region Constructors & Finalizer
///
/// Default constructor is private.
///
private UxrManipulationEventArgs()
{
}
///
/// Constructor that initializes the event type.
///
private UxrManipulationEventArgs(UxrManipulationEventType eventType)
{
EventType = eventType;
}
#endregion
#region Explicit IUxrSerializable
///
int IUxrSerializable.SerializationVersion => 0;
///
void IUxrSerializable.Serialize(IUxrSerializer serializer, int serializationVersion)
{
serializer.SerializeEnum(ref _eventType);
serializer.SerializeUniqueComponent(ref _grabbableObject);
serializer.SerializeUniqueComponent(ref _grabbableAnchor);
serializer.SerializeUniqueComponent(ref _grabber);
serializer.Serialize(ref _grabPointIndex);
serializer.Serialize(ref _isMultiHands);
serializer.Serialize(ref _isSwitchHands);
if (EventType == UxrManipulationEventType.Grab)
{
serializer.Serialize(ref _grabberLocalSnapPosition);
serializer.Serialize(ref _grabberLocalSnapRotation);
serializer.Serialize(ref _grabberLocalObjectPosition);
serializer.Serialize(ref _grabberLocalObjectRotation);
}
else if (EventType == UxrManipulationEventType.Release)
{
serializer.Serialize(ref _releaseStartPosition);
serializer.Serialize(ref _releaseStartRotation);
serializer.Serialize(ref _releaseVelocity);
serializer.Serialize(ref _releaseAngularVelocity);
}
else if (EventType == UxrManipulationEventType.Place)
{
serializer.SerializeEnum(ref _placementOptions);
}
}
#endregion
#region Public Methods
///
/// Constructor for Grab events.
///
/// Grabbable object
/// Grabbable object anchor
/// Grabber
/// Grab point index
/// Whether the object was already grabbed with one or more hands
/// Whether the event was a result of passing the grabbable object from one hand to the other
/// Grab snap position in local UxrGrabber space at the moment of grabbing
/// Grab snap rotation in local UxrGrabber space at the moment of grabbing
public static UxrManipulationEventArgs FromGrab(UxrGrabbableObject grabbableObject,
UxrGrabbableObjectAnchor grabbableAnchor,
UxrGrabber grabber,
int grabPointIndex,
bool isMultiHands,
bool isSwitchHands,
Vector3 grabberLocalSnapPosition,
Quaternion grabberLocalSnapRotation)
{
UxrManipulationEventArgs eventArgs = new UxrManipulationEventArgs(UxrManipulationEventType.Grab);
eventArgs.GrabbableObject = grabbableObject;
eventArgs.GrabbableAnchor = grabbableAnchor;
eventArgs.Grabber = grabber;
eventArgs.GrabPointIndex = grabPointIndex;
eventArgs.IsMultiHands = isMultiHands;
eventArgs.IsSwitchHands = isSwitchHands;
// Internal vars
if (grabbableObject != null && grabber != null)
{
eventArgs.GrabberLocalSnapPosition = grabberLocalSnapPosition;
eventArgs.GrabberLocalSnapRotation = grabberLocalSnapRotation;
eventArgs.GrabberLocalObjectPosition = grabber.transform.InverseTransformPoint(grabbableObject.transform.position);
eventArgs.GrabberLocalObjectRotation = Quaternion.Inverse(grabber.transform.rotation) * grabbableObject.transform.rotation;
}
return eventArgs;
}
///
/// Constructor for Release events.
///
/// Grabbable object
/// Grabbable object anchor
/// Grabber
/// Grab point index
/// Whether the object will still be grabbed with one or more hands
/// Whether the event was a result of passing the grabbable object from one hand to the other
/// The release velocity
/// The release angular velocity
public static UxrManipulationEventArgs FromRelease(UxrGrabbableObject grabbableObject,
UxrGrabbableObjectAnchor grabbableAnchor,
UxrGrabber grabber,
int grabPointIndex,
bool isMultiHands,
bool isSwitchHands,
Vector3 releaseVelocity = default(Vector3),
Vector3 releaseAngularVelocity = default(Vector3))
{
UxrManipulationEventArgs eventArgs = new UxrManipulationEventArgs(UxrManipulationEventType.Release);
eventArgs.GrabbableObject = grabbableObject;
eventArgs.GrabbableAnchor = grabbableAnchor;
eventArgs.Grabber = grabber;
eventArgs.GrabPointIndex = grabPointIndex;
eventArgs.IsMultiHands = isMultiHands;
eventArgs.IsSwitchHands = isSwitchHands;
eventArgs.ReleaseVelocity = releaseVelocity;
eventArgs.ReleaseAngularVelocity = releaseAngularVelocity;
// Internal vars
if (grabbableObject != null)
{
eventArgs.ReleaseStartPosition = grabbableObject.transform.position;
eventArgs.ReleaseStartRotation = grabbableObject.transform.rotation;
}
return eventArgs;
}
///
/// Constructor for Place events.
///
/// Grabbable object
/// Grabbable object anchor
/// Grabber
/// Grab point index
/// The placement options flags
public static UxrManipulationEventArgs FromPlace(UxrGrabbableObject grabbableObject,
UxrGrabbableObjectAnchor grabbableAnchor,
UxrGrabber grabber,
int grabPointIndex,
UxrPlacementOptions placementOptions)
{
UxrManipulationEventArgs eventArgs = new UxrManipulationEventArgs(UxrManipulationEventType.Place);
eventArgs.GrabbableObject = grabbableObject;
eventArgs.GrabbableAnchor = grabbableAnchor;
eventArgs.Grabber = grabber;
eventArgs.GrabPointIndex = grabPointIndex;
eventArgs.IsMultiHands = false;
eventArgs.IsSwitchHands = false;
eventArgs.PlacementOptions = placementOptions;
return eventArgs;
}
///
/// Constructor for Release events.
///
/// Grabbable object
/// Grabbable object anchor
/// Grabber
/// Grab point index
/// Whether the event was a result of a manipulation with more than one hand
/// Whether the event was a result of passing the grabbable object from one hand to the other
public static UxrManipulationEventArgs FromRemove(UxrGrabbableObject grabbableObject,
UxrGrabbableObjectAnchor grabbableAnchor,
UxrGrabber grabber,
int grabPointIndex = 0,
bool isMultiHands = false,
bool isSwitchHands = false)
{
UxrManipulationEventArgs eventArgs = new UxrManipulationEventArgs(UxrManipulationEventType.Remove);
eventArgs.GrabbableObject = grabbableObject;
eventArgs.GrabbableAnchor = grabbableAnchor;
eventArgs.Grabber = grabber;
eventArgs.GrabPointIndex = grabPointIndex;
eventArgs.IsMultiHands = isMultiHands;
eventArgs.IsSwitchHands = isSwitchHands;
return eventArgs;
}
///
/// Constructor for PlacedObjectRangeEntered/Left, AnchorRangeEntered/Left and GrabTrying events.
///
/// Grabbable object
/// Grabbable object anchor
/// Grabber
/// Grab point index
/// Whether the event was a result of a manipulation with more than one hand
/// Whether the event was a result of passing the grabbable object from one hand to the other
public static UxrManipulationEventArgs FromOther(UxrManipulationEventType eventType,
UxrGrabbableObject grabbableObject,
UxrGrabbableObjectAnchor grabbableAnchor,
UxrGrabber grabber,
int grabPointIndex = 0,
bool isMultiHands = false,
bool isSwitchHands = false)
{
UxrManipulationEventArgs eventArgs = new UxrManipulationEventArgs(eventType);
eventArgs.GrabbableObject = grabbableObject;
eventArgs.GrabbableAnchor = grabbableAnchor;
eventArgs.Grabber = grabber;
eventArgs.GrabPointIndex = grabPointIndex;
eventArgs.IsMultiHands = isMultiHands;
eventArgs.IsSwitchHands = isSwitchHands;
return eventArgs;
}
///
/// Gets a string that describes the event.
///
/// Whether to include information of the component unique IDs
/// String with a description of the event
public string ToString(bool includeIds = false)
{
switch (EventType)
{
case UxrManipulationEventType.Grab: return $"Grabbing {GetGrabbableObjectLogInfo(this, includeIds)}{GetGrabberLogInfo(this, includeIds)}";
case UxrManipulationEventType.Release: return $"Releasing {GetGrabbableObjectLogInfo(this, includeIds)}{GetGrabberLogInfo(this, includeIds)}";
case UxrManipulationEventType.Place: return $"Placing {GetGrabbableObjectLogInfo(this, includeIds)} on {GetAnchorLogInfo(this, includeIds)}{GetGrabberLogInfo(this, includeIds)}";
case UxrManipulationEventType.Remove: return $"Removing {GetGrabbableObjectLogInfo(this, includeIds)} from {GetAnchorLogInfo(this, includeIds)}{GetGrabberLogInfo(this, includeIds)}";
}
return "Unknown event";
}
#endregion
#region Private Methods
///
/// Gets the log string describing the grabber.
///
/// Event with the grabber to log
/// Whether to include information of the component unique IDs
/// Log string
private static string GetGrabberLogInfo(UxrManipulationEventArgs e, bool includeIds)
{
string id = e.Grabber != null && includeIds ? $" (id {e.Grabber.UniqueId})" : string.Empty;
return e.Grabber != null ? $" using {e.Grabber}{id}" : string.Empty;
}
///
/// Gets the log string describing the grabber.
///
/// Event with the grabber to log
/// Whether to include information of the component unique IDs
/// Log string
private static string GetAnchorLogInfo(UxrManipulationEventArgs e, bool includeIds)
{
string id = e.GrabbableAnchor != null && includeIds ? $" (id {e.GrabbableAnchor.UniqueId})" : string.Empty;
return e.GrabbableAnchor != null ? $"{e.GrabbableAnchor.name}{id}" : string.Empty;
}
///
/// Gets the log string describing the grabbable object.
///
/// Event with the grabbable object to log
/// Whether to include information of the component unique IDs
/// Log string
private static string GetGrabbableObjectLogInfo(UxrManipulationEventArgs e, bool includeIds)
{
string id = e.GrabbableObject != null && includeIds ? $" (id {e.GrabbableObject.UniqueId})" : string.Empty;
string grabPointInfo = e.GrabbableObject != null && e.GrabbableObject.GrabPointCount > 1 && e.GrabPointIndex >= 0 ? $" (grab point {e.GrabPointIndex})" : string.Empty;
return e.GrabbableObject != null ? $"{e.GrabbableObject.name}{id}{grabPointInfo}" : string.Empty;
}
#endregion
#region Private Types & Data
private UxrManipulationEventType _eventType;
private UxrGrabbableObject _grabbableObject;
private UxrGrabbableObjectAnchor _grabbableAnchor;
private UxrGrabber _grabber;
private int _grabPointIndex;
private bool _isMultiHands;
private bool _isSwitchHands;
private Vector3 _releaseVelocity;
private Vector3 _releaseAngularVelocity;
private UxrPlacementOptions _placementOptions;
private Vector3 _grabberLocalObjectPosition;
private Quaternion _grabberLocalObjectRotation;
private Vector3 _grabberLocalSnapPosition;
private Quaternion _grabberLocalSnapRotation;
private Vector3 _releaseStartPosition;
private Quaternion _releaseStartRotation;
#endregion
}
}