Init
This commit is contained in:
1 parent
a73338916a
commit
fbc1cc8d3e
207 files changed
+10327
-2
No files matched your search
@@ -0,0 +1,106 @@
|
||||
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.ResourceManagement.AsyncOperations;
|
||||
|
||||
namespace Code.Infrastructure.Audio
|
||||
{
|
||||
public interface IAudioFactory
|
||||
{
|
||||
UniTaskVoid LoadAudioClips(AudioNames groupName);
|
||||
void ReleaseAudios(AudioNames groupName);
|
||||
}
|
||||
|
||||
public class AudioFactory : IAudioFactory, IDisposable
|
||||
{
|
||||
private string _label;
|
||||
private Dictionary<AudioNames, Dictionary<int, AssetReference>> _audioInfos = new();
|
||||
|
||||
private Dictionary<AudioNames, Dictionary<int, AsyncOperationHandle<AudioClip>>> _clipsHandles = new();
|
||||
private AsyncOperationHandle<IList<AudioInfoConfig>> _configsHandle;
|
||||
private EventBus.EventBus _eventBus;
|
||||
|
||||
public AudioFactory(IConfigLocator configLocator, EventBus.EventBus eventBus)
|
||||
{
|
||||
_eventBus = eventBus;
|
||||
_label = configLocator.TryGetManyConfigAssetReferences<AudioInfoConfig>();
|
||||
|
||||
for (var i = 0; i < typeof(AudioNames).GetEnumValues().Length; i++)
|
||||
{
|
||||
_audioInfos.Add((AudioNames)i, new Dictionary<int, AssetReference>());
|
||||
_clipsHandles.Add((AudioNames)i, new Dictionary<int, AsyncOperationHandle<AudioClip>>());
|
||||
}
|
||||
|
||||
LoadConfigs().Forget();
|
||||
}
|
||||
|
||||
private async UniTaskVoid LoadConfigs()
|
||||
{
|
||||
_configsHandle = Addressables.LoadAssetsAsync<AudioInfoConfig>(_label);
|
||||
|
||||
await _configsHandle.ToUniTask();
|
||||
|
||||
foreach (AudioInfoConfig config in _configsHandle.Result)
|
||||
_audioInfos[config.GroupName].Add(config.id, config.fileReference);
|
||||
|
||||
_eventBus.RaiseEvent<IAudioConfigsLoadedHandle>(ui => ui.AudioConfigsLoaded());
|
||||
}
|
||||
|
||||
public async UniTaskVoid LoadAudioClips(AudioNames groupName)
|
||||
{
|
||||
UnityEngine.Debug.LogWarning($"Audios loaded {groupName}");
|
||||
|
||||
foreach (var audioInfo in _audioInfos[groupName])
|
||||
if (!_clipsHandles[groupName].ContainsKey(audioInfo.Key))
|
||||
_clipsHandles[groupName].Add(audioInfo.Key, Addressables.LoadAssetAsync<AudioClip>(audioInfo.Value));
|
||||
else
|
||||
_clipsHandles[groupName][audioInfo.Key] = Addressables.LoadAssetAsync<AudioClip>(audioInfo.Value);
|
||||
|
||||
foreach (var handle in _clipsHandles[groupName])
|
||||
await handle.Value.ToUniTask();
|
||||
|
||||
_eventBus.RaiseEvent<IAudioClipsEventHandle>(ui =>
|
||||
ui.AudioClipsLoaded(groupName, _clipsHandles[groupName].ToDictionary(
|
||||
x => x.Key,
|
||||
x => x.Value.Result)));
|
||||
}
|
||||
|
||||
public void ReleaseAudios(AudioNames groupName)
|
||||
{
|
||||
UnityEngine.Debug.LogWarning($"Audios unloaded {groupName}");
|
||||
_eventBus.RaiseEvent<IAudioClipsEventHandle>(x=> x.AudioClipsUnLoaded(groupName));
|
||||
|
||||
foreach (var handle in _clipsHandles)
|
||||
Addressables.Release(handle.Value);
|
||||
}
|
||||
public void Dispose()
|
||||
{
|
||||
foreach (var handles in _clipsHandles)
|
||||
{
|
||||
foreach (var handle in handles.Value)
|
||||
{
|
||||
handle.Value.Release();
|
||||
}
|
||||
}
|
||||
|
||||
_configsHandle.Release();
|
||||
}
|
||||
}
|
||||
|
||||
internal interface IAudioConfigsLoadedHandle : IGlobalSubscriber
|
||||
{
|
||||
void AudioConfigsLoaded();
|
||||
}
|
||||
|
||||
internal interface IAudioClipsEventHandle : IGlobalSubscriber
|
||||
{
|
||||
void AudioClipsLoaded(AudioNames groupName, Dictionary<int, AudioClip> toDictionary);
|
||||
void AudioClipsUnLoaded(AudioNames groupName);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: cc45c23918ed446681564b467668304b
|
||||
timeCreated: 1769344269
|
||||
@@ -0,0 +1,11 @@
|
||||
using Code.Infrastructure.Generators;
|
||||
|
||||
namespace Code.Infrastructure.Audio
|
||||
{
|
||||
[AudioMixerEnum]
|
||||
public enum AudioGroupType
|
||||
{
|
||||
Master,
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 754a72a6b2c140a49a23bf6d39654c94
|
||||
timeCreated: 1769609499
|
||||
@@ -0,0 +1,19 @@
|
||||
using Code.Infrastructure.Generators;
|
||||
using UnityEngine;
|
||||
using UnityEngine.AddressableAssets;
|
||||
|
||||
namespace Code.Infrastructure.Audio
|
||||
{
|
||||
[Config("Configs/Audio/AudioInfo", true)]
|
||||
public class AudioInfo
|
||||
{
|
||||
[ToConfig] public AudioNames GroupName;
|
||||
[ToConfig] public int id;
|
||||
[ToConfig] public AssetReference fileReference;
|
||||
}
|
||||
[Config("Configs/Audio/AudioSourceSettings")]
|
||||
public class AudioSourcePrefab
|
||||
{
|
||||
[ToConfig] public AssetReference sourcePrefab;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 821f8c193f8846568335e415bf1e7ced
|
||||
timeCreated: 1769437653
|
||||
@@ -0,0 +1,8 @@
|
||||
namespace Code.Infrastructure.Audio
|
||||
{
|
||||
public enum AudioNames
|
||||
{
|
||||
UISounds,
|
||||
EnemySFX
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 88f7326e5bec4c97b2a70228dcd9f899
|
||||
timeCreated: 1769437552
|
||||
@@ -0,0 +1,133 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Threading;
|
||||
using Code.Infrastructure.EventBus;
|
||||
using Cysharp.Threading.Tasks;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Audio;
|
||||
|
||||
namespace Code.Infrastructure.Audio
|
||||
{
|
||||
public interface IAudioService
|
||||
{
|
||||
AudioClip GetClip(AudioNames groupName, int id);
|
||||
void PlayTest();
|
||||
|
||||
UniTaskVoid PlayOneShot(AudioNames groupName, int id, Vector3 position = new Vector3(),
|
||||
AudioSourceType sourceType = AudioSourceType.NoBlend,
|
||||
AudioSource audioSource = null);
|
||||
|
||||
UniTaskVoid PlayRepeatedly(AudioNames groupName, int id,
|
||||
AudioSourceType sourceType = AudioSourceType.NoBlend, AudioSource audioSource = null, CancellationTokenSource cancellationTokenSource = null);
|
||||
|
||||
bool CheckClip(AudioNames groupName, int id);
|
||||
void CancelMusic(AudioNames groupName, int id);
|
||||
void ReleaseCancellationSource(AudioNames groupName, int id);
|
||||
}
|
||||
|
||||
public partial class AudioService : IAudioClipsEventHandle, IAudioService
|
||||
{
|
||||
private EventBus.EventBus _eventBus;
|
||||
private IAudioFactory _audioFactory;
|
||||
private IAudioSourcePool _pool;
|
||||
private Dictionary<AudioNames, Dictionary<int, AudioClip>> _audioClips = new();
|
||||
private AudioMixer _mixer;
|
||||
|
||||
private Dictionary<AudioGroupType, AudioMixerGroup> _audioMixerGroups = new();
|
||||
public AudioService(EventBus.EventBus eventBus, IAudioFactory audioFactory, IAudioSourcePool pool)
|
||||
{
|
||||
_eventBus = eventBus;
|
||||
_audioFactory = audioFactory;
|
||||
_pool = pool;
|
||||
|
||||
_eventBus.Subscribe(this);
|
||||
|
||||
for (int i = 0; i < typeof(AudioNames).GetEnumValues().Length; i++)
|
||||
_audioClips.Add((AudioNames)i, new Dictionary<int, AudioClip>());
|
||||
|
||||
//InitializeMixer();
|
||||
}
|
||||
|
||||
private partial void InitializeMixer();
|
||||
public void PlayTest()
|
||||
{
|
||||
_pool.GetSource(AudioSourceType.NoBlend).PlayOneShot(GetClip(AudioNames.UISounds, 0));
|
||||
}
|
||||
|
||||
public async UniTaskVoid PlayOneShot(AudioNames groupName, int id, Vector3 position = new Vector3(),
|
||||
AudioSourceType sourceType = AudioSourceType.NoBlend,
|
||||
AudioSource audioSource = null)
|
||||
{
|
||||
if (!CheckClip(groupName, id)) return;
|
||||
|
||||
if (!audioSource) audioSource = _pool.GetSource(sourceType);
|
||||
|
||||
audioSource.transform.position = position;
|
||||
audioSource.PlayOneShot(GetClip(groupName, id));
|
||||
|
||||
await UniTask.NextFrame();
|
||||
await UniTask.WaitUntilValueChanged(audioSource, _ => !audioSource.isPlaying);
|
||||
|
||||
_pool.ReleaseSource(audioSource);
|
||||
}
|
||||
|
||||
private Dictionary<KeyValuePair<AudioNames, int>, CancellationTokenSource> _cancellationTokenSources = new();
|
||||
|
||||
public void CancelMusic(AudioNames groupName, int id) => _cancellationTokenSources[new KeyValuePair<AudioNames, int>(groupName, id)].Cancel();
|
||||
public void ReleaseCancellationSource(AudioNames groupName, int id) => _cancellationTokenSources[new KeyValuePair<AudioNames, int>(groupName, id)] = null;
|
||||
public async UniTaskVoid PlayRepeatedly(AudioNames groupName, int id,
|
||||
AudioSourceType sourceType = AudioSourceType.NoBlend, AudioSource audioSource = null, CancellationTokenSource cancellationTokenSource = null)
|
||||
{
|
||||
if (!CheckClip(groupName, id)) return;
|
||||
|
||||
if(cancellationTokenSource == null)
|
||||
{
|
||||
cancellationTokenSource = new CancellationTokenSource();
|
||||
_cancellationTokenSources[new KeyValuePair<AudioNames, int>(groupName, id)] = cancellationTokenSource;
|
||||
}
|
||||
|
||||
if (!audioSource) audioSource = _pool.GetSource(sourceType);
|
||||
if(!audioSource.resource) audioSource.resource = GetClip(groupName, id);
|
||||
|
||||
audioSource.Play();
|
||||
|
||||
await UniTask.NextFrame();
|
||||
var (isCanceled, _) = await UniTask.WaitUntilValueChanged(audioSource,
|
||||
_ => !audioSource.isPlaying,
|
||||
cancellationToken: cancellationTokenSource.Token).SuppressCancellationThrow();
|
||||
UnityEngine.Debug.LogError("Music skipping");
|
||||
|
||||
if (isCanceled)
|
||||
{
|
||||
cancellationTokenSource.Dispose();
|
||||
|
||||
_pool.ReleaseSource(audioSource);
|
||||
|
||||
ReleaseCancellationSource(groupName,id);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
PlayRepeatedly(groupName, id, sourceType, audioSource, cancellationTokenSource).Forget();
|
||||
}
|
||||
|
||||
public AudioClip GetClip(AudioNames groupName, int id) => _audioClips[groupName][id];
|
||||
public bool CheckClip(AudioNames groupName, int id) => _audioClips[groupName].ContainsKey(id);
|
||||
|
||||
public void AudioClipsLoaded(AudioNames groupname, Dictionary<int, AudioClip> clips)
|
||||
{
|
||||
_audioClips[groupname] = clips;
|
||||
_eventBus.RaiseEvent<IReadyToPlayHandle>(x => x.OnReadyToPlay(groupname));
|
||||
}
|
||||
|
||||
public void AudioClipsUnLoaded(AudioNames groupName)
|
||||
{
|
||||
_audioClips[groupName].Clear();
|
||||
_audioClips[groupName] = null;
|
||||
}
|
||||
}
|
||||
|
||||
public interface IReadyToPlayHandle : IGlobalSubscriber
|
||||
{
|
||||
void OnReadyToPlay(AudioNames groupName);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e8426c9e925a431aa73069c49d6a71c0
|
||||
timeCreated: 1769446252
|
||||
@@ -0,0 +1,129 @@
|
||||
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.sourcePrefab);
|
||||
|
||||
_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 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();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 246ae406fabc4ca791673d3f38cfe1c5
|
||||
timeCreated: 1769448041
|
||||
@@ -0,0 +1,14 @@
|
||||
using Code.Infrastructure.Generators;
|
||||
|
||||
namespace Code.Infrastructure.Audio
|
||||
{
|
||||
[Config("Configs/Audio/AudioSourceSettings", true)]
|
||||
public class AudioSourceSettings
|
||||
{
|
||||
// Дополнять по мере необходимости
|
||||
[ToConfig] public float spatialBlend;
|
||||
|
||||
[ToConfig] public AudioSourceType sourceType;
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 76d9dd39cbe641dab0cfa8ed1f2007f4
|
||||
timeCreated: 1769448198
|
||||
@@ -0,0 +1,8 @@
|
||||
namespace Code.Infrastructure.Audio
|
||||
{
|
||||
public enum AudioSourceType
|
||||
{
|
||||
Full3D,
|
||||
NoBlend
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 85f9cb99599f4399a1fd66496b5184d0
|
||||
timeCreated: 1769448254
|
||||
Reference in new issue
Block a user