using UnityEngine; using asap.core; using UnityEngine.AddressableAssets; using System.Collections.Generic; using UniRx; using GameCore; using cfg; using game; using UnityEngine.ResourceManagement.AsyncOperations; using System.Linq; using System.Threading.Tasks; namespace Game { public struct ChangeRodDataEvent { public ChangeRodDataEvent(int rodId) { RodId = rodId; } public int RodId; } public interface IEventData { public SoundType audioType { set; get; } public string audioNameStr { set; get; } public float time { set; get; } } public class EventFishingSound : IEventData { public EventFishingSound(SoundType audioName, float time = 0, bool loop = false) { this.audioType = audioName; this.audioNameStr = audioName.ToString(); this.time = time; this.loop = loop; } public EventFishingSound(string audioName, float time = 0) { this.audioType = SoundType.Fishing; this.audioNameStr = audioName; this.time = time; } public Sound Sound { set; get; } public SoundType audioType { set; get; } public string audioNameStr { set; get; } public float time { set; get; } public bool loop { set; get; } public bool SkipPendingPlayback { set; get; } } public class EventUISound : IEventData { public EventUISound(SoundType audioName, float time = 0) { this.audioType = audioName; this.audioNameStr = audioName.ToString(); this.time = time; } public EventUISound(string audioName, float time = 0) { this.audioType = SoundType.UI; this.audioNameStr = audioName; this.time = time; } public Sound Sound { set; get; } public SoundType audioType { set; get; } public string audioNameStr { set; get; } public float time { set; get; } } public class EventRewardSound : IEventData { public EventRewardSound(SoundType audioName, float time = 0) { this.audioType = audioName; this.audioNameStr = audioName.ToString(); this.time = time; } public EventRewardSound(string audioName, float time = 0) { this.audioType = SoundType.UI; this.audioNameStr = audioName; this.time = time; } public Sound Sound { set; get; } public SoundType audioType { set; get; } public string audioNameStr { set; get; } public float time { set; get; } } public class EventBGMSound : IEventData { public EventBGMSound(string audioName, float time = 0) { this.audioType = SoundType.BGM; this.audioNameStr = audioName; this.time = time; } public SoundType audioType { set; get; } public string audioNameStr { set; get; } public float time { set; get; } } public class FadeOutEvent { public FadeOutEvent(Sound sound, float timer = 0.5f) { this.sound = sound; this.timer = timer; } public Sound sound { set; get; } public float timer { set; get; } } public struct SoundMuteEvent { public SoundMuteEvent(int muteType) { this.muteType = muteType; } public int muteType; } public class AssetReferenceAudioClip { public AssetReferenceAudioClip(AssetReferenceT assetReference, bool isOutDisable = false, SoundMainType mainType = SoundMainType.UI, float time = 0) { this.assetReference = assetReference; this.time = time; this.mainType = mainType; this.isOutDisable = isOutDisable; } public AssetReferenceT assetReference; public Sound Sound { set; get; } public float time { set; get; } public SoundMainType mainType { set; get; } public bool isOutDisable = false; } public class AssetReferenceAudioVoiceClip { public AssetReferenceAudioVoiceClip(AssetReferenceT assetReference) { this.assetReference = assetReference; } public AssetReferenceT assetReference; public Sound Sound { set; get; } } public class OnSoundStateEvent { public OnSoundStateEvent(int type) { this.type = type; } public int type; } public class SoundMgr { [Inject] public ISoundService soundService { set; get; } public Tables _tables { set; get; } string[] residentFish = { SoundType.audio_fishing_waiting.ToString(), SoundType.audio_fishing_waiting.ToString(), SoundType.audio_fishing_waiting_fishgathering.ToString(), "audio_fishing_drawing_hpevent_01", "audio_fishing_drawing_hpevent_02","audio_fishing_drawing_hpevent_03","audio_fishing_drawing_hpevent_04","audio_fishing_drawing_hpevent_05", SoundType.audio_fishing_welldone.ToString(), SoundType.audio_fishing_switchrod.ToString(), SoundType.audio_ui_targetcollect_collecting.ToString(), SoundType.audio_ui_targetcollect_fly.ToString(), "audio_fishing_pulling_fishflapping_01","audio_fishing_pulling_fishflapping_02","audio_fishing_pulling_fishflapping_03", SoundType.audio_ui_fishingmap_btn_levelup.ToString(), SoundType.audio_ui_fishingmap_fishpointfly.ToString(), SoundType.audio_fishing_dash.ToString(), SoundType.audio_fishing_fail_forcetoobig.ToString(), SoundType.audio_fishing_fail_forcetoosmall.ToString(), "audio_fishing_piercing01","audio_fishing_piercing02","audio_fishing_piercing03", }; Dictionary residentClip; Sound BGM_Sound; AudioClip BGM_Clip; RodSkinData rodData; OnSoundStateEvent onSoundState = new OnSoundStateEvent(0); string BGMName; Dictionary rewardSoundDic = new Dictionary(); readonly HashSet _activeFishingLoopSounds = new HashSet(); /// Reward 类音效全局节流:短间隔内只允许触发一次(与具体 clip 无关)。 const float RewardSoundThrottleSeconds = 0.2f; float _rewardSoundLastPlayRealtime = -1000f; bool TryConsumeRewardSoundThrottle() { float now = Time.realtimeSinceStartup; if (now - _rewardSoundLastPlayRealtime < RewardSoundThrottleSeconds) { return false; } _rewardSoundLastPlayRealtime = now; return true; } protected CompositeDisposable disposables; public async Task Init(System.Action progress) { //playerData = GContext.container.Resolve(); _tables = GContext.container.Resolve(); //var service = (SoundService)soundService; await soundService.InitAsync(); var opMap = new Dictionary>(); foreach (var addr in residentFish) { opMap[addr] = Addressables.LoadAssetAsync(addr); } var tasks = opMap.Values.Select(_ => _.Task); var total = (float)tasks.Count(); while (true) { var completed = tasks.Count(_ => _.IsCompleted); if (completed == total) { progress.Invoke(1f); break; } else { progress.Invoke(completed / total); } await Awaiters.NextFrame; } residentClip = opMap.ToDictionary(_ => _.Key, _ => _.Value.Result); disposables = new CompositeDisposable(); GContext.OnEvent().Subscribe(PlaySound).AddTo(disposables); GContext.OnEvent().Subscribe(PlayRewardSound).AddTo(disposables); GContext.OnEvent().Subscribe(PlayFishingSound).AddTo(disposables); GContext.OnEvent().Subscribe(PlayMusic).AddTo(disposables); GContext.OnEvent().Subscribe(FadeOutEvent).AddTo(disposables); GContext.OnEvent().Subscribe(PlaySoundByReference).AddTo(disposables); GContext.OnEvent().Subscribe(PlayVoiceSoundByReference).AddTo(disposables); GContext.OnEvent().Subscribe(OnChangeRodData).AddTo(disposables); GContext.OnEvent().Subscribe(OnSoundMute).AddTo(disposables); GContext.OnEvent().Subscribe(OnSoundStateEvent).AddTo(disposables); soundService.BGMVol = GContext.container.Resolve().Music ? 80 : 0; soundService.SFXVol = GContext.container.Resolve().Sound ? 80 : 0; soundService.VoiceVol = GContext.container.Resolve().Sound ? 80 : 0; } void OnSoundStateEvent(OnSoundStateEvent onSoundStateEvent) { onSoundState = onSoundStateEvent; SetSoundVolume(onSoundStateEvent.type); } void OnSoundMute(SoundMuteEvent soundMuteEvent) { if (soundMuteEvent.muteType == 0) { soundService.BGMVol = GContext.container.Resolve().Music ? 80 : 0; } else { soundService.VoiceVol = GContext.container.Resolve().Sound ? 80 : 0; soundService.SFXVol = GContext.container.Resolve().Sound ? 80 : 0; } } public async void OnChangeRodData(ChangeRodDataEvent changeRodDataEvent) { AudioClip audioClip; if (rodData != null) { if (residentClip.TryGetValue(rodData.ThrowingAudio, out audioClip)) { Addressables.Release(audioClip); residentClip.Remove(rodData.ThrowingAudio); } if (residentClip.TryGetValue(rodData.ReelingAudio, out audioClip)) { Addressables.Release(audioClip); residentClip.Remove(rodData.ReelingAudio); } if (residentClip.TryGetValue(rodData.LineAudio, out audioClip)) { Addressables.Release(audioClip); residentClip.Remove(rodData.LineAudio); } if (residentClip.TryGetValue(rodData.ComboOutAudio, out audioClip)) { Addressables.Release(audioClip); residentClip.Remove(rodData.ComboOutAudio); } if (residentClip.TryGetValue(rodData.ComboLoopAudio, out audioClip)) { Addressables.Release(audioClip); residentClip.Remove(rodData.ComboLoopAudio); } if (residentClip.TryGetValue(rodData.ComboIntoAudio, out audioClip)) { Addressables.Release(audioClip); residentClip.Remove(rodData.ComboIntoAudio); } } int skindID = GContext.container.Resolve().GetRodSkin(changeRodDataEvent.RodId); rodData = _tables.TbRodSkinData.GetOrDefault(skindID); audioClip = await Addressables.LoadAssetAsync(rodData.ThrowingAudio).Task; residentClip.Add(rodData.ThrowingAudio, audioClip); audioClip = await Addressables.LoadAssetAsync(rodData.ReelingAudio).Task; residentClip.Add(rodData.ReelingAudio, audioClip); audioClip = await Addressables.LoadAssetAsync(rodData.LineAudio).Task; residentClip.Add(rodData.LineAudio, audioClip); audioClip = await Addressables.LoadAssetAsync(rodData.ComboOutAudio).Task; residentClip.Add(rodData.ComboOutAudio, audioClip); audioClip = await Addressables.LoadAssetAsync(rodData.ComboLoopAudio).Task; residentClip.Add(rodData.ComboLoopAudio, audioClip); audioClip = await Addressables.LoadAssetAsync(rodData.ComboIntoAudio).Task; residentClip.Add(rodData.ComboIntoAudio, audioClip); } public async void PlaySoundByReference(AssetReferenceAudioClip eventSound) { string audioName = eventSound.assetReference.AssetGUID; if (!residentClip.TryGetValue(audioName, out var audioClip) || audioClip == null) { if (audioClip == null) { residentClip.Remove(audioName); } var audioClipL = await Addressables.LoadAssetAsync(eventSound.assetReference).Task;//.LoadAssetAsync().Task; if (disposables == null) { return; } if (residentClip.TryGetValue(audioName, out audioClip)) { Addressables.Release(audioClipL); } else { residentClip.Add(audioName, audioClipL); audioClip = audioClipL; } } if (audioClip == null) { soundService.ReturnSound(eventSound.Sound); eventSound.Sound = null; return; } SoundMainType soundMainType = eventSound.mainType; if (soundMainType == SoundMainType.Reward && !TryConsumeRewardSoundThrottle()) { return; } Sound sound; switch (soundMainType) { case SoundMainType.None: sound = null; break; case SoundMainType.BGM: await PlayBGM(audioClip, eventSound.time); residentClip.Remove(audioName); if (disposables == null) { return; } return; case SoundMainType.Fishing: sound = soundService.GetNewFishingSound(audioClip, time: eventSound.time); sound.soundMainType = SoundMainType.Fishing; break; case SoundMainType.Voice: SetSoundVolume(2); sound = soundService.GetNewVoiceSound(audioClip); sound.soundMainType = SoundMainType.Voice; break; case SoundMainType.UILoop: sound = soundService.GetNewUISound(audioClip, loop: true, time: eventSound.time); sound.soundMainType = SoundMainType.UI; break; //case SoundMainType.UI: default: sound = soundService.GetNewUISound(audioClip, time: eventSound.time); sound.soundMainType = soundMainType; break; } if (sound != null) { if (soundMainType == SoundMainType.Reward) { if (rewardSoundDic.TryGetValue(audioName, out Sound reward)) { if (reward.soundMainType == SoundMainType.Reward) { soundService.ReturnSound(reward); } } rewardSoundDic[audioName] = sound; } sound.audioSource.Play(); eventSound.Sound = sound; await Awaiters.Seconds(audioClip.length); if (eventSound.Sound.soundMainType == SoundMainType.Voice) { SetSoundVolume(onSoundState.type); } if (soundMainType == eventSound.Sound.soundMainType && !eventSound.isOutDisable) { soundService.ReturnSound(sound); eventSound.Sound = null; } } } async void PlayVoiceSoundByReference(AssetReferenceAudioVoiceClip eventSound) { var audioClip = await Addressables.LoadAssetAsync(eventSound.assetReference).Task; // eventSound.assetReference.LoadAssetAsync().Task; if (audioClip == null) { eventSound.Sound = null; return; } SetSoundVolume(2); var sound = soundService.GetNewVoiceSound(audioClip); sound.soundMainType = SoundMainType.Voice; sound.audioSource.Play(); eventSound.Sound = sound; await Awaiters.Seconds(audioClip.length); if (eventSound.Sound.soundMainType == SoundMainType.Voice) { SetSoundVolume(onSoundState.type); soundService.ReturnSound(sound); } Addressables.Release(audioClip); eventSound.Sound = null; } /// /// 0默认 type==1 钓鱼 type==2 人声 /// /// void SetSoundVolume(int type) { if (GContext.container.Resolve().Music) { soundService.BGMVol = type == 0 ? 80 : 72; } if (GContext.container.Resolve().Sound) { soundService.SFXVol = type == 2 ? 70 : 80; } } public async void PlaySound(EventUISound eventSound) { string audioName = GetAudioName(eventSound); if (!residentClip.TryGetValue(audioName, out var audioClip)) { var audioClipL = await Addressables.LoadAssetAsync(audioName).Task; if (residentClip.TryGetValue(audioName, out audioClip)) { Addressables.Release(audioClipL); } else { residentClip.Add(audioName, audioClipL); audioClip = audioClipL; } } if (audioClip == null) { eventSound.Sound = null; return; } var sound = soundService.GetNewUISound(audioClip, time: eventSound.time); sound.soundMainType = SoundMainType.UI; sound.audioSource.Play(); eventSound.Sound = sound; await Awaiters.Seconds(audioClip.length); if (SoundMainType.UI == eventSound.Sound.soundMainType) { soundService.ReturnSound(sound); } eventSound.Sound = null; } public async void PlayRewardSound(EventRewardSound eventSound) { string audioName = GetAudioName(eventSound); if (!residentClip.TryGetValue(audioName, out var audioClip)) { var audioClipL = await Addressables.LoadAssetAsync(audioName).Task; if (residentClip.TryGetValue(audioName, out audioClip)) { Addressables.Release(audioClipL); } else { residentClip.Add(audioName, audioClipL); audioClip = audioClipL; } } if (audioClip == null) { eventSound.Sound = null; return; } if (!TryConsumeRewardSoundThrottle()) { eventSound.Sound = null; return; } SoundMainType soundMainType = SoundMainType.Reward; Sound sound = soundService.GetNewUISound(audioClip, time: eventSound.time); sound.soundMainType = soundMainType; if (rewardSoundDic.TryGetValue(audioName, out Sound reward)) { if (reward.soundMainType == SoundMainType.Reward) { soundService.ReturnSound(reward); } } rewardSoundDic[audioName] = sound; sound.audioSource.Play(); eventSound.Sound = sound; await Awaiters.Seconds(audioClip.length); if (SoundMainType.Reward == eventSound.Sound.soundMainType) { soundService.ReturnSound(sound); } eventSound.Sound = null; } public async void PlayFishingSound(EventFishingSound eventSound) { string audioName = GetAudioName(eventSound); if (!residentClip.TryGetValue(audioName, out var audioClip)) { var audioClipL = await Addressables.LoadAssetAsync(audioName).Task; if (residentClip.TryGetValue(audioName, out audioClip)) { Addressables.Release(audioClipL); } else { residentClip.Add(audioName, audioClipL); audioClip = audioClipL; } } if (audioClip == null) { eventSound.Sound = null; return; } if (eventSound.SkipPendingPlayback) { eventSound.Sound = null; return; } bool isLoop = eventSound.loop; //if (eventSound.audioType == SoundType.LineAudioReeling || eventSound.audioType == SoundType.ReelingAudioReeling) //{ // isLoop = true; //} var sound = soundService.GetNewFishingSound(audioClip, loop: isLoop, time: eventSound.time); sound.soundMainType = SoundMainType.Fishing; sound.audioSource.Play(); eventSound.Sound = sound; if (isLoop) { _activeFishingLoopSounds.Add(sound); } if (!isLoop) { await Awaiters.Seconds(audioClip.length); if (eventSound.Sound != null && SoundMainType.Fishing == eventSound.Sound.soundMainType) { soundService.ReturnSound(sound); } eventSound.Sound = null; } } public void StopActiveFishingLoopSounds(float fadeSeconds = 0.35f) { var copy = _activeFishingLoopSounds.ToList(); foreach (var s in copy) { if (s != null) { FadeOutAsync(s, fadeSeconds); } } } public async Task PlayFishingSound(string audioName) { if (!residentClip.TryGetValue(audioName, out var audioClip)) { var audioClipL = await Addressables.LoadAssetAsync(audioName).Task; if (residentClip.TryGetValue(audioName, out audioClip)) { Addressables.Release(audioClipL); } else { residentClip.Add(audioName, audioClipL); audioClip = audioClipL; } } if (audioClip == null) { return; } var sound = soundService.GetNewFishingSound(audioClip); sound.soundMainType = SoundMainType.Fishing; sound.audioSource.Play(); await Awaiters.Seconds(audioClip.length); soundService.ReturnSound(sound); } public async void PlayMusic(EventBGMSound eventSound) { string audioName = GetAudioName(eventSound); if (BGMName == audioName) { return; } var audioClip = await Addressables.LoadAssetAsync(audioName).Task; if (BGMName == audioName) { Addressables.Release(audioClip); return; } await PlayBGM(audioClip, eventSound.time); } async Task PlayBGM(AudioClip audioClip, float time = 0) { if (audioClip == null) { return; } BGMName = audioClip.name; if (BGM_Clip != null) { AudioClip audioClip1 = BGM_Clip; BGM_Clip = null; Sound bgm_Sound = BGM_Sound; BGM_Sound = null; soundService.FadeOut(bgm_Sound, 0.5f); await Task.Delay(500); Addressables.Release(audioClip1); soundService.ReturnSound(bgm_Sound); } if (BGMName != audioClip.name) { return; } BGM_Sound = soundService.GetNewBgmSound(audioClip, time: time); BGM_Sound.soundMainType = SoundMainType.BGM; BGM_Clip = audioClip; BGM_Sound.audioSource.Play(); soundService.FadeIn(BGM_Sound, 0.5f); } public void SetBGM(AudioClip audioClip) { if (audioClip == BGM_Clip) return; if (BGM_Sound == null) { BGM_Sound = soundService.GetNewBgmSound(audioClip); } BGM_Sound.audioSource.clip = audioClip; BGM_Sound.soundMainType = SoundMainType.BGM; BGM_Clip = audioClip; BGM_Sound.audioSource.Play(); } void FadeOutEvent(FadeOutEvent fadeOutEvent) { FadeOutAsync(fadeOutEvent.sound, fadeOutEvent.timer); fadeOutEvent.sound = null; } async void FadeOutAsync(Sound sound, float timer = 0.5f) { if (sound == null) { return; } try { _activeFishingLoopSounds.Remove(sound); if (sound.soundMainType == SoundMainType.Voice) { SetSoundVolume(onSoundState.type); } if (sound.soundMainType == SoundMainType.BGM) { return; } soundService.FadeOut(sound, timer); await Task.Delay((int)(timer * 1000)); if (sound.soundMainType != SoundMainType.None) { soundService.ReturnSound(sound); } } catch (System.Exception e) { Debug.LogError(e); soundService.ReturnSound(sound); } } string GetAudioName(IEventData eventData) { PlayerData playerData = GContext.container.Resolve(); PlayerFishData playerFishData = GContext.container.Resolve(); int skindID = playerFishData.GetRodSkin(playerData.equipRodID); RodSkinData rodSkinData = _tables.TbRodSkinData.GetOrDefault(skindID); switch (eventData.audioType) { case SoundType.ThrowingAudio: return rodSkinData.ThrowingAudio; case SoundType.ReelingAudio: case SoundType.ReelingAudioReeling: return rodSkinData.ReelingAudio; case SoundType.LineAudioReeling: return rodSkinData.LineAudio; case SoundType.ComboOutAudio: return rodSkinData.ComboOutAudio; case SoundType.ComboLoopAudio: return rodSkinData.ComboLoopAudio; case SoundType.ComboIntoAudio: return rodSkinData.ComboIntoAudio; case SoundType.HPEvent: return "audio_fishing_drawing_hpevent_0" + Random.Range(1, 6); case SoundType.audio_fishing_piercing: return "audio_fishing_piercing0" + Random.Range(1, 4); case SoundType.audio_fishing_jumpout: return "audio_fishing_jumpout_0" + Random.Range(1, 4); case SoundType.audio_fishing_jumpinto: return "audio_fishing_jumpinto_0" + Random.Range(1, 4); case SoundType.BGM: case SoundType.Fishing: case SoundType.UI: default: return eventData.audioNameStr; } } public void Release() { if (disposables != null) { disposables.Dispose(); disposables = null; } if (residentClip != null) { foreach (var item in residentClip) { if (item.Value != null) { Addressables.Release(item.Value); } } residentClip.Clear(); } if (rewardSoundDic != null) { rewardSoundDic.Clear(); } if (soundService != null) { foreach (var s in _activeFishingLoopSounds.ToList()) { if (s != null) { s.audioSource.Stop(); soundService.ReturnSound(s); } } } _activeFishingLoopSounds.Clear(); if (soundService != null) { soundService.Release(); } if (BGM_Clip != null) { Addressables.Release(BGM_Clip); BGM_Clip = null; } if (BGM_Sound != null && BGM_Sound.gameObject != null) { GameObject.Destroy(BGM_Sound.gameObject); BGM_Sound = null; } BGMName = null; } } }