Files
5.24BuYu/Assets/MyGame/Scripts/fishResources/AudioResourcesData.cs
T
2026-10-15 03:57:20 +08:00

177 lines
7.6 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
using Newtonsoft.Json;
using Spine.Unity;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Threading.Tasks;
using UnityEngine;
using UnityEngine.AddressableAssets;
using UnityEngine.InputSystem;
using UnityEngine.ResourceManagement.AsyncOperations;
using static UnityEngine.AddressableAssets.Addressables;
[Serializable]
public class AudioResourcesData
{
public int audioID;
public string audioResourcesPath;
// ⭐ 音效字典存放在框架层 AudioManager(框架层不反向依赖 AudioResourcesData):
// AudioManager.NameToIdDic = 资源名→ID,AudioManager.ClipDic = ID→AudioClip
static Dictionary<int, AudioClip> audioClipDefaultDic=new Dictionary<int, AudioClip>();
static Dictionary<int, AudioClip> audioClipGameDic=new Dictionary<int, AudioClip>();
const string Audio_AALabel="Audio";
// ⭐ 句柄显式管理(修复"包只增不减"的根源):
// 之前 Load 的句柄直接丢弃(泄漏,包永不卸载),UnLoad 再重新 Load 一遍拿句柄释放
// (净引用数 0,等于什么都没卸载)。现在:加载时保存句柄,卸载时真正 Release。
// 注意:游戏音频物理上打在鱼包里(Audio+玩法 交集 = 鱼包),释放本句柄是鱼包能卸载的前提之一。
/// <summary>默认音频句柄(Audio+Default,进程常驻,不卸载)</summary>
static AsyncOperationHandle<IList<AudioClip>> _defaultAudioHandle;
/// <summary>当前玩法游戏音频句柄(Audio+玩法,进房加载/离房释放)</summary>
static AsyncOperationHandle<IList<AudioClip>> _gameAudioHandle;
static AudioResourcesData()
{
//默认音效(背景音乐、按钮点击 PW_Button 等)放在 Audio+Default 标签集合里,随启动常驻加载
LoadDefaultAudioGame();
}
static async void LoadDefaultAudioGame()
{
string prefabFishPath = Resources.Load<TextAsset>("tbaudio").text;
var v = JsonConvert.DeserializeObject<List<AudioResourcesData>>(prefabFishPath);
foreach (var item in v)
{
Debug.Log("加载文件音频ID: " + item.audioID);
Debug.Log(item.audioID + "加载文件音频路径: " + item.audioResourcesPath);
AudioManager.NameToIdDic[item.audioResourcesPath]=item.audioID;
}
var keys = new List<string> { Audio_AALabel, "Default" };
_defaultAudioHandle = Addressables.LoadAssetsAsync<AudioClip>(keys, audio =>
{
Debug.Log("加载音频: " + audio.name);
if (AudioManager.NameToIdDic.ContainsKey(audio.name))
{
Debug.Log("加载音频ID: " + AudioManager.NameToIdDic[audio.name]);
audioClipDefaultDic.Add(AudioManager.NameToIdDic[audio.name],audio);
}
}, MergeMode.Intersection);
await _defaultAudioHandle.Task;
foreach (var item in audioClipDefaultDic)
{
AudioManager.ClipDic.Add(item.Key, item.Value);
}
Debug.Log("加载了:"+ AudioManager.ClipDic.Count);
}
//public static async Task LoadAudioGame()
//{
// GameType gameType=GameManager.Instance.gameData.currGameType;
// var keys = new List<string> { Audio_AALabel, gameType.ToString() };
// await Addressables.LoadAssetsAsync<AudioClip>(keys, audio =>
// {
// //Debug.Log("加载音频: " + audio.name);
// //Debug.Log("加载音频ID: " + name_IDDic[audio.name]);
// if (name_IDDic.ContainsKey(audio.name))
// {
// audioClipGameDic[name_IDDic[audio.name]]= audio;
// }
// }, MergeMode.Intersection).Task;
// audioClipDic=new Dictionary<int, AudioClip>(audioClipDefaultDic);
// foreach (var item in audioClipGameDic)
// {
// audioClipDic[item.Key]=item.Value;
// }
// Debug.Log("加载了:"+ audioClipDic.Count);
//}
/// <summary>
/// 加载当前玩法游戏音频(Audio+玩法 交集)。
/// onProgress:进度回调 0~1(按 LoadAssetsAsync 的 PercentComplete),供进房进度条使用;不传则行为不变。
/// </summary>
public static async Task LoadAudioGame(Action<float> onProgress = null)
{
// ⭐ 资源加载超过 0.1 秒才显示"加载中"界面(引用计数,快速加载不显示)
UIManager.BeginLoading();
try { await LoadAudioGameCore(onProgress); }
finally { UIManager.EndLoading(); }
}
/// <summary>LoadAudioGame 的实际逻辑(外层负责"加载中"界面)</summary>
private static async Task LoadAudioGameCore(Action<float> onProgress)
{
GameType gameType = GameManager.Instance.gameData.currGameType;
var keys = new List<string> { Audio_AALabel, gameType.ToString() };
try
{
// ⭐ 防御:上一轮句柄未释放(如离房被跳过)时先释放,避免引用计数累加
if (_gameAudioHandle.IsValid())
Addressables.Release(_gameAudioHandle);
// ⭐ 双标签交集(Audio + 当前玩法):只加载当前玩法标记的音频。
// Union 会按 "Audio" 标签把其它玩法的音频包一并打开,
// 而这些音频物理上和鱼的 Prefab 打在同一个 LZMA 包里 → 整包解压进内存导致 iOS 被杀
// 句柄保存到 _gameAudioHandle,离房时 UnLoadAudioGame 真正释放 → 鱼包才能卸载
_gameAudioHandle = Addressables.LoadAssetsAsync<AudioClip>(keys, audio =>
{
if (AudioManager.NameToIdDic != null && AudioManager.NameToIdDic.ContainsKey(audio.name))
{
audioClipGameDic[AudioManager.NameToIdDic[audio.name]] = audio;
}
}, MergeMode.Intersection);
// 50ms 轮询上报进度(无回调时直接等完成)
if (onProgress != null)
{
while (!_gameAudioHandle.IsDone)
{
onProgress(_gameAudioHandle.PercentComplete);
await Task.Delay(50);
}
onProgress(1f);
}
else
{
await _gameAudioHandle.Task;
}
AudioManager.ClipDic = new Dictionary<int, AudioClip>();
if (audioClipDefaultDic != null)
{
foreach (var item in audioClipDefaultDic)
AudioManager.ClipDic[item.Key] = item.Value;
}
foreach (var item in audioClipGameDic)
{
AudioManager.ClipDic[item.Key] = item.Value;
}
Debug.Log("加载音频数量: " + AudioManager.ClipDic.Count);
}
catch (Exception e)
{
onProgress?.Invoke(1f);
Debug.LogError($"加载游戏音频失败: {e.Message}");
}
}
public static Task UnLoadAudioGame()
{
// ⭐ 真正的卸载:释放加载时保存的句柄(引用归零后 Audio+玩法 命中的 bundle 才会真正卸载)。
// 旧实现"重新 Load 一遍拿句柄再 Release"是净 0 操作,什么都卸不掉。
if (_gameAudioHandle.IsValid())
Addressables.Release(_gameAudioHandle);
// 清空游戏音频字典(包卸载后 AudioClip 对象已失效,残留引用会导致播放 null)
audioClipGameDic.Clear();
// 重建总字典:只保留默认音频
AudioManager.ClipDic = new Dictionary<int, AudioClip>(audioClipDefaultDic);
Debug.Log("卸载完成,当前音频数量:" + AudioManager.ClipDic.Count);
return Task.CompletedTask;
}
}