Files
bansonic_beta_main/Assets/scripts/Audio/BgmRuntimeBootstrap.cs
T

206 lines
6.9 KiB
C#

using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;
public static class BgmRuntimeBootstrap
{
private const string RuntimeAudioListenerName = "__RuntimeAudioListener";
private static readonly List<Transform> _transformBuffer = new List<Transform>(512);
private static readonly List<Transform> _transformStack = new List<Transform>(512);
[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.AfterSceneLoad)]
private static void Bootstrap()
{
var mgr = BgmPlaybackManager.EnsureInstance();
var controller = SceneObjectLookupCache.FindAny<btmandtopController>();
if (controller != null && controller.bgmMixerGroup != null)
{
mgr.SetOutputMixerGroup(controller.bgmMixerGroup);
}
mgr.EnsurePlaying();
EnsureAudioListener(SceneManager.GetActiveScene());
// Ensure UI binder exists
if (SceneObjectLookupCache.FindAny<BgmUiBinder>() == null)
{
var go = new GameObject("BGM_UI_Binder");
go.AddComponent<BgmUiBinder>();
Object.DontDestroyOnLoad(go);
}
RemoveBgmParticlesInLoadedScenes();
SceneManager.sceneLoaded -= OnSceneLoaded;
SceneManager.sceneLoaded += OnSceneLoaded;
}
private static void OnSceneLoaded(Scene scene, LoadSceneMode mode)
{
EnsureAudioListener(scene);
var mgr = BgmPlaybackManager.Instance ?? BgmPlaybackManager.EnsureInstance();
mgr.EnsurePlaying();
RemoveBgmParticlesInLoadedScenes();
}
private static void RemoveBgmParticlesInLoadedScenes()
{
int sceneCount = SceneManager.sceneCount;
for (int i = 0; i < sceneCount; i++)
{
var scene = SceneManager.GetSceneAt(i);
if (!scene.IsValid() || !scene.isLoaded) continue;
RemoveBgmParticlesInScene(scene);
}
}
private static void RemoveBgmParticlesInScene(Scene scene)
{
var emitters = Object.FindObjectsByType<BgmParticleEmitter>(FindObjectsInactive.Include, FindObjectsSortMode.None);
for (int i = 0; i < emitters.Length; i++)
{
var e = emitters[i];
if (e == null) continue;
if (!e.gameObject.scene.IsValid() || !e.gameObject.scene.isLoaded) continue;
Object.Destroy(e.gameObject);
}
CollectTransformsInScene(scene, _transformBuffer);
for (int i = 0; i < _transformBuffer.Count; i++)
{
var t = _transformBuffer[i];
if (t == null || t.gameObject.scene != scene) continue;
if (t.name.Equals("BgmParticles", System.StringComparison.OrdinalIgnoreCase))
Object.Destroy(t.gameObject);
}
}
private static void EnsureAudioListener(Scene scene)
{
if (!scene.IsValid() || !scene.isLoaded)
return;
AudioListener[] allListeners = Object.FindObjectsByType<AudioListener>(FindObjectsInactive.Include, FindObjectsSortMode.None);
AudioListener activeEnabledInScene = null;
AudioListener activeInScene = null;
AudioListener anyInScene = null;
for (int i = 0; i < allListeners.Length; i++)
{
AudioListener listener = allListeners[i];
if (listener == null)
continue;
if (!listener.gameObject.scene.IsValid() || listener.gameObject.scene != scene)
continue;
if (anyInScene == null)
anyInScene = listener;
if (listener.gameObject.activeInHierarchy && activeInScene == null)
activeInScene = listener;
if (listener.gameObject.activeInHierarchy && listener.enabled)
{
activeEnabledInScene = listener;
break;
}
}
if (activeEnabledInScene != null)
return;
if (activeInScene != null)
{
activeInScene.enabled = true;
return;
}
if (anyInScene != null)
{
anyInScene.enabled = true;
return;
}
Camera cameraInScene = FindBestCameraInScene(scene);
if (cameraInScene != null)
{
AudioListener cameraListener = cameraInScene.GetComponent<AudioListener>();
if (cameraListener == null)
cameraListener = cameraInScene.gameObject.AddComponent<AudioListener>();
cameraListener.enabled = true;
return;
}
GameObject listenerRoot = FindNamedObjectInScene(scene, RuntimeAudioListenerName);
if (listenerRoot == null)
{
listenerRoot = new GameObject(RuntimeAudioListenerName);
try { SceneManager.MoveGameObjectToScene(listenerRoot, scene); } catch { }
}
if (listenerRoot.GetComponent<AudioListener>() == null)
listenerRoot.AddComponent<AudioListener>();
}
private static Camera FindBestCameraInScene(Scene scene)
{
Camera[] cameras = Object.FindObjectsByType<Camera>(FindObjectsInactive.Include, FindObjectsSortMode.None);
Camera first = null;
for (int i = 0; i < cameras.Length; i++)
{
Camera cam = cameras[i];
if (cam == null || cam.gameObject.scene != scene)
continue;
if (first == null)
first = cam;
if (cam.gameObject.activeInHierarchy && cam.enabled && cam.CompareTag("MainCamera"))
return cam;
}
if (first != null)
return first;
return null;
}
private static GameObject FindNamedObjectInScene(Scene scene, string objectName)
{
if (string.IsNullOrEmpty(objectName))
return null;
CollectTransformsInScene(scene, _transformBuffer);
for (int i = 0; i < _transformBuffer.Count; i++)
{
var t = _transformBuffer[i];
if (t == null || t.gameObject.scene != scene) continue;
if (string.Equals(t.name, objectName, System.StringComparison.OrdinalIgnoreCase)) return t.gameObject;
}
return null;
}
private static void CollectTransformsInScene(Scene scene, List<Transform> buffer)
{
buffer.Clear();
_transformStack.Clear();
var roots = scene.GetRootGameObjects();
for (int i = 0; i < roots.Length; i++)
{
var root = roots[i];
if (root == null) continue;
_transformStack.Add(root.transform);
while (_transformStack.Count > 0)
{
int last = _transformStack.Count - 1;
var t = _transformStack[last];
_transformStack.RemoveAt(last);
if (t == null) continue;
buffer.Add(t);
int childCount = t.childCount;
for (int c = 0; c < childCount; c++)
{
_transformStack.Add(t.GetChild(c));
}
}
}
}
}