177 lines
7.6 KiB
C#
177 lines
7.6 KiB
C#
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;
|
||
}
|
||
|
||
|
||
}
|