projectEli/Assets/NeoFPS/Core/NeoSaveGames/SceneManagement/NeoSceneManager.cs
2022-11-06 20:28:33 -05:00

421 lines
17 KiB
C#

using System;
using System.Collections;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.SceneManagement;
namespace NeoSaveGames.SceneManagement
{
[CreateAssetMenu(fileName = "FpsManager_NeoSceneManager", menuName = "NeoFPS/Managers/Scene Manager", order = NeoFPS.NeoFpsMenuPriorities.manager_scene)]
[HelpURL("https://docs.neofps.com/manual/savegamesref-so-scenemanager.html")]
public class NeoSceneManager : NeoFPS.NeoFpsManager<NeoSceneManager>
{
private static RuntimeBehaviour s_ProxyGameObject = null;
private static bool s_Busy = false;
[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.BeforeSceneLoad)]
static void LoadNeoSceneManager()
{
GetInstance("FpsManager_NeoSceneManager");
}
protected override void Initialise()
{
s_ProxyGameObject = GetBehaviourProxy<RuntimeBehaviour>();
}
public override bool IsValid()
{
return true;
}
[SerializeField, Tooltip("The loading screen scene to load by default if a custom one is not specified.")]
private int m_DefaultLoadingScreenIndex = -1;
[SerializeField, Tooltip("The minimum amount of time the loading screen should be shown for. This prevents the loading screen from appearing for fractions of a second. Useful if you show tips.")]
private float m_MinLoadScreenTime = 2f;
[Header("Scene Load Events")]
[SerializeField] private SceneLoadEvent m_OnSceneLoaded = new SceneLoadEvent();
[SerializeField] private UnityEvent m_PreSceneActivation = new UnityEvent();
[SerializeField] private UnityEvent m_OnSceneLoadFailed = new UnityEvent();
enum LoadMode
{
Index,
Name,
Neither
}
[Serializable]
public class SceneLoadEvent : UnityEvent<int> { }
public class RuntimeBehaviour : MonoBehaviour { }
public static int defaultLoadingScreenIndex
{
get
{
if (instance != null)
return instance.m_DefaultLoadingScreenIndex;
else
{
Debug.LogWarning("NeoSceneManager instance not found");
return -1;
}
}
}
public static event UnityAction<int> onSceneLoaded
{
add
{
if (instance != null)
instance.m_OnSceneLoaded.AddListener(value);
}
remove
{
if (instance != null)
instance.m_OnSceneLoaded.RemoveListener(value);
}
}
public static event UnityAction preSceneActivation
{
add
{
if (instance != null)
instance.m_PreSceneActivation.AddListener(value);
}
remove
{
if (instance != null)
instance.m_PreSceneActivation.RemoveListener(value);
}
}
public static event UnityAction onSceneLoadFailed
{
add
{
if (instance != null)
instance.m_OnSceneLoadFailed.AddListener(value);
}
remove
{
if (instance != null)
instance.m_OnSceneLoadFailed.RemoveListener(value);
}
}
private void OnValidate()
{
m_MinLoadScreenTime = Mathf.Clamp(m_MinLoadScreenTime, 0f, 60f);
}
public static bool isSceneValid(string sceneName)
{
return sceneName != null && Application.CanStreamedLevelBeLoaded(sceneName);
}
public static bool isSceneValid(int sceneIndex)
{
return Application.CanStreamedLevelBeLoaded(sceneIndex);
}
#region OVERRIDES
public static void LoadScene(string sceneName)
{
if (instance != null && !s_Busy)
s_ProxyGameObject.StartCoroutine(LoadSceneInternal(sceneName, -1, null, defaultLoadingScreenIndex, null, null));
}
public static void LoadScene(int sceneIndex)
{
if (instance != null && !s_Busy)
s_ProxyGameObject.StartCoroutine(LoadSceneInternal(null, sceneIndex, null, defaultLoadingScreenIndex, null, null));
}
public static void LoadScene(string sceneName, string loadingSceneName)
{
if (instance != null && !s_Busy)
s_ProxyGameObject.StartCoroutine(LoadSceneInternal(sceneName, -1, loadingSceneName, -1, null, null));
}
public static void LoadScene(int sceneIndex, int loadingIndex)
{
if (instance != null && !s_Busy)
s_ProxyGameObject.StartCoroutine(LoadSceneInternal(null, sceneIndex, null, loadingIndex, null, null));
}
public static void LoadScene(string sceneName, int loadingIndex)
{
if (instance != null && !s_Busy)
s_ProxyGameObject.StartCoroutine(LoadSceneInternal(sceneName, -1, null, loadingIndex, null, null));
}
public static void LoadScene(int sceneIndex, string loadingSceneName)
{
if (instance != null && !s_Busy)
s_ProxyGameObject.StartCoroutine(LoadSceneInternal(null, sceneIndex, loadingSceneName, -1, null, null));
}
public static void LoadScene(string sceneName, Action onComplete)
{
if (instance != null && !s_Busy)
s_ProxyGameObject.StartCoroutine(LoadSceneInternal(sceneName, -1, null, defaultLoadingScreenIndex, null, onComplete));
}
public static void LoadScene(int sceneIndex, Action onComplete)
{
if (instance != null && !s_Busy)
s_ProxyGameObject.StartCoroutine(LoadSceneInternal(null, sceneIndex, null, defaultLoadingScreenIndex, null, onComplete));
}
public static void LoadScene(string sceneName, string loadingSceneName, Action onComplete)
{
if (instance != null && !s_Busy)
s_ProxyGameObject.StartCoroutine(LoadSceneInternal(sceneName, -1, loadingSceneName, -1, null, onComplete));
}
public static void LoadScene(int sceneIndex, int loadingIndex, Action onComplete)
{
if (instance != null && !s_Busy)
s_ProxyGameObject.StartCoroutine(LoadSceneInternal(null, sceneIndex, null, loadingIndex, null, onComplete));
}
public static void LoadScene(string sceneName, int loadingIndex, Action onComplete)
{
if (instance != null && !s_Busy)
s_ProxyGameObject.StartCoroutine(LoadSceneInternal(sceneName, -1, null, loadingIndex, null, onComplete));
}
public static void LoadScene(int sceneIndex, string loadingSceneName, Action onComplete)
{
if (instance != null && !s_Busy)
s_ProxyGameObject.StartCoroutine(LoadSceneInternal(null, sceneIndex, loadingSceneName, -1, null, onComplete));
}
public static void LoadScene(string sceneName, Action<Scene> activationCallback)
{
if (instance != null && !s_Busy)
s_ProxyGameObject.StartCoroutine(LoadSceneInternal(sceneName, -1, null, defaultLoadingScreenIndex, activationCallback, null));
}
public static void LoadScene(int sceneIndex, Action<Scene> activationCallback)
{
if (instance != null && !s_Busy)
s_ProxyGameObject.StartCoroutine(LoadSceneInternal(null, sceneIndex, null, defaultLoadingScreenIndex, activationCallback, null));
}
public static void LoadScene(string sceneName, string loadingSceneName, Action<Scene> activationCallback)
{
if (instance != null && !s_Busy)
s_ProxyGameObject.StartCoroutine(LoadSceneInternal(sceneName, -1, loadingSceneName, -1, activationCallback, null));
}
public static void LoadScene(int sceneIndex, int loadingIndex, Action<Scene> activationCallback)
{
if (instance != null && !s_Busy)
s_ProxyGameObject.StartCoroutine(LoadSceneInternal(null, sceneIndex, null, loadingIndex, activationCallback, null));
}
public static void LoadScene(string sceneName, int loadingIndex, Action<Scene> activationCallback)
{
if (instance != null && !s_Busy)
s_ProxyGameObject.StartCoroutine(LoadSceneInternal(sceneName, -1, null, loadingIndex, activationCallback, null));
}
public static void LoadScene(int sceneIndex, string loadingSceneName, Action<Scene> activationCallback)
{
if (instance != null && !s_Busy)
s_ProxyGameObject.StartCoroutine(LoadSceneInternal(null, sceneIndex, loadingSceneName, -1, activationCallback, null));
}
public static void LoadScene(string sceneName, Action<Scene> activationCallback, Action onComplete)
{
if (instance != null && !s_Busy)
s_ProxyGameObject.StartCoroutine(LoadSceneInternal(sceneName, -1, null, defaultLoadingScreenIndex, activationCallback, onComplete));
}
public static void LoadScene(int sceneIndex, Action<Scene> activationCallback, Action onComplete)
{
if (instance != null && !s_Busy)
s_ProxyGameObject.StartCoroutine(LoadSceneInternal(null, sceneIndex, null, defaultLoadingScreenIndex, activationCallback, onComplete));
}
public static void LoadScene(string sceneName, string loadingSceneName, Action<Scene> activationCallback, Action onComplete)
{
if (instance != null && !s_Busy)
s_ProxyGameObject.StartCoroutine(LoadSceneInternal(sceneName, -1, loadingSceneName, -1, activationCallback, onComplete));
}
public static void LoadScene(int sceneIndex, int loadingIndex, Action<Scene> activationCallback, Action onComplete)
{
if (instance != null && !s_Busy)
s_ProxyGameObject.StartCoroutine(LoadSceneInternal(null, sceneIndex, null, loadingIndex, activationCallback, onComplete));
}
public static void LoadScene(string sceneName, int loadingIndex, Action<Scene> activationCallback, Action onComplete)
{
if (instance != null && !s_Busy)
s_ProxyGameObject.StartCoroutine(LoadSceneInternal(sceneName, -1, null, loadingIndex, activationCallback, onComplete));
}
public static void LoadScene(int sceneIndex, string loadingSceneName, Action<Scene> activationCallback, Action onComplete)
{
if (instance != null && !s_Busy)
s_ProxyGameObject.StartCoroutine(LoadSceneInternal(null, sceneIndex, loadingSceneName, -1, activationCallback, onComplete));
}
#endregion
static IEnumerator LoadSceneInternal(string sceneName, int sceneIndex, string loadingSceneName, int loadingSceneIndex, Action<Scene> activationCallback, Action onComplete)
{
s_Busy = true;
// Check how to load the scene
LoadMode sceneLoadMode = LoadMode.Neither;
if (isSceneValid(sceneIndex))
sceneLoadMode = LoadMode.Index;
else
{
if (isSceneValid(sceneName))
sceneLoadMode = LoadMode.Name;
}
if (sceneLoadMode == LoadMode.Neither)
{
Debug.LogError(string.Format("Attempting to load invalid scene. Check it exists and is added to the build options.", sceneName));
instance.m_OnSceneLoadFailed.Invoke();
if (onComplete != null)
onComplete();
}
else
{
// Check how to load the loading overlay scene
LoadMode overlayLoadMode = LoadMode.Neither;
if (isSceneValid(loadingSceneIndex))
overlayLoadMode = LoadMode.Index;
else
{
if (isSceneValid(loadingSceneName))
overlayLoadMode = LoadMode.Name;
}
if (overlayLoadMode == LoadMode.Neither)
{
Debug.LogError("\"Loading\" scene is not valid. Reverting to standard SceneManager.");
AsyncOperation op = null;
if (sceneLoadMode == LoadMode.Index)
op = SceneManager.LoadSceneAsync(sceneIndex, LoadSceneMode.Single);
else
op = SceneManager.LoadSceneAsync(sceneName, LoadSceneMode.Single);
while (!op.isDone)
yield return null;
// Signal completion
if (onComplete != null)
onComplete();
}
else
{
var startTime = Time.realtimeSinceStartup;
AsyncOperation op = null;
Scene loadingScene = new Scene();
// Open "loading" scene (immediate)
if (overlayLoadMode == LoadMode.Index)
{
op = SceneManager.LoadSceneAsync(loadingSceneIndex, LoadSceneMode.Single);
loadingScene = SceneManager.GetSceneByBuildIndex(loadingSceneIndex);
}
else
{
op = SceneManager.LoadSceneAsync(loadingSceneName, LoadSceneMode.Single);
loadingScene = SceneManager.GetSceneByName(loadingSceneName);
}
while (!op.isDone)
yield return null;
// Load the main scene in the background (async)
Scene scene = new Scene();
if (sceneLoadMode == LoadMode.Index)
{
op = SceneManager.LoadSceneAsync(sceneIndex, LoadSceneMode.Additive);
scene = SceneManager.GetSceneByBuildIndex(sceneIndex);
}
else
{
op = SceneManager.LoadSceneAsync(sceneName, LoadSceneMode.Additive);
//sceneName = sceneName.Substring(7, sceneName.Length - 13);
scene = SceneManager.GetSceneByName(sceneName);
if (!scene.IsValid())
scene = SceneManager.GetSceneByPath(sceneName);
}
SceneManager.sceneLoaded += OnSceneLoaded;
// Prevent activation and wait for pre-activation to complete
op.allowSceneActivation = false;
while (op.progress < 0.9f)
yield return null;
// Wait for minimum load time
while (Time.realtimeSinceStartup < startTime + instance.m_MinLoadScreenTime)
yield return null;
// Invoke pre-activation event
instance.m_PreSceneActivation.Invoke();
// Allow activation and wait for complete
op.allowSceneActivation = true;
while (!op.isDone)
yield return null;
// Set the scene to active and signal activation
SceneManager.SetActiveScene(scene);
if (activationCallback != null)
activationCallback(scene);
#if UNITY_2019_3_OR_NEWER
// Rebuild light-probes
LightProbes.Tetrahedralize();
#endif
// Unload the "loading" scene
op = SceneManager.UnloadSceneAsync(loadingScene.buildIndex);
if (op == null)
{
Debug.LogError("Can't unload \"Loading\" scene, because the main scene failed to load.");
// Invoke failed event
instance.m_OnSceneLoadFailed.Invoke();
}
else
{
while (!op.isDone)
yield return null;
// Invoke succeeded event
instance.m_OnSceneLoaded.Invoke(scene.buildIndex);
}
// Signal completion
if (onComplete != null)
onComplete();
}
}
s_Busy = false;
}
static void OnSceneLoaded(Scene s, LoadSceneMode mode)
{
SceneManager.SetActiveScene(s);
SceneManager.sceneLoaded -= OnSceneLoaded;
}
}
}