using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.CompilerServices;
using UnityEditor;
using UnityEngine;
using UnityEngine.Rendering;
using UnityEngine.UIElements;
using UnityEngine.Serialization;
[assembly: InternalsVisibleTo("Unity.AdaptivePerformance.Tests")]
namespace UnityEngine.AdaptivePerformance
{
///
/// Class to handle active loader and subsystem management for Adaptive Performance. This class is to be added as a
/// ScriptableObject asset in your project and should only be referenced by an
/// instance for its use.
///
/// Given a list of loaders, it will attempt to load each loader in the given order. Unity will use the first
/// loader that is successful and ignore all remaining loaders. The successful loader
/// is accessible through the property on the manager.
///
/// Depending on configuration, the instance will automatically manage the active loader
/// at the correct points in the application lifecycle. You can override certain points in the active loader lifecycle
/// and manually manage them by toggling the and
/// properties. Disabling implies that you are responsible for the full lifecycle
/// of the Adaptive Performance session normally handled by the instance. Setting this to false also sets
/// to false.
///
/// Disabling only implies that you are responsible for starting and stopping
/// the through the and APIs.
///
/// Unity executes atomatic lifecycle management as follows:
///
/// * OnEnable calls internally. The loader list will be iterated over and the first successful loader will be set as the active loader.
/// * Start calls internally. Ask the active loader to start all subsystems.
/// * OnDisable calls internally. Ask the active loader to stop all subsystems.
/// * OnDestroy calls internally. Deinitialize and remove the active loader.
///
public sealed class AdaptivePerformanceManagerSettings : ScriptableObject
{
[HideInInspector]
bool m_InitializationComplete = false;
[SerializeField]
[Tooltip("Determines if the Adaptive Performance Manager instance is responsible for creating and destroying the appropriate loader instance.")]
bool m_AutomaticLoading = false;
///
/// Get and set Automatic Loading state for this manager. When this is true, the manager will automatically call
/// and for you. When false,
/// is also set to false and remains that way. This means that disabling automatic loading disables all automatic behavior
/// for the manager.
///
public bool automaticLoading
{
get { return m_AutomaticLoading; }
set { m_AutomaticLoading = value; }
}
[SerializeField]
[Tooltip("Determines if the Adaptive Performance Manager instance is responsible for starting and stopping subsystems for the active loader instance.")]
bool m_AutomaticRunning = false;
///
/// Get and set the automatic running state for this manager. When this is true, the manager will call
/// and APIs at appropriate times. When false, or when is false,
/// it is up to the user of the manager to handle that same functionality.
///
public bool automaticRunning
{
get { return m_AutomaticRunning; }
set { m_AutomaticRunning = value; }
}
[SerializeField]
[Tooltip("List of Adaptive Performance Loader instances arranged in desired load order.")]
List m_Loaders = new List();
///
/// List of loaders currently managed by this Adaptive Performance Manager instance.
///
public List loaders
{
get { return m_Loaders; }
#if UNITY_EDITOR
set { m_Loaders = value; }
#endif
}
///
/// Read-only boolean that is true if initialization is completed and false otherwise. Because initialization is
/// handled as a Coroutine, applications that use the auto-lifecycle management of AdaptivePerformanceManager
/// will need to wait for init to complete before checking for an ActiveLoader and calling StartSubsystems.
///
public bool isInitializationComplete
{
get { return m_InitializationComplete; }
}
[HideInInspector]
static AdaptivePerformanceLoader s_ActiveLoader = null;
///
/// Returns the current singleton active loader instance.
///
[HideInInspector]
public AdaptivePerformanceLoader activeLoader { get { return s_ActiveLoader; } private set { s_ActiveLoader = value; } }
///
/// Returns the current active loader, cast to the requested type. Useful shortcut when you need
/// to get the active loader as something less generic than AdaptivePerformanceLoader.
///
/// Requested type of the loader.
/// The active loader as requested type, or null if no active loader currently exists.
public T ActiveLoaderAs() where T : AdaptivePerformanceLoader
{
return activeLoader as T;
}
///
/// Iterate over the configured list of loaders and attempt to initialize each one. The first one
/// that succeeds is set as the active loader and initialization immediately terminates.
///
/// When this completes, will be set to true. This will mark that it is safe to
/// call other parts of the API, but does not guarantee that init successfully created a loader. To check that init successfully created a loader,
/// you need to check that ActiveLoader is not null.
///
/// **Note**: There can only be one active loader. Any attempt to initialize a new active loader with one
/// already set will cause a warning to be logged and immediate exit of this function.
///
/// This method is synchronous and on return all state should be immediately checkable.
///
public void InitializeLoaderSync()
{
if (isInitializationComplete && activeLoader != null)
{
Debug.LogWarning(
"Adaptive Performance Management has already initialized an active loader in this scene." +
"Please make sure to stop all subsystems and deinitialize the active loader before initializing a new one.");
return;
}
foreach (var loader in loaders)
{
if (loader != null)
{
if (loader.Initialize())
{
activeLoader = loader;
m_InitializationComplete = true;
return;
}
}
}
activeLoader = null;
}
///
/// Iterate over the configured list of loaders and attempt to initialize each one. The first one
/// that succeeds is set as the active loader and initialization immediately terminates.
///
/// When complete, will be set to true. This will mark that it is safe to
/// call other parts of the API, but does not guarantee that init successfully created a loader. To check that init successfully created a loader,
/// you need to check that ActiveLoader is not null.
///
/// **Note:** There can only be one active loader. Any attempt to initialize a new active loader with one
/// already set will cause a warning to be logged and this function wil immeditely exit.
///
/// Iteration is done asynchronously. You must call this method within the context of a Coroutine.
///
///
/// Enumerator marking the next spot to continue execution at.
public IEnumerator InitializeLoader()
{
if (isInitializationComplete && activeLoader != null)
{
Debug.LogWarning(
"Adaptive Performance Management has already initialized an active loader in this scene." +
"Please make sure to stop all subsystems and deinitialize the active loader before initializing a new one.");
yield break;
}
foreach (var loader in loaders)
{
if (loader != null)
{
if (loader.Initialize())
{
activeLoader = loader;
m_InitializationComplete = true;
yield break;
}
}
yield return null;
}
activeLoader = null;
}
///
/// If there is an active loader, this will request the loader to start all the subsystems that it
/// is managing.
///
/// You must wait for to be set to true before calling this API.
///
public void StartSubsystems()
{
if (!m_InitializationComplete)
{
Debug.LogWarning(
"Call to StartSubsystems without an initialized manager." +
"Please make sure to wait for initialization to complete before calling this API.");
return;
}
if (activeLoader != null)
{
activeLoader.Start();
}
}
///
/// If there is an active loader, this will request the loader to stop all the subsystems that it
/// is managing.
///
/// You must wait for to be set to true before calling this API.
///
public void StopSubsystems()
{
if (!m_InitializationComplete)
{
Debug.LogWarning(
"Call to StopSubsystems without an initialized manager." +
"Please make sure to wait for initialization to complete before calling this API.");
return;
}
if (activeLoader != null)
{
activeLoader.Stop();
}
}
///
/// If there is an active loader, this function will deinitialize it and remove the active loader instance from
/// management. Unity will automatically call before deinitialization to make sure
/// that things are cleaned up appropriately.
///
/// You must wait for to be set to true before calling this API.
///
/// On return, will be set to false.
///
public void DeinitializeLoader()
{
if (!m_InitializationComplete)
{
Debug.LogWarning(
"Call to DeinitializeLoader without an initialized manager." +
"Please make sure to wait for initialization to complete before calling this API.");
return;
}
StopSubsystems();
if (activeLoader != null)
{
activeLoader.Deinitialize();
activeLoader = null;
}
m_InitializationComplete = false;
}
// Use this for initialization
void Start()
{
if (automaticLoading && automaticRunning)
{
StartSubsystems();
}
}
void OnDisable()
{
if (automaticLoading && automaticRunning)
{
StopSubsystems();
}
}
void OnDestroy()
{
if (automaticLoading)
{
DeinitializeLoader();
}
}
}
}