mixedreality/com.microsoft.mixedreality..../Services/TeleportSystem/MixedRealityTeleportSystem.cs

318 lines
12 KiB
C#

// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
using Microsoft.MixedReality.Toolkit.Input;
using Microsoft.MixedReality.Toolkit.Utilities;
using Unity.Profiling;
using UnityEngine;
using UnityEngine.EventSystems;
namespace Microsoft.MixedReality.Toolkit.Teleport
{
/// <summary>
/// The Mixed Reality Toolkit's implementation of the <see cref="Microsoft.MixedReality.Toolkit.Teleport.IMixedRealityTeleportSystem"/>.
/// </summary>
public class MixedRealityTeleportSystem : BaseCoreSystem, IMixedRealityTeleportSystem
{
/// <summary>
/// Constructor.
/// </summary>
/// <param name="registrar">The <see cref="IMixedRealityServiceRegistrar"/> instance that loaded the service.</param>
[System.Obsolete("This constructor is obsolete (registrar parameter is no longer required) and will be removed in a future version of the Microsoft Mixed Reality Toolkit.")]
public MixedRealityTeleportSystem(
IMixedRealityServiceRegistrar registrar) : base(registrar, null) // Teleport system does not use a profile
{
Registrar = registrar;
}
/// <summary>
/// Constructor.
/// </summary>
public MixedRealityTeleportSystem() : base(null) { } // Teleport system does not use a profile
private TeleportEventData teleportEventData;
private bool isTeleporting = false;
private bool isProcessingTeleportRequest = false;
private Vector3 targetPosition = Vector3.zero;
private Vector3 targetRotation = Vector3.zero;
/// <summary>
/// Used to clean up event system when shutting down, if this system created one.
/// </summary>
private GameObject eventSystemReference = null;
#region IMixedRealityService Implementation
/// <inheritdoc/>
public override string Name { get; protected set; } = "Mixed Reality Teleport System";
/// <inheritdoc />
public override void Initialize()
{
base.Initialize();
InitializeInternal();
}
private void InitializeInternal()
{
#if UNITY_EDITOR
if (!UnityEditor.EditorApplication.isPlaying)
{
var eventSystems = Object.FindObjectsOfType<EventSystem>();
if (eventSystems.Length == 0)
{
if (!IsInputSystemEnabled)
{
eventSystemReference = new GameObject("Event System");
eventSystemReference.AddComponent<EventSystem>();
}
else
{
Debug.Log("The input system didn't properly add an event system to your scene. Please make sure the input system's priority is set higher than the teleport system.");
}
}
else if (eventSystems.Length > 1)
{
Debug.Log("Too many event systems in the scene. The Teleport System requires only one.");
}
}
#endif // UNITY_EDITOR
teleportEventData = new TeleportEventData(EventSystem.current);
}
/// <inheritdoc />
public override void Destroy()
{
base.Destroy();
if (eventSystemReference != null)
{
if (!Application.isPlaying)
{
Object.DestroyImmediate(eventSystemReference);
}
else
{
Object.Destroy(eventSystemReference);
}
}
}
#endregion IMixedRealityService Implementation
#region IEventSystemManager Implementation
private static readonly ProfilerMarker HandleEventPerfMarker = new ProfilerMarker("[MRTK] MixedRealityTeleportSystem.HandleEvent");
/// <inheritdoc />
public override void HandleEvent<T>(BaseEventData eventData, ExecuteEvents.EventFunction<T> eventHandler)
{
using (HandleEventPerfMarker.Auto())
{
Debug.Assert(eventData != null);
var teleportData = ExecuteEvents.ValidateEventData<TeleportEventData>(eventData);
Debug.Assert(teleportData != null);
Debug.Assert(!teleportData.used);
// Process all the event listeners
base.HandleEvent(teleportData, eventHandler);
}
}
/// <summary>
/// Register a <see href="https://docs.unity3d.com/ScriptReference/GameObject.html">GameObject</see> to listen to teleport events.
/// </summary>
public override void Register(GameObject listener) => base.Register(listener);
/// <summary>
/// Unregister a <see href="https://docs.unity3d.com/ScriptReference/GameObject.html">GameObject</see> from listening to teleport events.
/// </summary>
public override void Unregister(GameObject listener) => base.Unregister(listener);
#endregion IEventSystemManager Implementation
#region IMixedRealityTeleportSystem Implementation
/// <summary>
/// Is an input system registered?
/// </summary>
private bool IsInputSystemEnabled => CoreServices.InputSystem != null;
private float teleportDuration = 0.25f;
/// <inheritdoc />
public float TeleportDuration
{
get => teleportDuration;
set
{
if (isProcessingTeleportRequest)
{
Debug.LogWarning("Couldn't change teleport duration. Teleport in progress.");
return;
}
teleportDuration = value;
}
}
private static readonly ExecuteEvents.EventFunction<IMixedRealityTeleportHandler> OnTeleportRequestHandler =
delegate (IMixedRealityTeleportHandler handler, BaseEventData eventData)
{
var casted = ExecuteEvents.ValidateEventData<TeleportEventData>(eventData);
handler.OnTeleportRequest(casted);
};
private static readonly ProfilerMarker RaiseTeleportRequestPerfMarker = new ProfilerMarker("[MRTK] MixedRealityTeleportSystem.RaiseTeleportRequest");
/// <inheritdoc />
public void RaiseTeleportRequest(IMixedRealityPointer pointer, IMixedRealityTeleportHotspot hotSpot)
{
using (RaiseTeleportRequestPerfMarker.Auto())
{
// initialize event
teleportEventData.Initialize(pointer, hotSpot);
// Pass handler
HandleEvent(teleportEventData, OnTeleportRequestHandler);
}
}
private static readonly ExecuteEvents.EventFunction<IMixedRealityTeleportHandler> OnTeleportStartedHandler =
delegate (IMixedRealityTeleportHandler handler, BaseEventData eventData)
{
var casted = ExecuteEvents.ValidateEventData<TeleportEventData>(eventData);
handler.OnTeleportStarted(casted);
};
private static readonly ProfilerMarker RaiseTeleportStartedPerfMarker = new ProfilerMarker("[MRTK] MixedRealityTeleportSystem.RaiseTeleportStarted");
/// <inheritdoc />
public void RaiseTeleportStarted(IMixedRealityPointer pointer, IMixedRealityTeleportHotspot hotSpot)
{
if (isTeleporting)
{
Debug.LogError("Teleportation already in progress");
return;
}
using (RaiseTeleportStartedPerfMarker.Auto())
{
isTeleporting = true;
// initialize event
teleportEventData.Initialize(pointer, hotSpot);
// Pass handler
HandleEvent(teleportEventData, OnTeleportStartedHandler);
ProcessTeleportationRequest(teleportEventData);
}
}
private static readonly ExecuteEvents.EventFunction<IMixedRealityTeleportHandler> OnTeleportCompletedHandler =
delegate (IMixedRealityTeleportHandler handler, BaseEventData eventData)
{
var casted = ExecuteEvents.ValidateEventData<TeleportEventData>(eventData);
handler.OnTeleportCompleted(casted);
};
private static readonly ProfilerMarker RaiseTeleportCompletePerfMarker = new ProfilerMarker("[MRTK] MixedRealityTeleportSystem.RaiseTeleportComplete");
/// <summary>
/// Raise a teleportation completed event.
/// </summary>
/// <param name="pointer">The pointer that raised the event.</param>
/// <param name="hotSpot">The teleport target</param>
private void RaiseTeleportComplete(IMixedRealityPointer pointer, IMixedRealityTeleportHotspot hotSpot)
{
if (!isTeleporting)
{
Debug.LogError("No Active Teleportation in progress.");
return;
}
using (RaiseTeleportCompletePerfMarker.Auto())
{
// initialize event
teleportEventData.Initialize(pointer, hotSpot);
// Pass handler
HandleEvent(teleportEventData, OnTeleportCompletedHandler);
isTeleporting = false;
}
}
private static readonly ExecuteEvents.EventFunction<IMixedRealityTeleportHandler> OnTeleportCanceledHandler =
delegate (IMixedRealityTeleportHandler handler, BaseEventData eventData)
{
var casted = ExecuteEvents.ValidateEventData<TeleportEventData>(eventData);
handler.OnTeleportCanceled(casted);
};
private static readonly ProfilerMarker RaiseTeleportCanceledPerfMarker = new ProfilerMarker("[MRTK] MixedRealityTeleportSystem.RaiseTeleportHandled");
/// <inheritdoc />
public void RaiseTeleportCanceled(IMixedRealityPointer pointer, IMixedRealityTeleportHotspot hotSpot)
{
using (RaiseTeleportCanceledPerfMarker.Auto())
{
// initialize event
teleportEventData.Initialize(pointer, hotSpot);
// Pass handler
HandleEvent(teleportEventData, OnTeleportCanceledHandler);
}
}
#endregion IMixedRealityTeleportSystem Implementation
private static readonly ProfilerMarker ProcessTeleportationRequestPerfMarker = new ProfilerMarker("[MRTK] MixedRealityTeleportSystem.ProcessTeleportationRequest");
private void ProcessTeleportationRequest(TeleportEventData eventData)
{
using (ProcessTeleportationRequestPerfMarker.Auto())
{
isProcessingTeleportRequest = true;
targetRotation = Vector3.zero;
if (eventData.Pointer is IMixedRealityTeleportPointer teleportPointer && !teleportPointer.IsNull())
{
targetRotation.y = teleportPointer.PointerOrientation;
}
targetPosition = eventData.Pointer.Result.Details.Point;
if (eventData.Hotspot != null)
{
targetPosition = eventData.Hotspot.Position;
if (eventData.Hotspot.OverrideOrientation)
{
targetRotation.y = eventData.Hotspot.TargetRotation;
}
}
float height = targetPosition.y;
targetPosition -= CameraCache.Main.transform.position - MixedRealityPlayspace.Position;
targetPosition.y = height;
MixedRealityPlayspace.Position = targetPosition;
MixedRealityPlayspace.RotateAround(
CameraCache.Main.transform.position,
Vector3.up,
targetRotation.y - CameraCache.Main.transform.eulerAngles.y);
isProcessingTeleportRequest = false;
// Raise complete event using the pointer and hot spot provided.
RaiseTeleportComplete(eventData.Pointer, eventData.Hotspot);
}
}
}
}