116 lines
3.4 KiB
C#
116 lines
3.4 KiB
C#
using System;
|
|
using System.Collections;
|
|
using System.Collections.Generic;
|
|
using UnityEngine;
|
|
using UnityEngine.SceneManagement;
|
|
|
|
namespace AibisDream
|
|
{
|
|
public sealed class SceneReadinessResult
|
|
{
|
|
public bool Success { get; internal set; }
|
|
public bool Cancelled { get; internal set; }
|
|
public string Error { get; internal set; }
|
|
}
|
|
|
|
public static class SceneReadiness
|
|
{
|
|
public const float DefaultTimeoutSeconds = 15f;
|
|
|
|
public static IEnumerator WaitUntilReady(
|
|
Scene scene,
|
|
Func<bool> isCancellationRequested,
|
|
Action<SceneReadinessResult> completed,
|
|
float timeoutSeconds = DefaultTimeoutSeconds)
|
|
{
|
|
var result = new SceneReadinessResult();
|
|
|
|
// 等待场景内 Awake/Start 完成,再收集当前场景自己的 Gate。
|
|
yield return null;
|
|
|
|
if (isCancellationRequested?.Invoke() == true)
|
|
{
|
|
result.Cancelled = true;
|
|
result.Error = "Scene readiness was cancelled.";
|
|
completed?.Invoke(result);
|
|
yield break;
|
|
}
|
|
|
|
if (!scene.IsValid() || !scene.isLoaded)
|
|
{
|
|
result.Error = "Loaded scene is invalid or not loaded.";
|
|
completed?.Invoke(result);
|
|
yield break;
|
|
}
|
|
|
|
var gates = CollectGates(scene);
|
|
if (gates.Count == 0)
|
|
{
|
|
result.Success = true;
|
|
completed?.Invoke(result);
|
|
yield break;
|
|
}
|
|
|
|
var deadline = Time.unscaledTime + Mathf.Max(0f, timeoutSeconds);
|
|
while (true)
|
|
{
|
|
if (isCancellationRequested?.Invoke() == true)
|
|
{
|
|
result.Cancelled = true;
|
|
result.Error = "Scene readiness was cancelled.";
|
|
break;
|
|
}
|
|
|
|
var allReady = true;
|
|
foreach (var gate in gates)
|
|
{
|
|
if (gate is UnityEngine.Object unityObject && unityObject == null)
|
|
{
|
|
result.Error = "A scene dialogue gate was destroyed while waiting.";
|
|
completed?.Invoke(result);
|
|
yield break;
|
|
}
|
|
|
|
if (!gate.IsDialogueReady)
|
|
{
|
|
allReady = false;
|
|
}
|
|
}
|
|
|
|
if (allReady)
|
|
{
|
|
result.Success = true;
|
|
break;
|
|
}
|
|
|
|
if (Time.unscaledTime >= deadline)
|
|
{
|
|
result.Error = $"Scene readiness timed out after {timeoutSeconds:0.#} seconds.";
|
|
break;
|
|
}
|
|
|
|
yield return null;
|
|
}
|
|
|
|
completed?.Invoke(result);
|
|
}
|
|
|
|
private static List<ISceneDialogueGate> CollectGates(Scene scene)
|
|
{
|
|
var gates = new List<ISceneDialogueGate>();
|
|
foreach (var root in scene.GetRootGameObjects())
|
|
{
|
|
foreach (var behaviour in root.GetComponentsInChildren<MonoBehaviour>(true))
|
|
{
|
|
if (behaviour is ISceneDialogueGate gate)
|
|
{
|
|
gates.Add(gate);
|
|
}
|
|
}
|
|
}
|
|
|
|
return gates;
|
|
}
|
|
}
|
|
}
|