Files
KopMap/Assets/NatureManufacture Assets/WorldStreamer/Scritps/Utils/StreamerLoadingManager.cs
2025-09-02 18:55:19 +08:00

354 lines
12 KiB
C#

using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;
namespace WorldStreamer2
{
public class StreamerLoadingManager
{
private enum SceneType
{
Scene,
Collider,
SceneSplit
}
private struct SceneToLoad
{
public SceneType SceneType;
public string SceneName;
public SceneSplit SceneSplit;
public ColliderStreamer ColliderStreamer;
}
private struct SceneToUnload
{
public SceneType SceneType;
public Scene Scene;
public SceneSplit SceneSplit;
public ColliderStreamer ColliderStreamer;
}
public Streamer Streamer;
private readonly List<SceneToUnload> _scenesToUnload = new();
public int ScenesToUnloadCount => _scenesToUnload.Count;
private readonly List<SceneToLoad> _scenesToLoad = new();
public int ScenesToLoadCount => _scenesToLoad.Count;
private readonly List<AsyncOperation> _asyncOperations = new();
public int AsyncOperationsCount => _asyncOperations.Count;
private LoadingState _loadingState = LoadingState.Loading;
private enum LoadingState
{
Loading,
Unloading
}
private bool _operationStarted;
public void Update()
{
//Debug.Log($"_operationStarted {_operationStarted}");
if (_operationStarted)
return;
//Debug.Log($"_loadingState {_loadingState}");
//Debug.Log(_asyncOperations.Count);
if (_asyncOperations.Count > 0)
return;
//Debug.Log($"_loadingState {_loadingState} {_scenesToLoad.Count} {_scenesToUnload.Count} {_asyncOperations.Count}");
if (_loadingState == LoadingState.Unloading)
{
if (_scenesToLoad.Count > 0)
{
_loadingState = LoadingState.Loading;
}
else if (_scenesToUnload.Count > 0)
{
// Debug.Log("scenesToUnload " + scenesToUnload.Count + " " + asyncOperations.Count);
_operationStarted = true;
Streamer.StartCoroutine(UnloadAsync());
//Unload();
}
}
if (_loadingState == LoadingState.Loading)
{
if (_scenesToLoad.Count > 0)
{
// Debug.Log("scenesToLoad " + scenesToLoad.Count + " " + asyncOperations.Count);
_operationStarted = true;
//Load();
Streamer.StartCoroutine(LoadAsync());
}
if (_scenesToLoad.Count == 0)
_loadingState = LoadingState.Unloading;
}
}
private IEnumerator LoadAsync()
{
// yield return new WaitForSeconds(0.5f);
for (int i = 0; i < _scenesToLoad.Count; i++)
{
int sceneID = SceneManager.sceneCount;
AsyncOperation asyncOperation;
if (_scenesToLoad[i].SceneType == SceneType.SceneSplit)
{
SceneSplit split = _scenesToLoad[i].SceneSplit;
if (CheckIfSplitIsUnloaded(split))
{
GameObject sceneGameObject = split.scene.GetRootGameObjects()[0];
Streamer.BaseSplitSetup(split, sceneGameObject);
//remove from unload list
_scenesToUnload.RemoveAll(x => x.SceneSplit == split);
}
else
{
asyncOperation = SceneManager.LoadSceneAsync(split.sceneName, LoadSceneMode.Additive);
if (asyncOperation != null)
{
asyncOperation.completed += (operation) =>
{
SceneLoadComplete(sceneID, split);
OnOperationDone(operation);
};
_asyncOperations.Add(asyncOperation);
}
}
}
else if (_scenesToLoad[i].SceneType == SceneType.Collider)
{
ColliderStreamer colliderStreamer = _scenesToLoad[i].ColliderStreamer;
if (CheckIfColliderIsUnloaded(colliderStreamer))
{
//remove from unload list
_scenesToUnload.RemoveAll(x => x.ColliderStreamer == colliderStreamer);
colliderStreamer.SetSceneGameObject(colliderStreamer.sceneGameObject);
}
else
{
asyncOperation = SceneManager.LoadSceneAsync(colliderStreamer.sceneName, LoadSceneMode.Additive);
if (asyncOperation != null)
{
asyncOperation.completed += (operation) =>
{
//
OnOperationDone(operation);
};
_asyncOperations.Add(asyncOperation);
}
}
}
else
{
if (CheckIfSceneIsUnloaded(_scenesToLoad[i].SceneName))
{
_scenesToUnload.RemoveAll(x => x.Scene.name == _scenesToLoad[i].SceneName);
}
else
{
asyncOperation = SceneManager.LoadSceneAsync(_scenesToLoad[i].SceneName, LoadSceneMode.Additive);
if (asyncOperation != null)
{
asyncOperation.completed += OnOperationDone;
_asyncOperations.Add(asyncOperation);
}
}
}
yield return null;
}
_scenesToLoad.Clear();
//Debug.Log("Load finished " + asyncOperations.Count);
_operationStarted = false;
}
private bool CheckIfSceneIsUnloaded(string sceneName)
{
for (int i = 0; i < _scenesToUnload.Count; i++)
{
if (_scenesToUnload[i].SceneType == SceneType.Scene && _scenesToUnload[i].Scene.name == sceneName)
{
return true;
}
}
return false;
}
private bool CheckIfSplitIsUnloaded(SceneSplit split)
{
for (int i = 0; i < _scenesToUnload.Count; i++)
{
if (_scenesToUnload[i].SceneSplit == split)
{
return true;
}
}
return false;
}
private bool CheckIfColliderIsUnloaded(ColliderStreamer colliderStreamer)
{
for (int i = 0; i < _scenesToUnload.Count; i++)
{
if (_scenesToUnload[i].SceneType == SceneType.Collider && _scenesToUnload[i].ColliderStreamer == colliderStreamer)
{
return true;
}
}
return false;
}
private void SceneLoadComplete(int sceneID, SceneSplit split)
{
//Debug.Log(SceneManager.GetSceneAt(sceneID).name);
Streamer.StartCoroutine(SceneLoadCompleteAsync(sceneID, split));
}
private IEnumerator SceneLoadCompleteAsync(int sceneID, SceneSplit split)
{
yield return null;
Streamer.OnSceneLoaded(SceneManager.GetSceneAt(sceneID), split);
}
private void OnOperationDone(AsyncOperation asyncOperation)
{
//Debug.Log($"onOperationDone {asyncOperation.isDone} {_asyncOperations.Count}");
Streamer.StartCoroutine(RemoveAsyncOperation(asyncOperation));
}
private IEnumerator RemoveAsyncOperation(AsyncOperation asyncOperation)
{
yield return null;
yield return null;
_asyncOperations.Remove(asyncOperation);
}
private IEnumerator UnloadAsync()
{
yield return null;
//Debug.Log(asyncOperations.Count);
for (int i = 0; i < _scenesToUnload.Count; i++)
{
Scene sceneToUnload;
switch (_scenesToUnload[i].SceneType)
{
case SceneType.Scene:
sceneToUnload = _scenesToUnload[i].Scene;
break;
case SceneType.SceneSplit:
sceneToUnload = _scenesToUnload[i].SceneSplit.scene;
CheckForColliderStreamer(_scenesToUnload[i].SceneSplit);
break;
case SceneType.Collider:
if (_scenesToUnload[i].ColliderStreamer.sceneGameObject != null)
{
sceneToUnload = _scenesToUnload[i].ColliderStreamer.sceneGameObject.scene;
_scenesToUnload[i].ColliderStreamer.sceneGameObject = null;
}
else
continue;
break;
default:
throw new ArgumentOutOfRangeException();
}
sceneToUnload.GetRootGameObjects()[0].name = $" (Unloading) {sceneToUnload.GetRootGameObjects()[0].name}";
AsyncOperation asyncOperation = SceneManager.UnloadSceneAsync(sceneToUnload);
if (asyncOperation != null)
{
asyncOperation.completed += OnOperationDone;
_asyncOperations.Add(asyncOperation);
}
//Debug.Log($" UnloadAsync {sceneToUnload.name} {_asyncOperations.Count}");
yield return null;
}
_scenesToUnload.Clear();
//Debug.Log("Unload finished " + _asyncOperations.Count);
_operationStarted = false;
}
private void CheckForColliderStreamer(SceneSplit sceneSplit)
{
ColliderStreamer[] colliderStreamers = sceneSplit.scene.GetRootGameObjects()[0].GetComponentsInChildren<ColliderStreamer>();
for (int i = 0; i < colliderStreamers.Length; i++)
{
ColliderStreamer colliderStreamer = colliderStreamers[i];
if (colliderStreamer.CurrentState != ColliderStreamer.State.Ready
&& colliderStreamer.CurrentState != ColliderStreamer.State.Unloaded)
colliderStreamer.UnloadScene();
}
}
public void UnloadSplitAsync(SceneSplit sceneSplit)
{
//Debug.LogWarning($" UnloadSceneAsync {sceneSplit.scene.name}");
_scenesToUnload.Add(new SceneToUnload() { SceneType = SceneType.SceneSplit, SceneSplit = sceneSplit });
}
public void UnloadSceneAsync(Scene scene)
{
//Debug.LogWarning($" UnloadSceneAsync {scene.name}");
_scenesToUnload.Add(new SceneToUnload() { SceneType = SceneType.Scene, Scene = scene });
}
public void UnloadColliderAsync(ColliderStreamer colliderStreamer)
{
_scenesToUnload.Add(new SceneToUnload() { SceneType = SceneType.Collider, ColliderStreamer = colliderStreamer });
}
public void LoadSceneAsync(SceneSplit split)
{
//Debug.Log($" LoadSceneAsync {split.sceneName} ");
_scenesToLoad.Add(new SceneToLoad() { SceneType = SceneType.SceneSplit, SceneSplit = split });
}
public void LoadSceneAsync(string sceneName)
{
//Debug.Log($" LoadSceneAsync sceneName {sceneName} ");
_scenesToLoad.Add(new SceneToLoad() { SceneType = SceneType.Scene, SceneName = sceneName });
}
public void LoadColliderAsync(ColliderStreamer colliderStreamer)
{
_scenesToLoad.Add(new SceneToLoad() { SceneType = SceneType.Collider, ColliderStreamer = colliderStreamer });
}
}
}