using System; using System.Collections.Generic; using System.Linq; using System.Threading; using Code.Infrastructure.Configs; using Code.Infrastructure.EventBus; using Cysharp.Threading.Tasks; using UnityEngine; using UnityEngine.AddressableAssets; using UnityEngine.Audio; using UnityEngine.Pool; using UnityEngine.ResourceManagement.AsyncOperations; using Object = UnityEngine.Object; namespace Code.Infrastructure.Audio { public interface IAudioSourcePool { AudioSource GetSource(AudioSourceType sourceType); void ReleaseSource(AudioSource source); } public class AudioSourcePool : IAudioSourcePool, IDisposable { // The pool holds plain GameObjects (you can swap this for any component type). private IObjectPool _pool; private GameObject _sourcePrefab; private Dictionary _settings; public AudioSourcePool(Dictionary settings) => _settings = settings; private string _configsLabel; private AsyncOperationHandle> _handles; private AssetReference _sourcePrefabConfigReference; private AsyncOperationHandle _prefabConfigHandle; private AsyncOperationHandle _prefabHandle; private EventBus.EventBus _eventBus; public AudioSourcePool(IConfigLocator configLocator, EventBus.EventBus eventBus) { _eventBus = eventBus; _configsLabel = configLocator.TryGetManyConfigAssetReferences(); _sourcePrefabConfigReference = configLocator.TryGetConfigAssetReference(); LoadConfigs().Forget(); } private async UniTaskVoid LoadConfigs() { _prefabConfigHandle = Addressables.LoadAssetAsync(_sourcePrefabConfigReference); _handles = Addressables.LoadAssetsAsync(_configsLabel); await UniTask.WhenAll( _prefabConfigHandle.ToUniTask(), _handles.ToUniTask()); _prefabHandle = Addressables.LoadAssetAsync(_prefabConfigHandle.Result.sourcePrefab); _settings = _handles.Result.ToDictionary(x => x.sourceType); await _prefabHandle.ToUniTask(); _pool = new ObjectPool( createFunc: CreateItem, // actionOnGet: OnGet, actionOnRelease: OnRelease, actionOnDestroy: OnDestroyItem, collectionCheck: true, // helps catch double-release mistakes defaultCapacity: 10, maxSize: 20 ); _eventBus.RaiseEvent(x => x.AudioSourcePoolInitialized()); } // Creates a new pooled GameObject the first time (and whenever the pool needs more). private AudioSource CreateItem() { var audioSource = Object.Instantiate(_prefabHandle.Result).GetComponent(); audioSource.name = "PooledAudioSource"; Object.DontDestroyOnLoad(audioSource); return audioSource; } // Called when an item is taken from the pool. private void OnGet(AudioSource source) { //source.gameObject.SetActive(true); } // Called when an item is returned to the pool. private void OnRelease(AudioSource source) { source.Stop(); source.resource = null; //source.gameObject.SetActive(false); } // Called when the pool decides to destroy an item (e.g., above max size). private void OnDestroyItem(AudioSource source) { Object.Destroy(source.gameObject); } public AudioSource GetSource(AudioSourceType sourceType) { var source = _pool.Get(); source.spatialBlend = _settings[sourceType].spatialBlend; return source; } public void ReleaseSource(AudioSource source) => _pool.Release(source); public void Dispose() { Addressables.Release(_handles); Addressables.Release(_prefabConfigHandle); if(_sourcePrefab) Addressables.Release(_sourcePrefab); } } public interface IAudioSourcePoolInitializedHandle : IGlobalSubscriber { void AudioSourcePoolInitialized(); } }