Files
Infratest/Assets/Code/Infrastructure/Audio/AudioSourcePool.cs
T
2026-01-27 12:33:40 +03:00

180 lines
7.5 KiB
C#

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<AudioSource> _pool;
private GameObject _sourcePrefab;
private Dictionary<AudioSourceType, AudioSourceSettingsConfig> _settings;
public AudioSourcePool(Dictionary<AudioSourceType, AudioSourceSettingsConfig> settings) => _settings = settings;
private string _configsLabel;
private AsyncOperationHandle<IList<AudioSourceSettingsConfig>> _handles;
private AssetReference _sourcePrefabConfigReference;
private AsyncOperationHandle<AudioSourcePrefabConfig> _prefabConfigHandle;
private AsyncOperationHandle<GameObject> _prefabHandle;
private EventBus.EventBus _eventBus;
public AudioSourcePool(IConfigLocator configLocator, EventBus.EventBus eventBus)
{
_eventBus = eventBus;
_configsLabel = configLocator.TryGetManyConfigAssetReferences<AudioSourceSettingsConfig>();
_sourcePrefabConfigReference = configLocator.TryGetConfigAssetReference<AudioSourcePrefabConfig>();
LoadConfigs().Forget();
}
private async UniTaskVoid LoadConfigs()
{
_prefabConfigHandle = Addressables.LoadAssetAsync<AudioSourcePrefabConfig>(_sourcePrefabConfigReference);
_handles = Addressables.LoadAssetsAsync<AudioSourceSettingsConfig>(_configsLabel);
await UniTask.WhenAll(
_prefabConfigHandle.ToUniTask(),
_handles.ToUniTask());
_prefabHandle = Addressables.LoadAssetAsync<GameObject>(_prefabConfigHandle.Result.prefabReference);
_settings = _handles.Result.ToDictionary(x => x.sourceType);
await _prefabHandle.ToUniTask();
_pool = new ObjectPool<AudioSource>(
createFunc: CreateItem,
// actionOnGet: OnGet,
actionOnRelease: OnRelease,
actionOnDestroy: OnDestroyItem,
collectionCheck: true, // helps catch double-release mistakes
defaultCapacity: 10,
maxSize: 20
);
_eventBus.RaiseEvent<IAudioSourcePoolInitializedHandle>(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>();
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 async UniTaskVoid PlayOneShot(AudioClip clip, Vector3 position, AudioMixerGroup audioMixerGroup, AudioSourceType audioSourceType = AudioSourceType.NoBlend, Action onComplete = null)
// {
// AudioSource source = _pool.Get();
// source.PlayOneShot(clip);
// source.spatialBlend = _settings[audioSourceType].spatialBlend;
// source.transform.position = position;
// source.outputAudioMixerGroup = audioMixerGroup;
//
// await UniTask.WaitUntilValueChanged(source, x => x.isPlaying);
// onComplete?.Invoke();
// _pool.Release(source);
// }
// public async UniTaskVoid PlayOneShot(AudioClip clip, AudioMixerGroup audioMixerGroup, AudioSourceType audioSourceType = AudioSourceType.NoBlend, Action onComplete = null)
// {
// AudioSource source = _pool.Get();
// source.PlayOneShot(clip);
// source.spatialBlend = _settings[audioSourceType].spatialBlend;
// source.outputAudioMixerGroup = audioMixerGroup;
//
// await UniTask.WaitUntilValueChanged(source, x => x.isPlaying);
// onComplete?.Invoke();
// _pool.Release(source);
// }
// public async UniTaskVoid PlayOneShot(AudioSource audioSource, AudioClip clip, AudioMixerGroup audioMixerGroup, AudioSourceType audioSourceType = AudioSourceType.NoBlend, Action onComplete = null)
// {
// audioSource.PlayOneShot(clip);
// audioSource.spatialBlend = _settings[audioSourceType].spatialBlend;
// audioSource.outputAudioMixerGroup = audioMixerGroup;
//
// // TODO Потом сделать. Можно с cancellation, но сейчас лень. Ну правда
// await UniTask.WaitUntilValueChanged(audioSource, x => x.isPlaying);
//
// if (!audioSource) return;
//
// _pool.Release(audioSource);
// onComplete?.Invoke();
// }
// public async UniTaskVoid PlayOneShot(AudioClip clip, AudioMixerGroup audioMixerGroup, CancellationTokenSource cancellationToken, AudioSourceType audioSourceType = AudioSourceType.NoBlend, Action onComplete = null)
// {
// AudioSource source = _pool.Get();
// source.PlayOneShot(clip);
// source.spatialBlend = _settings[audioSourceType].spatialBlend;
// source.outputAudioMixerGroup = audioMixerGroup;
//
// var (isCanceled, _) = await UniTask.WaitUntilValueChanged(source, x => x.isPlaying, cancellationToken: cancellationToken.Token).SuppressCancellationThrow();
//
// _pool.Release(source);
//
// if(!isCanceled) onComplete?.Invoke();
// else cancellationToken.Dispose();
// }
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);
Addressables.Release(_sourcePrefab);
}
}
public interface IAudioSourcePoolInitializedHandle : IGlobalSubscriber
{
void AudioSourcePoolInitialized();
}
}