using System.Collections.Generic; using System.Threading.Tasks; using Audio; using Framework.Asset; using UnityEngine; using YooAsset; using AudioType = Framework.Audio.AudioType; namespace System.AudioHandler { /// /// 单独分离的音频资源加载器,方便后续升级资源加载策略 /// public class AudioSourceHandler : IAudioSourceHandler { private static readonly Dictionary _AUDIO_PATH = new Dictionary() { {AudioType.BGM, "BGM"}, {AudioType.BSE, "BSE"}, {AudioType.SOUND, "SE"} }; private readonly string _rootPath; private Dictionary _audioSource; private Dictionary _audioReferenceCount; private List _audioPaths; //用于编辑器状态下监视资源状态 public Dictionary editorLog; public Dictionary EditorLog() => this.editorLog; private string AudioFullPath(AudioType audioType, string audioName) { audioName = audioName.Replace("\\", "/"); return $"{this._rootPath}/{_AUDIO_PATH[audioType]}/{audioName}"; } public AudioSourceHandler(string rootPath) { this._rootPath = rootPath; this._audioReferenceCount = new Dictionary(); this._audioSource = new Dictionary(); this._audioPaths = new List(AssetManager.Instance.GetResourceLocation(this._rootPath)); #if UNITY_EDITOR this.editorLog = new Dictionary(); #endif } public bool IsAsync() { return false; } /// /// 异步加载音频资源 /// /// /// /// public async Task GetAudioClipAsync(AudioType audioType, string audioName) { var audioKey = audioType + audioName; //当指定音效没有或者其资源为null时,通过ab包加载 if (!this._audioSource.ContainsKey(audioKey) || this._audioSource[audioKey] == null) { var fullpath = AudioFullPath((AudioType) audioType, audioName); var path = GetAudioPath(fullpath); if (path == null) { return null; } if (!AssetManager.Instance.CheckLocationValid (path , false)) { #if UNITY_EDITOR Debug.Log ("【AudioManager】无效的音频资源路径:" + path); #endif return null; } var audioAsset = AssetManager.Instance.LoadAssetRequestAsync(path , false); await audioAsset.Task; this._audioSource[audioKey] = new AudioAsset(audioAsset , audioKey); this._audioReferenceCount[audioKey] = 0; } var audioClip = this._audioSource[audioKey].Clip; this._audioReferenceCount[audioKey] += audioClip != null ? 1 : 0; #if UNITY_EDITOR RefreshLog(); #endif return audioClip; } public string GetAudioPath(string pullPath) { pullPath += "."; foreach (var audioPath in this._audioPaths) { if (audioPath.IndexOf(pullPath, StringComparison.Ordinal) == 0) { return audioPath; } } return null; } /// /// 获取一个音频资源 /// /// /// /// public AudioClip GetAudioClip(AudioType audioType, string audioName) { var audioKey = audioType + audioName; //当指定音效没有或者其资源为null时,通过ab包加载 if (!this._audioSource.ContainsKey(audioKey) || this._audioSource[audioKey] == null) { var fullpath = AudioFullPath((AudioType) audioType, audioName); var path = GetAudioPath(fullpath); if (path == null) { return null; } if (!AssetManager.Instance.CheckLocationValid (path , false)) { // #if UNITY_EDITOR // Debug.Log ("【AudioManager】无效的音频资源路径:" + path); // #endif Debug.Log ("【AudioManager】无效的音频资源路径:" + path); return null; } var audioAsset = AssetManager.Instance.LoadAssetRequest(path , false); this._audioSource[audioKey] = new AudioAsset(audioAsset , audioKey); this._audioReferenceCount[audioKey] = 0; } var audioClip = this._audioSource[audioKey].Clip; this._audioReferenceCount[audioKey] += audioClip != null ? 1 : 0; #if UNITY_EDITOR RefreshLog(); #endif return audioClip; } public void OnAudioInvalid(AudioType audioType, string audioName) { var audioKey = audioType + audioName; if (this._audioReferenceCount.ContainsKey(audioKey) && this._audioReferenceCount[audioKey] >= 1) { this._audioReferenceCount[audioKey] -= 1; if (this._audioReferenceCount[audioKey] == 0) { if (audioType == AudioType.BGM || audioType == AudioType.BSE) { var audioAsset = this._audioSource[audioKey]; this._audioSource[audioKey] = null; audioAsset.KillAsset(); } #if UNITY_EDITOR RefreshLog(); #endif } } } /// /// 卸载所有未使用的音效资源 /// public void UnLoadAllInvalid() { List sourceKeys = new List(this._audioSource.Keys); for (int i = sourceKeys.Count - 1; i >= 0; i--) { var audioSourceKey = sourceKeys[i]; if (this._audioReferenceCount[audioSourceKey] == 0) { // ushort group = ushort.Parse(audioSourceKey.Substring(0, 1)); // string audioName = audioSourceKey.Substring(1); var audioAsset = this._audioSource[audioSourceKey]; audioAsset.KillAsset(); this._audioSource.Remove(audioSourceKey); this._audioReferenceCount.Remove(audioSourceKey); #if UNITY_EDITOR this.editorLog.Remove(audioSourceKey); #endif } } #if UNITY_EDITOR RefreshLog(); #endif } public void RefreshLog() { #if UNITY_EDITOR foreach (var audioSourceKey in this._audioSource.Keys) { this.editorLog[audioSourceKey] = $"\t{this._audioSource[audioSourceKey] != null} \t{this._audioReferenceCount[audioSourceKey]}"; } #endif } public float[] LoadVolume() { var volumes = new float[3] {1, 1, 1}; volumes[0] = Account.Instance.AccountSystemData.BGMValue; volumes[1] = Account.Instance.AccountSystemData.BSEValue; volumes[2] = Account.Instance.AccountSystemData.SEValue; return volumes; } public void SaveVolume(float bgm, float bse, float se) { Account.Instance.AccountSystemData.BGMValue = bgm; Account.Instance.AccountSystemData.BSEValue = bse; Account.Instance.AccountSystemData.SEValue = se; Account.Instance.Save(Framework.Save.SaveData.System); } } public class AudioAsset { private AudioClip _clip; private AssetHandle _assetRequest; private string _key; public AudioAsset(AssetHandle assetRequest, string key) { this._assetRequest = assetRequest; this._key = key; if (assetRequest == null || assetRequest.AssetObject == null) { Debug.Log("Error Audio Path : " + key + " path: " + assetRequest?.GetAssetInfo ().AssetPath); return; } this._clip = assetRequest.AssetObject as AudioClip; } public void KillAsset() { this._clip = null; this._assetRequest.Release(); } public string Key => this._key; public AudioClip Clip => this._clip; } }