Приемлемое воспроизведение музыки

This commit is contained in:
ThomasCharester committed 2025-11-15 01:12:33 +03:00
1 parent 3020140360
commit 5c81bde5db
13 files changed
+355 -193

No files matched your search

@@ -30,9 +30,7 @@ namespace Code.Audio
private AsyncOperationHandle<IList<AudioClip>> _enemiesHandle;
private AsyncOperationHandle<IList<AudioClip>> _dispatcherHandle;
public List<AudioClip> PeacefulMusic { get; private set; } = new();
public List<AudioClip> ActionMusic { get; private set; } = new();
public List<AudioClip> MenuMusic { get; private set; } = new();
public Dictionary<MusicType, List<AudioClip>> MusicDictionary { get; private set; } = new();
public List<AudioClip> SFXAudios { get; private set; } = new();
public List<AudioClip> EnemiesAudios { get; private set; } = new();
public List<AudioClip> DispatcherAudios { get; private set; } = new();
@@ -54,6 +52,10 @@ namespace Code.Audio
_enemies = enemiesSoundListConfig.enemies;
_dispatcher = dispatcherSoundListConfig.dispatcher;
// _character = characterSoundListConfig.character;
MusicDictionary.Add(MusicType.Menu, new ());
MusicDictionary.Add(MusicType.Peaceful, new ());
MusicDictionary.Add(MusicType.Action, new ());
}
// public async UniTask<AudioMixer> CreateMixer()
@@ -72,18 +74,17 @@ namespace Code.Audio
_peacefulMusicHandle = Addressables.LoadAssetsAsync<AudioClip>(_peacefulSoundtrack, OnPeacefulTrackLoaded, Addressables.MergeMode.None);
await UniTask.WhenAll(_actionMusicHandle.ToUniTask(), _peacefulMusicHandle.ToUniTask());
}
public void ReleaseGameplayMusic()
public void ReleaseActionMusic()
{
ActionMusic.Clear();
MusicDictionary[MusicType.Action].Clear();
_actionMusicHandle.Release();
PeacefulMusic.Clear();
}
public void ReleasePeacefulMusic()
{
MusicDictionary[MusicType.Peaceful].Clear();
_peacefulMusicHandle.Release();
}
public async UniTask WarmMenuMusic( )
{
_menuMusicHandle = Addressables.LoadAssetsAsync<AudioClip>(_menuSoundtrack, OnMenuTrackLoaded, Addressables.MergeMode.None);
@@ -91,10 +92,9 @@ namespace Code.Audio
await _menuMusicHandle.ToUniTask();
}
public void ReleaseMenuMusic()
{
MenuMusic.Clear();
MusicDictionary[MusicType.Menu].Clear();
// foreach (var assetReference in _menuSoundtrack) assetReference.ReleaseAsset();
_menuMusicHandle.Release();
}
@@ -105,7 +105,6 @@ namespace Code.Audio
await _SFXHandle.ToUniTask();
}
public void ReleaseSFX()
{
SFXAudios.Clear();
@@ -139,17 +138,17 @@ namespace Code.Audio
_dispatcherHandle.Release();
}
private void OnMenuTrackLoaded(AudioClip audioClip)
{
MusicDictionary[MusicType.Menu].Add(audioClip);
}
private void OnActionTrackLoaded(AudioClip audioClip)
{
ActionMusic.Add(audioClip);
MusicDictionary[MusicType.Action].Add(audioClip);
}
private void OnPeacefulTrackLoaded(AudioClip audioClip)
{
PeacefulMusic.Add(audioClip);
}
private void OnMenuTrackLoaded(AudioClip audioClip)
{
MenuMusic.Add(audioClip);
MusicDictionary[MusicType.Peaceful].Add(audioClip);
}
private void OnSFXLoaded(AudioClip audioClip)
{
+239 -145
View File
@@ -22,9 +22,9 @@ namespace Code.Audio
private AudioSource _peacefulMusicSource;
private AudioMixerGroup _masterGroup,
_musicGroup,
_actionMusicGroup,
_peacefulMusicGroup,
// _musicGroup,
// _actionMusicGroup,
// _peacefulMusicGroup,
_SFXGroup,
_creaturesGroup,
_dispatcherGroup,
@@ -34,7 +34,7 @@ namespace Code.Audio
private readonly AudioSourcePool _audioSourcePool = new();
private Dictionary<AudioSnapshotState, AudioMixerSnapshot> _snapshots = new();
public AudioService(IAudioFactory audioFactory)
{
_audioFactory = audioFactory;
@@ -44,112 +44,201 @@ namespace Code.Audio
{
// _mixer = await _audioFactory.CreateMixer();
_mixer = _audioFactory.AudioMixer;
_masterGroup = _mixer.FindMatchingGroups(AudioGroups.MasterGroup)[0];
_actionMusicGroup = _mixer.FindMatchingGroups(AudioGroups.ActionMusicGroup)[0];
_peacefulMusicGroup = _mixer.FindMatchingGroups(AudioGroups.PeacefulMusicGroup)[0];
// _actionMusicGroup = _mixer.FindMatchingGroups(AudioGroups.ActionMusicGroup)[0];
// _peacefulMusicGroup = _mixer.FindMatchingGroups(AudioGroups.PeacefulMusoup)[0];
// _musicGroup = _mixer.FindMatchingGroups(AudioGroups.MusicGroup)[0];
_musicAudioGroups.Add(MusicType.Menu, _mixer.FindMatchingGroups(AudioGroups.MenuMusicGroup)[0]);
_musicAudioGroups.Add(MusicType.Action, _mixer.FindMatchingGroups(AudioGroups.ActionMusicGroup)[0]);
_musicAudioGroups.Add(MusicType.Peaceful, _mixer.FindMatchingGroups(AudioGroups.PeacefulMusicGroup)[0]);
_cancellationTokenSources.Add(MusicType.Menu, new());
_cancellationTokenSources.Add(MusicType.Action, new());
_cancellationTokenSources.Add(MusicType.Peaceful, new());
_musicAudioSources.Add(MusicType.Menu, null);
_musicAudioSources.Add(MusicType.Action, null);
_musicAudioSources.Add(MusicType.Peaceful, null);
_SFXGroup = _mixer.FindMatchingGroups(AudioGroups.SFXGroup)[0];
_musicGroup = _mixer.FindMatchingGroups(AudioGroups.MusicGroup)[0];
_creaturesGroup = _mixer.FindMatchingGroups(AudioGroups.CreaturesGroup)[0];
_dispatcherGroup = _mixer.FindMatchingGroups(AudioGroups.DispatcherMusicGroup)[0];
_courierGroup = _mixer.FindMatchingGroups(AudioGroups.CourierMusicGroup)[0];
_enemiesGroup = _mixer.FindMatchingGroups(AudioGroups.EnemiesMusicGroup)[0];
_snapshots[AudioSnapshotState.None] = _mixer.FindSnapshot(AudioGroups.NoneSnapshot);
_snapshots[AudioSnapshotState.Peaceful] = _mixer.FindSnapshot(AudioGroups.PeacefulSnapshot);
_snapshots[AudioSnapshotState.Action] = _mixer.FindSnapshot(AudioGroups.ActionSnapshot);
_snapshots[AudioSnapshotState.None] = _mixer.FindSnapshot(AudioGroups.NoneSnapshot);
_snapshots[AudioSnapshotState.Menu] = _mixer.FindSnapshot(AudioGroups.MenuSnapshot);
await _audioFactory.LoadAudioSourcePrefab(_audioSourcePool.Initialize);
// InitializeMusicSources();
}
// private void InitializeMusicSources()
// {
// _actionMusicSource = _audioSourcePool.GetSource();
// _actionMusicSource.outputAudioMixerGroup = _actionMusicGroup;
// _actionMusicSource.spatialBlend = 0f;
//
// _peacefulMusicSource = _audioSourcePool.GetSource();
// _peacefulMusicSource.outputAudioMixerGroup = _peacefulMusicGroup;
// _peacefulMusicSource.spatialBlend = 0f;
// }
// public void PlayRandomGameplayMusic()
// {
// _peacefulMusicSource.resource =
// _audioFactory.PeacefulMusic[Random.Range(0, _audioFactory.PeacefulMusic.Count)];
// _actionMusicSource.resource =
// _audioFactory.ActionMusic[Random.Range(0, _audioFactory.ActionMusic.Count)];
//
// _peacefulMusicSource.Play();
// _actionMusicSource.Play();
// }
// public void PlayRandomMenuMusic()
// {
// TransitToSnapshot(AudioSnapshotState.Peaceful);
//
// _peacefulMusicSource.resource = _audioFactory.MenuMusic[Random.Range(0, _audioFactory.MenuMusic.Count)];
//
// _peacefulMusicSource.Play();
// }
//
// public void PlayRandomMenuMusic()
// {
// TransitToSnapshot(AudioSnapshotState.Peaceful);
//
// _peacefulMusicSource.resource = _audioFactory.MenuMusic[Random.Range(0, _audioFactory.MenuMusic.Count)];
//
// _peacefulMusicSource.Play();
// }
#pragma warning disable CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed
private Dictionary<MusicType, CancellationTokenSource> _cancellationTokenSources = new();
private Dictionary<MusicType, AudioSource> _musicAudioSources = new();
private Dictionary<MusicType, AudioMixerGroup> _musicAudioGroups = new();
public async UniTaskVoid PlayRandomMusicUntilHumanityWillBeDestroyedForTheySins(MusicType musicType)
{
if(!_musicAudioSources[musicType])
{
_musicAudioSources[musicType] = _audioSourcePool.GetSource();
_musicAudioSources[musicType].spatialBlend = 0f;
_musicAudioSources[musicType].outputAudioMixerGroup = _musicAudioGroups[musicType];
}
_musicAudioSources[musicType].resource =
_audioFactory.MusicDictionary[musicType][
Random.Range(0, _audioFactory.MusicDictionary[musicType].Count)];
_musicAudioSources[musicType].Play();
// await UniTask.WaitUntilValueChanged(_musicAudioSources[musicType],
// _ => !_musicAudioSources[musicType].isPlaying,
// cancellationToken: _cancellationTokenSources[musicType].Token);
await UniTask.WaitUntil(() => _musicAudioSources[musicType].isPlaying);
Debug.Log($"Playing {musicType}");
var isCanceled = await UniTask.WaitUntil(() => !_musicAudioSources[musicType].isPlaying,
cancellationToken: _cancellationTokenSources[musicType].Token).SuppressCancellationThrow();
Debug.Log($"Finished {musicType}");
if (isCanceled)
{
Debug.Log($"Cancelled {musicType}");
_cancellationTokenSources[musicType].Dispose();
_cancellationTokenSources[musicType] = new();
_audioSourcePool.ReleaseSource(_musicAudioSources[musicType]);
return;
}
PlayRandomMusicUntilHumanityWillBeDestroyedForTheySins(musicType);
}
InitializeMusicSources();
}
private void InitializeMusicSources()
public async UniTaskVoid GladlyAskToStopMusic(MusicType musicType, AudioSnapshotState audioSnapshotState = AudioSnapshotState.None, float time = 1f, Action callback = null)
{
_actionMusicSource = _audioSourcePool.GetSource();
_actionMusicSource.outputAudioMixerGroup = _actionMusicGroup;
_actionMusicSource.spatialBlend = 0f;
TransitToSnapshot(audioSnapshotState, time);
await UniTask.WaitForSeconds(time);
_peacefulMusicSource = _audioSourcePool.GetSource();
_peacefulMusicSource.outputAudioMixerGroup = _peacefulMusicGroup;
_peacefulMusicSource.spatialBlend = 0f;
}
public void PlayRandomGameplayMusic()
{
_peacefulMusicSource.resource = _audioFactory.PeacefulMusic[Random.Range(0, _audioFactory.PeacefulMusic.Count)];
_actionMusicSource.resource =
_audioFactory.ActionMusic[Random.Range(0, _audioFactory.ActionMusic.Count)];
_peacefulMusicSource.Play();
_actionMusicSource.Play();
}
public void PlayRandomMenuMusic()
{
TransitToSnapshot(AudioSnapshotState.Peaceful);
_peacefulMusicSource.resource = _audioFactory.MenuMusic[Random.Range(0, _audioFactory.MenuMusic.Count)];
_peacefulMusicSource.Play();
}
private CancellationTokenSource _menuMusicTokenSource = new();
public async UniTaskVoid PlayRandomMenuMusicUntilHumanityWillBeDestroyedForTheySins()
{
TransitToSnapshot(AudioSnapshotState.Peaceful);
_cancellationTokenSources[musicType].Cancel();
_peacefulMusicSource.resource = _audioFactory.MenuMusic[Random.Range(0, _audioFactory.MenuMusic.Count)];
_peacefulMusicSource.Play();
// _musicAudioSources[musicType].Stop();
await UniTask.WaitUntilValueChanged(_peacefulMusicSource, _ => _peacefulMusicSource.isPlaying, cancellationToken: _menuMusicTokenSource.Token);
if (_menuMusicTokenSource.IsCancellationRequested)
{
_menuMusicTokenSource.Dispose();
_menuMusicTokenSource = new();
return;
}
PlayRandomMenuMusicUntilHumanityWillBeDestroyedForTheySins();
}
private CancellationTokenSource _peacefulMusicTokenSource = new();
public async UniTaskVoid PlayRandomPeacefulMusicUntilHumanityWillBeDestroyedForTheySins()
{
TransitToSnapshot(AudioSnapshotState.Peaceful);
_peacefulMusicSource.resource = _audioFactory.PeacefulMusic[Random.Range(0, _audioFactory.PeacefulMusic.Count)];
_peacefulMusicSource.Play();
await UniTask.WaitUntilValueChanged(_peacefulMusicSource, _ => _peacefulMusicSource.isPlaying, cancellationToken: _peacefulMusicTokenSource.Token);
if (_peacefulMusicTokenSource.IsCancellationRequested)
{
_peacefulMusicTokenSource.Dispose();
_peacefulMusicTokenSource = new();
return;
}
PlayRandomPeacefulMusicUntilHumanityWillBeDestroyedForTheySins();
}
private CancellationTokenSource _actionMusicTokenSource = new();
public async UniTaskVoid PlayRandomActionMusicUntilHumanityWillBeDestroyedForTheySins()
{
TransitToSnapshot(AudioSnapshotState.Action);
_actionMusicSource.resource = _audioFactory.ActionMusic[Random.Range(0, _audioFactory.ActionMusic.Count)];
_actionMusicSource.Play();
await UniTask.WaitUntilValueChanged(_actionMusicSource, _ => _actionMusicSource.isPlaying, cancellationToken: _actionMusicTokenSource.Token);
if (_actionMusicTokenSource.IsCancellationRequested)
{
_actionMusicTokenSource.Dispose();
_actionMusicTokenSource = new();
return;
}
PlayRandomActionMusicUntilHumanityWillBeDestroyedForTheySins();
callback?.Invoke();
}
//
// private CancellationTokenSource _menuMusicTokenSource = new();
//
// public async UniTaskVoid PlayRandomMenuMusicUntilHumanityWillBeDestroyedForTheySins()
// {
// TransitToSnapshot(AudioSnapshotState.Peaceful);
//
// _peacefulMusicSource.resource = _audioFactory.MenuMusic[Random.Range(0, _audioFactory.MenuMusic.Count)];
//
// _peacefulMusicSource.Play();
//
// await UniTask.WaitUntilValueChanged(_peacefulMusicSource, _ => _peacefulMusicSource.isPlaying,
// cancellationToken: _menuMusicTokenSource.Token);
// if (_menuMusicTokenSource.IsCancellationRequested)
// {
// _menuMusicTokenSource.Dispose();
// _menuMusicTokenSource = new();
// return;
// }
//
// PlayRandomMenuMusicUntilHumanityWillBeDestroyedForTheySins();
// }
//
// private CancellationTokenSource _peacefulMusicTokenSource = new();
//
// public async UniTaskVoid PlayRandomPeacefulMusicUntilHumanityWillBeDestroyedForTheySins()
// {
// TransitToSnapshot(AudioSnapshotState.Peaceful);
//
// _peacefulMusicSource.resource =
// _audioFactory.PeacefulMusic[Random.Range(0, _audioFactory.PeacefulMusic.Count)];
//
// _peacefulMusicSource.Play();
//
// await UniTask.WaitUntilValueChanged(_peacefulMusicSource, _ => _peacefulMusicSource.isPlaying,
// cancellationToken: _peacefulMusicTokenSource.Token);
// if (_peacefulMusicTokenSource.IsCancellationRequested)
// {
// _peacefulMusicTokenSource.Dispose();
// _peacefulMusicTokenSource = new();
// return;
// }
//
// PlayRandomPeacefulMusicUntilHumanityWillBeDestroyedForTheySins();
// }
//
// private CancellationTokenSource _actionMusicTokenSource = new();
// public async UniTaskVoid PlayRandomActionMusicUntilHumanityWillBeDestroyedForTheySins()
// {
// TransitToSnapshot(AudioSnapshotState.Action);
//
// _actionMusicSource.resource = _audioFactory.ActionMusic[Random.Range(0, _audioFactory.ActionMusic.Count)];
//
// _actionMusicSource.Play();
//
// await UniTask.WaitUntilValueChanged(_actionMusicSource, _ => _actionMusicSource.isPlaying,
// cancellationToken: _actionMusicTokenSource.Token);
// if (_actionMusicTokenSource.IsCancellationRequested)
// {
// _actionMusicTokenSource.Dispose();
// _actionMusicTokenSource = new();
// return;
// }
//
// PlayRandomActionMusicUntilHumanityWillBeDestroyedForTheySins();
// }
#pragma warning restore CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed
public void StopMusic()
{
@@ -162,60 +251,63 @@ namespace Code.Audio
TransitToSnapshot(AudioSnapshotState.None);
_peacefulMusicSource.Stop();
_actionMusicSource.Stop();
callback?.Invoke();
}
public async UniTaskVoid GladlyAskToStopMenuMusic(Action callback = null)
{
TransitToSnapshot(AudioSnapshotState.None);
await UniTask.WaitForSeconds(1f);
_peacefulMusicSource.Stop();
_menuMusicTokenSource.Cancel();
callback?.Invoke();
}
public async UniTaskVoid GladlyAskToStopGameplayMusic(Action callback = null)
{
TransitToSnapshot(AudioSnapshotState.None);
await UniTask.WaitForSeconds(1f);
_actionMusicSource.Stop();
_peacefulMusicSource.Stop();
_actionMusicTokenSource.Cancel();
_peacefulMusicTokenSource.Cancel();
callback?.Invoke();
}
public async UniTaskVoid GladlyAskToStopActionMusic(Action callback = null)
{
TransitToSnapshot(AudioSnapshotState.None);
await UniTask.WaitForSeconds(1f);
_actionMusicSource.Stop();
_actionMusicTokenSource.Cancel();
callback?.Invoke();
}
public async UniTaskVoid GladlyAskToStopPeacefulMusic(Action callback = null)
{
TransitToSnapshot(AudioSnapshotState.None);
await UniTask.WaitForSeconds(1f);
_peacefulMusicSource.Stop();
_peacefulMusicTokenSource.Cancel();
callback?.Invoke();
}
//
// public async UniTaskVoid GladlyAskToStopMenuMusic(Action callback = null)
// {
// TransitToSnapshot(AudioSnapshotState.None);
//
// await UniTask.WaitForSeconds(1f);
//
// _peacefulMusicSource.Stop();
//
// _menuMusicTokenSource.Cancel();
//
// callback?.Invoke();
// }
//
// public async UniTaskVoid GladlyAskToStopGameplayMusic(Action callback = null)
// {
// TransitToSnapshot(AudioSnapshotState.None);
//
// await UniTask.WaitForSeconds(1f);
//
// _actionMusicSource.Stop();
// _peacefulMusicSource.Stop();
//
// _actionMusicTokenSource.Cancel();
// _peacefulMusicTokenSource.Cancel();
//
// callback?.Invoke();
// }
//
// public async UniTaskVoid GladlyAskToStopActionMusic(Action callback = null)
// {
// TransitToSnapshot(AudioSnapshotState.None);
//
// await UniTask.WaitForSeconds(1f);
//
// _actionMusicSource.Stop();
//
// _actionMusicTokenSource.Cancel();
//
// callback?.Invoke();
// }
//
// public async UniTaskVoid GladlyAskToStopPeacefulMusic(Action callback = null)
// {
// TransitToSnapshot(AudioSnapshotState.None);
//
// await UniTask.WaitForSeconds(1f);
//
// _peacefulMusicSource.Stop();
//
// _peacefulMusicTokenSource.Cancel();
//
// callback?.Invoke();
// }
public void TransitToSnapshot(AudioSnapshotState state, float time = 1f)
{
@@ -227,10 +319,12 @@ namespace Code.Audio
{
_audioSourcePool.PlayOneShot(_audioFactory.SFXAudios[(int)sfxId], position, _SFXGroup);
}
public void PlayEnemy(EnemiesSounds enemySoundId, Vector3 position)
{
_audioSourcePool.PlayOneShot(_audioFactory.EnemiesAudios[(int)enemySoundId], position, _enemiesGroup);
}
public void PlayDispatcher(DispatcherSounds dispatcherSoundId)
{
_audioSourcePool.PlayShizo(_audioFactory.DispatcherAudios[(int)dispatcherSoundId], _dispatcherGroup);
@@ -4,6 +4,7 @@ namespace Code.Audio
{
None,
Peaceful,
Action
Action,
Menu
}
}
@@ -19,7 +19,7 @@ namespace Code.Audio
_pool = new ObjectPool<AudioSource>(
createFunc: CreateItem,
// actionOnGet: OnGet,
// actionOnRelease: OnRelease,
actionOnRelease: OnRelease,
actionOnDestroy: OnDestroyItem,
collectionCheck: true, // helps catch double-release mistakes
defaultCapacity: 10,
@@ -45,6 +45,7 @@ namespace Code.Audio
// Called when an item is returned to the pool.
private void OnRelease(AudioSource source)
{
source.Stop();
//source.gameObject.SetActive(false);
}
@@ -8,16 +8,14 @@ namespace Code.Audio
{
public interface IAudioFactory
{
List<AudioClip> PeacefulMusic { get; }
List<AudioClip> ActionMusic { get; }
List<AudioClip> MenuMusic { get; }
List<AudioClip> SFXAudios { get; }
List<AudioClip> EnemiesAudios { get; }
List<AudioClip> DispatcherAudios { get; }
AudioMixer AudioMixer { get; }
Dictionary<MusicType, List<AudioClip>> MusicDictionary { get; }
UniTask LoadAudioSourcePrefab(Action<GameObject> callback);
UniTask WarmGameplayMusic();
void ReleaseGameplayMusic();
void ReleaseActionMusic();
UniTask WarmMenuMusic();
void ReleaseMenuMusic();
UniTask WarmSFX();
@@ -26,5 +24,6 @@ namespace Code.Audio
void ReleaseEnemies();
UniTask WarmDispatcher();
void ReleaseDispatcher();
void ReleasePeacefulMusic();
}
}
@@ -7,20 +7,13 @@ namespace Code.Audio
public interface IAudioService
{
UniTask Initialize();
void PlayRandomGameplayMusic();
UniTaskVoid PlayRandomMusicUntilHumanityWillBeDestroyedForTheySins(MusicType musicType);
UniTaskVoid GladlyAskToStopMusic(MusicType musicType, AudioSnapshotState audioSnapshotState = AudioSnapshotState.None, float time = 1f, Action callback = null);
void StopMusic();
void GladlyAskToStopMusic(Action callback = null);
void TransitToSnapshot(AudioSnapshotState state, float time = 1f);
void PlaySFX(SFXSounds sfxId, Vector3 position);
void PlayEnemy(EnemiesSounds enemySoundId, Vector3 position);
void PlayDispatcher(DispatcherSounds dispatcherSoundId);
void PlayRandomMenuMusic();
UniTaskVoid PlayRandomMenuMusicUntilHumanityWillBeDestroyedForTheySins();
void StopMusic();
void GladlyAskToStopMusic(Action callback = null);
UniTaskVoid GladlyAskToStopMenuMusic(Action callback = null);
UniTaskVoid GladlyAskToStopActionMusic(Action callback = null);
UniTaskVoid GladlyAskToStopPeacefulMusic(Action callback = null);
UniTaskVoid PlayRandomPeacefulMusicUntilHumanityWillBeDestroyedForTheySins();
UniTaskVoid PlayRandomActionMusicUntilHumanityWillBeDestroyedForTheySins();
UniTaskVoid GladlyAskToStopGameplayMusic(Action callback = null);
}
}
@@ -0,0 +1,9 @@
namespace Code.Audio
{
public enum MusicType
{
Menu,
Peaceful,
Action
}
}
@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 74ff08d5f1b741f69e37fc06fb07ae8d
timeCreated: 1763151897