VR4Medical/ICI/Library/PackageCache/com.unity.xr.openxr@3903c1059bcf/Runtime/OpenXRRestarter.cs
2025-07-29 13:45:50 +03:00

292 lines
8.4 KiB
C#

using System;
using System.Collections;
using UnityEngine;
using UnityEngine.XR.Management;
#if UNITY_EDITOR
using UnityEditor;
#endif
namespace UnityEngine.XR.OpenXR
{
internal class OpenXRRestarter : MonoBehaviour
{
internal Action onAfterRestart;
internal Action onAfterShutdown;
internal Action onQuit;
internal Action onAfterCoroutine;
internal Action onAfterSuccessfulRestart;
static OpenXRRestarter()
{
#if UNITY_EDITOR
EditorApplication.playModeStateChanged += (state) =>
{
if (state == PlayModeStateChange.EnteredPlayMode)
m_pauseAndRestartAttempts = 0;
};
#endif
TimeBetweenRestartAttempts = 5.0f;
DisableApplicationQuit = false;
}
public void ResetCallbacks()
{
onAfterRestart = null;
onAfterSuccessfulRestart = null;
onAfterShutdown = null;
onAfterCoroutine = null;
onQuit = null;
m_pauseAndRestartAttempts = 0;
}
/// <summary>
/// True if the restarter is currently running
/// </summary>
public bool isRunning => m_Coroutine != null;
private static OpenXRRestarter s_Instance = null;
private Coroutine m_Coroutine;
private static int m_pauseAndRestartCoroutineCount = 0;
private Object m_PauseAndRestartCoroutineCountLock = new Object();
private static int m_pauseAndRestartAttempts = 0;
public static float TimeBetweenRestartAttempts
{
get;
set;
}
public static int PauseAndRestartAttempts
{
get
{
return m_pauseAndRestartAttempts;
}
}
internal static int PauseAndRestartCoroutineCount
{
get
{
return m_pauseAndRestartCoroutineCount;
}
}
public static OpenXRRestarter Instance
{
get
{
if (s_Instance == null)
{
var go = GameObject.Find("~oxrestarter");
if (go == null)
{
go = new GameObject("~oxrestarter");
go.hideFlags = HideFlags.HideAndDontSave;
go.AddComponent<OpenXRRestarter>();
}
s_Instance = go.GetComponent<OpenXRRestarter>();
}
return s_Instance;
}
}
/// <summary>
/// If true, disables the application quitting, even when Quit is called.
/// Used in testing, which needs to monitor for Quit to be called.
/// </summary>
internal static bool DisableApplicationQuit
{
get;
set;
}
/// <summary>
/// Shutdown the the OpenXR loader and optionally quit the application
/// </summary>
public void Shutdown()
{
if (OpenXRLoader.Instance == null)
return;
if (m_Coroutine != null)
{
Debug.LogError("Only one shutdown or restart can be executed at a time");
return;
}
m_Coroutine = StartCoroutine(RestartCoroutine(false, true));
}
/// <summary>
/// Restart the OpenXR loader
/// </summary>
public void ShutdownAndRestart()
{
if (OpenXRLoader.Instance == null)
return;
if (m_Coroutine != null)
{
Debug.LogError("Only one shutdown or restart can be executed at a time");
return;
}
m_Coroutine = StartCoroutine(RestartCoroutine(true, true));
}
/// <summary>
/// Start a coroutine that will pause, then shut xr down, then re-initialize xr.
/// </summary>
public void PauseAndShutdownAndRestart()
{
if (OpenXRLoader.Instance == null)
{
return;
}
StartCoroutine(PauseAndShutdownAndRestartCoroutine(TimeBetweenRestartAttempts));
}
/// <summary>
/// Start a coroutine that will pause, then re-initialize xr if xr hasn't already succeeded.
/// </summary>
public void PauseAndRetryInitialization()
{
if (OpenXRLoader.Instance == null)
{
return;
}
StartCoroutine(PauseAndRetryInitializationCoroutine(TimeBetweenRestartAttempts));
}
private void IncrementPauseAndRestartCoroutineCount()
{
lock (m_PauseAndRestartCoroutineCountLock)
{
m_pauseAndRestartCoroutineCount += 1;
}
}
private void DecrementPauseAndRestartCoroutineCount()
{
lock (m_PauseAndRestartCoroutineCountLock)
{
m_pauseAndRestartCoroutineCount -= 1;
}
}
private IEnumerator PauseAndShutdownAndRestartCoroutine(float pauseTimeInSeconds)
{
IncrementPauseAndRestartCoroutineCount();
try
{
// Wait a few seconds to add delay between restart requests in a restart loop.
yield return new WaitForSeconds(pauseTimeInSeconds);
yield return new WaitForRestartFinish();
m_pauseAndRestartAttempts += 1;
m_Coroutine = StartCoroutine(RestartCoroutine(true, true));
}
finally
{
onAfterCoroutine?.Invoke();
}
DecrementPauseAndRestartCoroutineCount();
}
private IEnumerator PauseAndRetryInitializationCoroutine(float pauseTimeInSeconds)
{
IncrementPauseAndRestartCoroutineCount();
try
{
// Wait a few seconds to add delay between restart requests in a restart loop.
yield return new WaitForSeconds(pauseTimeInSeconds);
yield return new WaitForRestartFinish();
bool shouldSkipRestart = XRGeneralSettings.Instance.Manager.activeLoader != null;
if (!shouldSkipRestart)
{
m_pauseAndRestartAttempts += 1;
m_Coroutine = StartCoroutine(RestartCoroutine(true, false));
}
}
finally
{
onAfterCoroutine?.Invoke();
}
DecrementPauseAndRestartCoroutineCount();
}
private IEnumerator RestartCoroutine(bool shouldRestart, bool shouldShutdown)
{
try
{
if (shouldShutdown)
{
Debug.Log("Shutting down OpenXR.");
yield return null;
// Always shutdown the loader
XRGeneralSettings.Instance.Manager.DeinitializeLoader();
yield return null;
onAfterShutdown?.Invoke();
}
// Restart?
if (shouldRestart && OpenXRRuntime.ShouldRestart())
{
Debug.Log("Initializing OpenXR.");
yield return XRGeneralSettings.Instance.Manager.InitializeLoader();
XRGeneralSettings.Instance.Manager.StartSubsystems();
if (XRGeneralSettings.Instance.Manager.activeLoader != null)
{
m_pauseAndRestartAttempts = 0;
onAfterSuccessfulRestart?.Invoke();
}
onAfterRestart?.Invoke();
}
// Quit?
else if (OpenXRRuntime.ShouldQuit())
{
onQuit?.Invoke();
if (!DisableApplicationQuit)
{
#if UNITY_EDITOR
if (EditorApplication.isPlaying || EditorApplication.isPaused)
{
EditorApplication.ExitPlaymode();
}
#else
Application.Quit();
#endif
}
}
}
finally
{
m_Coroutine = null;
onAfterCoroutine?.Invoke();
}
}
}
}