diff --git a/unity-renderer/Assets/DCLServices/EmotesCatalog/EmotesCatalogService/LambdasEmotesCatalogService.cs b/unity-renderer/Assets/DCLServices/EmotesCatalog/EmotesCatalogService/LambdasEmotesCatalogService.cs index 526832ba20..cc204ead76 100644 --- a/unity-renderer/Assets/DCLServices/EmotesCatalog/EmotesCatalogService/LambdasEmotesCatalogService.cs +++ b/unity-renderer/Assets/DCLServices/EmotesCatalog/EmotesCatalogService/LambdasEmotesCatalogService.cs @@ -1,5 +1,3 @@ -using System.Collections.Generic; -using System.Threading; using Cysharp.Threading.Tasks; using DCL; using DCL.Emotes; @@ -9,6 +7,8 @@ using DCLServices.Lambdas; using DCLServices.WearablesCatalogService; using System; +using System.Collections.Generic; +using System.Threading; using UnityEngine; public class LambdasEmotesCatalogService : IEmotesCatalogService @@ -160,23 +160,14 @@ public Promise> RequestOwnedEmotes(string userId) public async UniTask> RequestOwnedEmotesAsync(string userId, CancellationToken ct = default) { - const int TIMEOUT = 60; - CancellationTokenSource timeoutCTS = new CancellationTokenSource(); - var timeout = timeoutCTS.CancelAfterSlim(TimeSpan.FromSeconds(TIMEOUT)); var promise = RequestOwnedEmotes(userId); try { ct.ThrowIfCancellationRequested(); - var linkedCt = CancellationTokenSource.CreateLinkedTokenSource(ct, timeoutCTS.Token); - await promise.WithCancellation(linkedCt.Token); + await promise.WithCancellation(ct); } catch (OperationCanceledException e) { return null; } - finally - { - timeout?.Dispose(); - timeoutCTS?.Dispose(); - } return promise.value; } @@ -307,9 +298,10 @@ public async UniTask> RequestEmotesAsync(IList RequestEmoteAsync(x, ct)); - return await UniTask.WhenAll(tasks).AttachExternalCancellation(ct); + WearableItem[] result = await UniTask.WhenAll(tasks).AttachExternalCancellation(ct); + return result; } - catch (OperationCanceledException e) { return null; } + catch (OperationCanceledException) { return null; } } public void ForgetEmote(string id) diff --git a/unity-renderer/Assets/DCLServices/EmotesCatalog/EmotesRequestWeb.cs b/unity-renderer/Assets/DCLServices/EmotesCatalog/EmotesRequestWeb.cs index 5e45af0998..5bab11d9fd 100644 --- a/unity-renderer/Assets/DCLServices/EmotesCatalog/EmotesRequestWeb.cs +++ b/unity-renderer/Assets/DCLServices/EmotesCatalog/EmotesRequestWeb.cs @@ -6,7 +6,6 @@ using System.Collections.Generic; using System.Linq; using System.Threading; -using System.Threading.Tasks; namespace DCLServices.EmotesCatalog { diff --git a/unity-renderer/Assets/DCLServices/EmotesService/EmoteAnimationLoader.cs b/unity-renderer/Assets/DCLServices/EmotesService/EmoteAnimationLoader.cs index 2b103d8452..af731f5d33 100644 --- a/unity-renderer/Assets/DCLServices/EmotesService/EmoteAnimationLoader.cs +++ b/unity-renderer/Assets/DCLServices/EmotesService/EmoteAnimationLoader.cs @@ -1,9 +1,10 @@ using AvatarSystem; -using System; -using System.Threading; using Cysharp.Threading.Tasks; using DCL.Helpers; using DCL.Providers; +using DCLServices.EmotesService; +using System; +using System.Threading; using UnityEngine; using Object = UnityEngine.Object; @@ -20,9 +21,11 @@ public class EmoteAnimationLoader : IEmoteAnimationLoader private AudioClip audioClip; private AssetPromise_AudioClip audioClipPromise; + private readonly EmoteVolumeHandler emoteVolumeHandler; - public EmoteAnimationLoader(IWearableRetriever retriever, AddressableResourceProvider resourceProvider) + public EmoteAnimationLoader(IWearableRetriever retriever, AddressableResourceProvider resourceProvider, EmoteVolumeHandler emoteVolumeHandler) { + this.emoteVolumeHandler = emoteVolumeHandler; this.retriever = retriever; this.resourceProvider = resourceProvider; } @@ -140,6 +143,8 @@ private async UniTask SetupAudioClip(AudioClip clip, GameObject audioSourceParen audioSource.clip = audioClip; audioSource.transform.SetParent(audioSourceParent.transform, false); audioSource.transform.ResetLocalTRS(); + + emoteVolumeHandler.AddAudioSource(audioSource); } private bool IsValidAudioClip(string fileName) => @@ -155,6 +160,7 @@ private async UniTask AsyncLoadAudioClip(string file, ContentProvider public void Dispose() { + emoteVolumeHandler.RemoveAudioSource(audioSource); AssetPromiseKeeper_AudioClip.i.Forget(audioClipPromise); retriever?.Dispose(); } diff --git a/unity-renderer/Assets/DCLServices/EmotesService/EmoteAnimationLoaderFactory.cs b/unity-renderer/Assets/DCLServices/EmotesService/EmoteAnimationLoaderFactory.cs index eac6e406ef..9e9e47ae70 100644 --- a/unity-renderer/Assets/DCLServices/EmotesService/EmoteAnimationLoaderFactory.cs +++ b/unity-renderer/Assets/DCLServices/EmotesService/EmoteAnimationLoaderFactory.cs @@ -1,18 +1,21 @@ using AvatarSystem; using DCL.Providers; +using DCLServices.EmotesService; namespace DCL.Emotes { public class EmoteAnimationLoaderFactory { private readonly AddressableResourceProvider resourceProvider; + private readonly EmoteVolumeHandler emoteVolumeHandler; public EmoteAnimationLoaderFactory(AddressableResourceProvider resourceProvider) { this.resourceProvider = resourceProvider; + emoteVolumeHandler = new EmoteVolumeHandler(); } public virtual IEmoteAnimationLoader Get() => - new EmoteAnimationLoader(new WearableRetriever(), resourceProvider); + new EmoteAnimationLoader(new WearableRetriever(), resourceProvider, emoteVolumeHandler); } } diff --git a/unity-renderer/Assets/DCLServices/EmotesService/EmoteVolumeHandler.cs b/unity-renderer/Assets/DCLServices/EmotesService/EmoteVolumeHandler.cs new file mode 100644 index 0000000000..7a706579fb --- /dev/null +++ b/unity-renderer/Assets/DCLServices/EmotesService/EmoteVolumeHandler.cs @@ -0,0 +1,50 @@ +using DCL.Helpers; +using DCL.SettingsCommon; +using System.Collections.Generic; +using UnityEngine; +using AudioSettings = DCL.SettingsCommon.AudioSettings; + +namespace DCLServices.EmotesService +{ + public class EmoteVolumeHandler + { + private const float BASE_VOLUME = 0.2f; + + private readonly List audioSources = new (); + private readonly ISettingsRepository audioSettings; + + public EmoteVolumeHandler() + { + audioSettings = Settings.i.audioSettings; + audioSettings.OnChanged += OnVolumeChanged; + OnVolumeChanged(audioSettings.Data); + } + + public void AddAudioSource(AudioSource audioSource) + { + audioSources.Add(audioSource); + SetVolume(audioSource, GetVolume(audioSettings.Data)); + } + + public void RemoveAudioSource(AudioSource audioSource) + { + audioSources.Remove(audioSource); + } + + private void SetVolume(AudioSource audioSource, float volume) + { + audioSource.volume = volume; + } + + private void OnVolumeChanged(AudioSettings settings) + { + float targetVolume = GetVolume(settings); + + foreach (AudioSource audioSource in audioSources) + SetVolume(audioSource, targetVolume); + } + + private static float GetVolume(AudioSettings audioSettings) => + BASE_VOLUME * Utils.ToVolumeCurve(audioSettings.avatarSFXVolume * audioSettings.masterVolume); + } +} diff --git a/unity-renderer/Assets/DCLServices/EmotesService/EmoteVolumeHandler.cs.meta b/unity-renderer/Assets/DCLServices/EmotesService/EmoteVolumeHandler.cs.meta new file mode 100644 index 0000000000..8ea2703cec --- /dev/null +++ b/unity-renderer/Assets/DCLServices/EmotesService/EmoteVolumeHandler.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 5d183b2e693e4dd6a5e4a47735ab9f5b +timeCreated: 1700178797 \ No newline at end of file diff --git a/unity-renderer/Assets/DCLServices/EmotesService/EmotesService.asmdef b/unity-renderer/Assets/DCLServices/EmotesService/EmotesService.asmdef index 9cb4ac4b06..181b5540b0 100644 --- a/unity-renderer/Assets/DCLServices/EmotesService/EmotesService.asmdef +++ b/unity-renderer/Assets/DCLServices/EmotesService/EmotesService.asmdef @@ -17,7 +17,8 @@ "GUID:6e6a87f97192ec947993f360104e75b7", "GUID:a3ceb534947fac14da25035bc5c24788", "GUID:99cea83ca76dcd846abed7e61a8c90bd", - "GUID:b1087c5731ff68448a0a9c625bb7e52d" + "GUID:b1087c5731ff68448a0a9c625bb7e52d", + "GUID:301149363e31a4bdaa1943465a825c8e" ], "includePlatforms": [], "excludePlatforms": [], diff --git a/unity-renderer/Assets/DCLServices/EmotesService/EmotesService.cs b/unity-renderer/Assets/DCLServices/EmotesService/EmotesService.cs index 28731598fc..a6b7fca0ec 100644 --- a/unity-renderer/Assets/DCLServices/EmotesService/EmotesService.cs +++ b/unity-renderer/Assets/DCLServices/EmotesService/EmotesService.cs @@ -1,6 +1,7 @@ using AvatarAssets; using Cysharp.Threading.Tasks; using DCL.Configuration; +using DCLServices.EmotesService; using DCLServices.WearablesCatalogService; using System; using System.Collections.Generic; @@ -22,6 +23,7 @@ public class EmotesService : IEmotesService private readonly IWearablesCatalogService wearablesCatalogService; private readonly ICatalyst catalyst; private GameObject animationsModelsContainer; + private readonly EmoteVolumeHandler audioVolumeHandler; private readonly Dictionary embeddedEmotes = new (); private readonly Dictionary extendedEmotes = new (); diff --git a/unity-renderer/Assets/Scripts/MainScripts/DCL/AvatarSystem/AvatarEmotesController.cs b/unity-renderer/Assets/Scripts/MainScripts/DCL/AvatarSystem/AvatarEmotesController.cs index 75272ed232..f95074f9ba 100644 --- a/unity-renderer/Assets/Scripts/MainScripts/DCL/AvatarSystem/AvatarEmotesController.cs +++ b/unity-renderer/Assets/Scripts/MainScripts/DCL/AvatarSystem/AvatarEmotesController.cs @@ -1,19 +1,15 @@ using Cysharp.Threading.Tasks; using DCL.Emotes; -using DCL.Helpers; -using DCL.SettingsCommon; using DCL.Tasks; using System; using System.Collections.Generic; using System.Threading; using UnityEngine; -using AudioSettings = DCL.SettingsCommon.AudioSettings; namespace AvatarSystem { public class AvatarEmotesController : IAvatarEmotesController { - private const float BASE_VOLUME = 0.2f; private const string IN_HIDE_AREA = "IN_HIDE_AREA"; public event Action OnEmoteEquipped; @@ -100,23 +96,12 @@ public void PlayEmote(string emoteId, long timestamps, bool spatial = true, bool var emoteKey = new EmoteBodyId(bodyShapeId, emoteId); if (!equippedEmotes.ContainsKey(emoteKey)) return; - float volume = GetEmoteVolume(); - animator.PlayEmote(emoteId, timestamps, spatial, volume, occlude, forcePlay); + animator.PlayEmote(emoteId, timestamps, spatial, occlude, forcePlay); } private bool CanPlayEmote() => !visibilityConstraints.Contains(IN_HIDE_AREA); - // TODO: We have to decouple this volume logic into an IAudioMixer.GetVolume(float, Channel) since we are doing the same calculations everywhere - // Using AudioMixer does not work in WebGL so we calculate the volume manually - private float GetEmoteVolume() - { - // no cache since the data can change - AudioSettings audioSettingsData = Settings.i != null ? Settings.i.audioSettings.Data : new AudioSettings(); - float baseVolume = BASE_VOLUME * Utils.ToVolumeCurve(audioSettingsData.avatarSFXVolume * audioSettingsData.masterVolume); - return baseVolume; - } - public void StopEmote(bool immediate) { animator.StopEmote(immediate); @@ -124,6 +109,7 @@ public void StopEmote(bool immediate) public void EquipEmote(string emoteId, IEmoteReference emoteReference) { + if (emoteReference == null) return; var emoteKey = new EmoteBodyId(bodyShapeId, emoteId); if (equippedEmotes.ContainsKey(emoteKey)) diff --git a/unity-renderer/Assets/Scripts/MainScripts/DCL/AvatarSystem/Definitions/IAnimator.cs b/unity-renderer/Assets/Scripts/MainScripts/DCL/AvatarSystem/Definitions/IAnimator.cs index 3f05073d73..796ca89fc9 100644 --- a/unity-renderer/Assets/Scripts/MainScripts/DCL/AvatarSystem/Definitions/IAnimator.cs +++ b/unity-renderer/Assets/Scripts/MainScripts/DCL/AvatarSystem/Definitions/IAnimator.cs @@ -6,7 +6,8 @@ namespace AvatarSystem public interface IAnimator { bool Prepare(string bodyshapeId, GameObject container); - void PlayEmote(string emoteId, long timestamps, bool spatial, float volume, bool occlude, + + void PlayEmote(string emoteId, long timestamps, bool spatial, bool occlude, bool forcePlay); void StopEmote(bool immediate); diff --git a/unity-renderer/Assets/Scripts/MainScripts/DCL/Components/Avatar/AvatarAnimatorLegacy.cs b/unity-renderer/Assets/Scripts/MainScripts/DCL/Components/Avatar/AvatarAnimatorLegacy.cs index 0098459b7b..00e8b4326f 100644 --- a/unity-renderer/Assets/Scripts/MainScripts/DCL/Components/Avatar/AvatarAnimatorLegacy.cs +++ b/unity-renderer/Assets/Scripts/MainScripts/DCL/Components/Avatar/AvatarAnimatorLegacy.cs @@ -399,10 +399,7 @@ private void StopEmoteInternal(bool immediate) if (animation == null) return; if (!string.IsNullOrEmpty(blackboard.expressionTriggerId)) - { - Debug.Log($"Emote stopped {blackboard.expressionTriggerId}"); animation.Blend(blackboard.expressionTriggerId, 0, !immediate ? EXPRESSION_EXIT_TRANSITION_TIME : 0); - } // Disabled Temporally // Instantly replicate our emote status and position @@ -419,7 +416,7 @@ private void StopEmoteInternal(bool immediate) if (!immediate) OnUpdateWithDeltaTime(blackboard.deltaTime); } - private void StartEmote(string emoteId, bool spatial, float volume, bool occlude) + private void StartEmote(string emoteId, bool spatial, bool occlude) { if (!string.IsNullOrEmpty(emoteId)) { @@ -429,7 +426,7 @@ private void StartEmote(string emoteId, bool spatial, float volume, bool occlude { lastExtendedEmoteData = emoteClipData; - emoteClipData.Play(gameObject.layer, spatial, volume, occlude); + emoteClipData.Play(gameObject.layer, spatial, occlude); } } else { lastExtendedEmoteData?.Stop(); } @@ -449,7 +446,7 @@ public void SetIdleFrame() animation.Play(currentLocomotions.idle.name); } - public void PlayEmote(string emoteId, long timestamps, bool spatial, float volume, bool occlude, + public void PlayEmote(string emoteId, long timestamps, bool spatial, bool occlude, bool forcePlay) { if (animation == null) @@ -476,7 +473,7 @@ public void PlayEmote(string emoteId, long timestamps, bool spatial, float volum if (mustTriggerAnimation || loop) { - StartEmote(emoteId, spatial, volume, occlude); + StartEmote(emoteId, spatial, occlude); if (!string.IsNullOrEmpty(emoteId)) { diff --git a/unity-renderer/Assets/Scripts/MainScripts/DCL/Controllers/HUD/BackpackEditorHUDV2/BackpackEmotesSectionController.cs b/unity-renderer/Assets/Scripts/MainScripts/DCL/Controllers/HUD/BackpackEditorHUDV2/BackpackEmotesSectionController.cs index 5e0cb00367..79c90365bc 100644 --- a/unity-renderer/Assets/Scripts/MainScripts/DCL/Controllers/HUD/BackpackEditorHUDV2/BackpackEmotesSectionController.cs +++ b/unity-renderer/Assets/Scripts/MainScripts/DCL/Controllers/HUD/BackpackEditorHUDV2/BackpackEmotesSectionController.cs @@ -121,18 +121,14 @@ async UniTaskVoid LoadEmotesAsync(CancellationToken ct = default) } allEmotes = consolidatedEmotes.Values.ToList(); - UpdateEmotes(); try { await FetchCustomEmoteItems(allEmotes, ct); await FetchCustomEmoteCollections(allEmotes, ct); - UpdateEmotes(); - } - catch (Exception e) when (e is not OperationCanceledException) - { - Debug.LogException(e); } + catch (Exception e) when (e is not OperationCanceledException) { Debug.LogException(e); } + finally { UpdateEmotes(); } void UpdateEmotes() { diff --git a/unity-renderer/Assets/Scripts/MainScripts/DCL/Controllers/HUD/SettingsPanelHUD/Configuration/Controls/AvatarSFXVolumeControlConfiguration.asset b/unity-renderer/Assets/Scripts/MainScripts/DCL/Controllers/HUD/SettingsPanelHUD/Configuration/Controls/AvatarSFXVolumeControlConfiguration.asset index 9166ecb7c3..d249d10d28 100644 --- a/unity-renderer/Assets/Scripts/MainScripts/DCL/Controllers/HUD/SettingsPanelHUD/Configuration/Controls/AvatarSFXVolumeControlConfiguration.asset +++ b/unity-renderer/Assets/Scripts/MainScripts/DCL/Controllers/HUD/SettingsPanelHUD/Configuration/Controls/AvatarSFXVolumeControlConfiguration.asset @@ -12,13 +12,16 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: 060c1aa63ccfe124aa3cd640f9286a0b, type: 3} m_Name: AvatarSFXVolumeControlConfiguration m_EditorClassIdentifier: - title: AVATAR SFX + title: AVATAR & EMOTE SFX controlPrefab: {fileID: 6783608136250682537, guid: b07edc69073d61d4bbfb5c70a6b0c833, type: 3} controlController: {fileID: 11400000, guid: 0a8ca3291ff98c44caeda6bfa12fa322, type: 2} flagsThatDisableMe: [] flagsThatDeactivateMe: [] + flagsThatOverrideMe: [] isBeta: 0 + infoButtonEnabled: 0 + infoTooltipMessage: sliderMinValue: 0 sliderMaxValue: 100 storeValueAsNormalized: 0 diff --git a/unity-renderer/Assets/Scripts/MainScripts/DCL/Models/AvatarAssets/EmoteClipData.cs b/unity-renderer/Assets/Scripts/MainScripts/DCL/Models/AvatarAssets/EmoteClipData.cs index a6cfc9010a..c1882db53a 100644 --- a/unity-renderer/Assets/Scripts/MainScripts/DCL/Models/AvatarAssets/EmoteClipData.cs +++ b/unity-renderer/Assets/Scripts/MainScripts/DCL/Models/AvatarAssets/EmoteClipData.cs @@ -49,7 +49,7 @@ public EmoteClipData(AnimationClip mainClip, GameObject container, AudioSource a renderers = ExtraContent.GetComponentsInChildren(); } - public void Play(int gameObjectLayer, bool spatial, float volume, bool occlude) + public void Play(int gameObjectLayer, bool spatial, bool occlude) { if (renderers != null) { @@ -83,7 +83,6 @@ public void Play(int gameObjectLayer, bool spatial, float volume, bool occlude) if (AudioSource == null) return; AudioSource.spatialBlend = spatial ? 1 : 0; - AudioSource.volume = volume; AudioSource.loop = Loop; AudioSource.Play(); }