From 4d0b236c4be6a93dd4958b10c7a8fd7997bbcc3c Mon Sep 17 00:00:00 2001 From: Patricio Guerra Date: Fri, 10 Nov 2023 13:57:11 -0300 Subject: [PATCH 1/7] fix: emote and movement replication (#5906) * Tweaked replication logic about emote and movement * Bugfixes * Updated cancel emote logic * Fixed emotes not stopping after moving, fixed AvatarMovementController speed not correctly being accelerated * Fixed avatars stopping their emotes when hidden by camera or distance * Fixed null references when spawning an Avatar Shape * Suggested changes --- .../ECSComponents/AvatarShape/AvatarShape.cs | 19 +- .../DCL.ECSComponents.AvatarShape.asmdef | 3 +- .../AvatarSystem/AvatarEmotesController.cs | 30 +-- .../DCL/AvatarSystem/Definitions/IAnimator.cs | 4 +- .../Definitions/IAvatarEmotesController.cs | 2 +- .../Components/Avatar/AvatarAnimatorLegacy.cs | 217 +++++++++--------- .../Avatar/AvatarMovementController.cs | 26 ++- .../Avatar/AvatarSceneEmoteHandler.cs | 7 +- .../DCL/Components/Avatar/AvatarShape.cs | 13 +- .../DCL/Components/Avatar/AvatarShape.prefab | 48 +++- .../Tests/AvatarSceneEmoteHandlerShould.cs | 4 +- .../Avatar/Tests/AvatarShapeTests.asmdef | 3 +- .../DCLCharacterController.cs | 33 +-- .../CharacterPreviewController.cs | 15 +- .../DCL/UserProfile/UserProfile.cs | 1 + 15 files changed, 236 insertions(+), 189 deletions(-) diff --git a/unity-renderer/Assets/DCLPlugins/ECS7/ECSComponents/AvatarShape/AvatarShape.cs b/unity-renderer/Assets/DCLPlugins/ECS7/ECSComponents/AvatarShape/AvatarShape.cs index 5152581a3f..1897c0dbb0 100644 --- a/unity-renderer/Assets/DCLPlugins/ECS7/ECSComponents/AvatarShape/AvatarShape.cs +++ b/unity-renderer/Assets/DCLPlugins/ECS7/ECSComponents/AvatarShape/AvatarShape.cs @@ -3,13 +3,13 @@ using DCL.Components; using DCL.Configuration; using DCL.Controllers; +using DCL.Emotes; using DCL.Helpers; using DCL.Interface; using DCL.Models; using System; using System.Collections.Generic; using System.Linq; -using System.Runtime.ExceptionServices; using System.Threading; using UnityEngine; using LOD = AvatarSystem.LOD; @@ -87,6 +87,8 @@ public class AvatarShape : MonoBehaviour, IHideAvatarAreaHandler, IPoolableObjec private Service avatarFactory; private Service emotesCatalog; + private IAvatarEmotesController emotesController; + private AvatarSceneEmoteHandler sceneEmoteHandler; public IAvatar internalAvatar => avatar; private void Awake() @@ -104,11 +106,19 @@ private void Awake() LOD avatarLOD = new LOD(avatarContainer, visibility, avatarMovementController); AvatarAnimatorLegacy animator = GetComponentInChildren(); + //Ensure base avatar references var baseAvatarReferences = baseAvatarContainer.GetComponentInChildren() ?? Instantiate(baseAvatarReferencesPrefab, baseAvatarContainer); avatar = avatarFactory.Ref.CreateAvatarWithHologram(avatarContainer, new BaseAvatar(baseAvatarReferences), animator, avatarLOD, visibility); + emotesController = avatar.GetEmotesController(); + + sceneEmoteHandler = new AvatarSceneEmoteHandler( + emotesController, + Environment.i.serviceLocator.Get(), + new UserProfileWebInterfaceBridge()); + avatarReporterController ??= new AvatarReporterController(Environment.i.world.state); onPointerDown.OnPointerDownReport += PlayerClicked; @@ -202,8 +212,11 @@ public async void ApplyModel(IParcelScene scene, IDCLEntity entity, PBAvatarShap } } - // If the model contains a value for expressionTriggerId then we try it, if value doesn't exist, we skip - if(model.HasExpressionTriggerId) + if (sceneEmoteHandler.IsSceneEmote(model.ExpressionTriggerId)) + sceneEmoteHandler + .LoadAndPlayEmote(model.BodyShape, model.ExpressionTriggerId) + .Forget(); + else avatar.GetEmotesController().PlayEmote(model.ExpressionTriggerId, model.GetExpressionTriggerTimestamp()); UpdatePlayerStatus(entity, model); diff --git a/unity-renderer/Assets/DCLPlugins/ECS7/ECSComponents/AvatarShape/DCL.ECSComponents.AvatarShape.asmdef b/unity-renderer/Assets/DCLPlugins/ECS7/ECSComponents/AvatarShape/DCL.ECSComponents.AvatarShape.asmdef index d5536fd6b0..30d6fd25aa 100644 --- a/unity-renderer/Assets/DCLPlugins/ECS7/ECSComponents/AvatarShape/DCL.ECSComponents.AvatarShape.asmdef +++ b/unity-renderer/Assets/DCLPlugins/ECS7/ECSComponents/AvatarShape/DCL.ECSComponents.AvatarShape.asmdef @@ -49,7 +49,8 @@ "GUID:6c1761dc8f737004198eb333521bd665", "GUID:c8ea72e806cd2ab47b539b37895b86b7", "GUID:9cccce9925d3495d8a5e4fa5b25f54a5", - "GUID:2d39cc535b437e749965d4a8258f0c13" + "GUID:2d39cc535b437e749965d4a8258f0c13", + "GUID:0c0c18c12967b3944b844b79c47c2320" ], "includePlatforms": [], "excludePlatforms": [], diff --git a/unity-renderer/Assets/Scripts/MainScripts/DCL/AvatarSystem/AvatarEmotesController.cs b/unity-renderer/Assets/Scripts/MainScripts/DCL/AvatarSystem/AvatarEmotesController.cs index 8d07eaae91..75272ed232 100644 --- a/unity-renderer/Assets/Scripts/MainScripts/DCL/AvatarSystem/AvatarEmotesController.cs +++ b/unity-renderer/Assets/Scripts/MainScripts/DCL/AvatarSystem/AvatarEmotesController.cs @@ -1,11 +1,10 @@ using Cysharp.Threading.Tasks; -using DCL; -using System.Collections.Generic; 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; @@ -15,7 +14,8 @@ namespace AvatarSystem public class AvatarEmotesController : IAvatarEmotesController { private const float BASE_VOLUME = 0.2f; - private const string INSIDE_CAMERA = "INSIDE_CAMERA"; + private const string IN_HIDE_AREA = "IN_HIDE_AREA"; + public event Action OnEmoteEquipped; public event Action OnEmoteUnequipped; @@ -41,7 +41,7 @@ public void AddVisibilityConstraint(string key) visibilityConstraints.Add(key); if (!CanPlayEmote()) - StopEmote(); + StopEmote(true); } public void RemoveVisibilityConstraint(string key) @@ -86,9 +86,15 @@ private async UniTask AsyncEmoteLoad(string bodyShapeId, string emoteId) catch (Exception e) { Debug.LogException(e); } } - public void PlayEmote(string emoteId, long timestamps, bool spatial, bool occlude, bool forcePlay) + public void PlayEmote(string emoteId, long timestamps, bool spatial = true, bool occlude = true, bool forcePlay = false) { - if (string.IsNullOrEmpty(emoteId)) return; + bool isPlayingEmote = !string.IsNullOrEmpty(animator.GetCurrentEmoteId()); + bool emoteIsValid = !string.IsNullOrEmpty(emoteId); + + if (isPlayingEmote && !emoteIsValid) + animator.StopEmote(false); + + if (!emoteIsValid) return; if (!CanPlayEmote()) return; var emoteKey = new EmoteBodyId(bodyShapeId, emoteId); @@ -98,12 +104,8 @@ public void PlayEmote(string emoteId, long timestamps, bool spatial, bool occlud animator.PlayEmote(emoteId, timestamps, spatial, volume, occlude, forcePlay); } - private bool CanPlayEmote() - { - if (visibilityConstraints.Count == 0) return true; - if (visibilityConstraints.Count > 1) return false; - return visibilityConstraints.Contains(INSIDE_CAMERA); - } + 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 @@ -115,9 +117,9 @@ private float GetEmoteVolume() return baseVolume; } - public void StopEmote() + public void StopEmote(bool immediate) { - animator.StopEmote(); + animator.StopEmote(immediate); } public void EquipEmote(string emoteId, IEmoteReference emoteReference) 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 8ce70f8ac1..3f05073d73 100644 --- a/unity-renderer/Assets/Scripts/MainScripts/DCL/AvatarSystem/Definitions/IAnimator.cs +++ b/unity-renderer/Assets/Scripts/MainScripts/DCL/AvatarSystem/Definitions/IAnimator.cs @@ -8,9 +8,11 @@ public interface IAnimator bool Prepare(string bodyshapeId, GameObject container); void PlayEmote(string emoteId, long timestamps, bool spatial, float volume, bool occlude, bool forcePlay); - void StopEmote(); + + void StopEmote(bool immediate); void EquipEmote(string emoteId, EmoteClipData emoteClipData); void UnequipEmote(string emoteId); + string GetCurrentEmoteId(); } } diff --git a/unity-renderer/Assets/Scripts/MainScripts/DCL/AvatarSystem/Definitions/IAvatarEmotesController.cs b/unity-renderer/Assets/Scripts/MainScripts/DCL/AvatarSystem/Definitions/IAvatarEmotesController.cs index b0c4e1a6fe..877f11b55d 100644 --- a/unity-renderer/Assets/Scripts/MainScripts/DCL/AvatarSystem/Definitions/IAvatarEmotesController.cs +++ b/unity-renderer/Assets/Scripts/MainScripts/DCL/AvatarSystem/Definitions/IAvatarEmotesController.cs @@ -13,7 +13,7 @@ public interface IAvatarEmotesController : IDisposable void PlayEmote(string emoteId, long timestamps, bool spatial = true, bool occlude = true, bool forcePlay = false); - void StopEmote(); + void StopEmote(bool immediate); void EquipEmote(string emoteId, IEmoteReference emoteReference); 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 61f5441ae2..aeee81dc4a 100644 --- a/unity-renderer/Assets/Scripts/MainScripts/DCL/Components/Avatar/AvatarAnimatorLegacy.cs +++ b/unity-renderer/Assets/Scripts/MainScripts/DCL/Components/Avatar/AvatarAnimatorLegacy.cs @@ -1,11 +1,11 @@ -using System; -using System.Collections.Generic; using AvatarSystem; using Cysharp.Threading.Tasks; using DCL; using DCL.Components; using DCL.Emotes; using DCL.Helpers; +using System; +using System.Collections.Generic; using UnityEngine; using Environment = DCL.Environment; @@ -32,31 +32,32 @@ public static bool ShouldLoop(this AvatarAnimation avatarAnimation) public class AvatarAnimatorLegacy : MonoBehaviour, IPoolLifecycleHandler, IAnimator { - const float IDLE_TRANSITION_TIME = 0.2f; - const float RUN_TRANSITION_TIME = 0.15f; - const float WALK_TRANSITION_TIME = 0.15f; - const float WALK_MAX_SPEED = 6; - const float RUN_MIN_SPEED = 4f; - const float WALK_MIN_SPEED = 0.1f; - const float WALK_RUN_SWITCH_TIME = 1.5f; - const float JUMP_TRANSITION_TIME = 0.01f; - const float FALL_TRANSITION_TIME = 0.5f; - const float EXPRESSION_EXIT_TRANSITION_TIME = 0.2f; - const float EXPRESSION_ENTER_TRANSITION_TIME = 0.1f; - const float OTHER_PLAYER_MOVE_THRESHOLD = 0.02f; - - const float AIR_EXIT_TRANSITION_TIME = 0.2f; - - const float ELEVATION_OFFSET = 0.6f; - const float RAY_OFFSET_LENGTH = 3.0f; + private const float ZERO_POSE_LOOP_TIME_SECONDS = 2f; + private const float IDLE_TRANSITION_TIME = 0.2f; + private const float RUN_TRANSITION_TIME = 0.15f; + private const float WALK_TRANSITION_TIME = 0.15f; + private const float WALK_MAX_SPEED = 6; + private const float RUN_MIN_SPEED = 4f; + private const float WALK_MIN_SPEED = 0.1f; + private const float WALK_RUN_SWITCH_TIME = 1.5f; + private const float JUMP_TRANSITION_TIME = 0.01f; + private const float FALL_TRANSITION_TIME = 0.5f; + private const float EXPRESSION_EXIT_TRANSITION_TIME = 0.2f; + private const float EXPRESSION_ENTER_TRANSITION_TIME = 0.1f; + private const float OTHER_PLAYER_MOVE_THRESHOLD = 0.5f; + + private const float AIR_EXIT_TRANSITION_TIME = 0.2f; + + private const float ELEVATION_OFFSET = 0.6f; + private const float RAY_OFFSET_LENGTH = 3.0f; // Time it takes to determine if a character is grounded when vertical velocity is 0 - const float FORCE_GROUND_TIME = 0.05f; + private const float FORCE_GROUND_TIME = 0.05f; // Minimum vertical speed used to consider whether an avatar is on air - const float MIN_VERTICAL_SPEED_AIR = 0.025f; + private const float MIN_VERTICAL_SPEED_AIR = 0.025f; - [System.Serializable] + [Serializable] public class AvatarLocomotion { public AnimationClip idle; @@ -66,7 +67,7 @@ public class AvatarLocomotion public AnimationClip fall; } - [System.Serializable] + [Serializable] public class BlackBoard { public float walkSpeedFactor; @@ -82,16 +83,16 @@ public class BlackBoard [SerializeField] internal AvatarLocomotion femaleLocomotions; [SerializeField] internal AvatarLocomotion maleLocomotions; - AvatarLocomotion currentLocomotions; + private AvatarLocomotion currentLocomotions; public new Animation animation; public BlackBoard blackboard; public Transform target; - internal System.Action currentState; + private Action currentState; - Vector3 lastPosition; - bool isOwnPlayer = false; + private Vector3 lastPosition; + private bool isOwnPlayer; private AvatarAnimationEventHandler animEventHandler; private float lastOnAirTime = 0; @@ -115,19 +116,26 @@ public class BlackBoard private AnimationState currentEmote; private int lastEmoteLoopCount; + private float lastZeroPoseTime; + private int zeroPoseLoop; + private void Awake() { hasTarget = target != null; + if (!hasTarget) Debug.LogError(message: $"Target is not assigned. {nameof(UpdateInterface)} will not work correctly.", this); } - public void Start() { OnPoolGet(); } + public void Start() + { + OnPoolGet(); + } // AvatarSystem entry points public bool Prepare(string bodyshapeId, GameObject container) { - StopEmote(); + StopEmote(true); animation = container.gameObject.GetOrCreateComponent(); container.gameObject.GetOrCreateComponent(); @@ -142,15 +150,8 @@ public bool Prepare(string bodyshapeId, GameObject container) { isUpdateRegistered = true; - if (isOwnPlayer) - { - DCLCharacterController.i.OnUpdateFinish += OnUpdateWithDeltaTime; - } - else - { - Environment.i.platform.updateEventHandler.AddListener(IUpdateEventHandler.EventType.Update, OnEventHandlerUpdate); - } - + if (isOwnPlayer) { DCLCharacterController.i.OnUpdateFinish += OnUpdateWithDeltaTime; } + else { Environment.i.platform.updateEventHandler.AddListener(IUpdateEventHandler.EventType.Update, OnEventHandlerUpdate); } } return true; @@ -158,14 +159,8 @@ public bool Prepare(string bodyshapeId, GameObject container) private void PrepareLocomotionAnims(string bodyshapeId) { - if (bodyshapeId.Contains(WearableLiterals.BodyShapes.MALE)) - { - currentLocomotions = maleLocomotions; - } - else if (bodyshapeId.Contains(WearableLiterals.BodyShapes.FEMALE)) - { - currentLocomotions = femaleLocomotions; - } + if (bodyshapeId.Contains(WearableLiterals.BodyShapes.MALE)) { currentLocomotions = maleLocomotions; } + else if (bodyshapeId.Contains(WearableLiterals.BodyShapes.FEMALE)) { currentLocomotions = femaleLocomotions; } EquipBaseClip(currentLocomotions.idle); EquipBaseClip(currentLocomotions.walk); @@ -182,7 +177,11 @@ private void PrepareLocomotionAnims(string bodyshapeId) runAnimationState = animation[runAnimationName]; walkAnimationState = animation[walkAnimationName]; } - private void OnEventHandlerUpdate() { OnUpdateWithDeltaTime(Time.deltaTime); } + + private void OnEventHandlerUpdate() + { + OnUpdateWithDeltaTime(Time.deltaTime); + } public void OnPoolGet() { @@ -203,25 +202,19 @@ public void OnPoolRelease() { isUpdateRegistered = false; - if (isOwnPlayer && DCLCharacterController.i) - { - DCLCharacterController.i.OnUpdateFinish -= OnUpdateWithDeltaTime; - } - else - { - Environment.i.platform.updateEventHandler.RemoveListener(IUpdateEventHandler.EventType.Update, OnEventHandlerUpdate); - } + if (isOwnPlayer && DCLCharacterController.i) { DCLCharacterController.i.OnUpdateFinish -= OnUpdateWithDeltaTime; } + else { Environment.i.platform.updateEventHandler.RemoveListener(IUpdateEventHandler.EventType.Update, OnEventHandlerUpdate); } } } - void OnUpdateWithDeltaTime(float deltaTime) + private void OnUpdateWithDeltaTime(float deltaTime) { blackboard.deltaTime = deltaTime; UpdateInterface(); currentState?.Invoke(blackboard); } - void UpdateInterface() + private void UpdateInterface() { if (!target) return; @@ -232,10 +225,7 @@ void UpdateInterface() float verticalVelocity = flattenedVelocity.y; //NOTE(Kinerius): if we have more or less than zero we consider that we are either jumping or falling - if (Mathf.Abs(verticalVelocity) > MIN_VERTICAL_SPEED_AIR) - { - lastOnAirTime = Time.time; - } + if (Mathf.Abs(verticalVelocity) > MIN_VERTICAL_SPEED_AIR) { lastOnAirTime = Time.time; } blackboard.verticalSpeed = verticalVelocity; @@ -268,7 +258,6 @@ void UpdateInterface() isGroundedByRaycast = Physics.Raycast(rayCache, RAY_OFFSET_LENGTH - ELEVATION_OFFSET, iGroundLayers); - } blackboard.isGrounded = isGroundedByCharacterController || isGroundedByVelocity || isGroundedByRaycast; @@ -276,19 +265,13 @@ void UpdateInterface() lastPosition = velocityTargetPosition; } - void State_Init(BlackBoard bb) + private void State_Init(BlackBoard bb) { - if (bb.isGrounded) - { - currentState = State_Ground; - } - else - { - currentState = State_Air; - } + if (bb.isGrounded) { currentState = State_Ground; } + else { currentState = State_Air; } } - void State_Ground(BlackBoard bb) + private void State_Ground(BlackBoard bb) { if (bb.deltaTime <= 0) return; @@ -299,22 +282,13 @@ void State_Ground(BlackBoard bb) walkAnimationState.normalizedSpeed = movementSpeed * bb.walkSpeedFactor; if (movementSpeed >= WALK_MAX_SPEED) - { CrossFadeTo(AvatarAnimation.RUN, runAnimationName, RUN_TRANSITION_TIME); - } else if (movementSpeed >= RUN_MIN_SPEED && movementSpeed < WALK_MAX_SPEED) - { - // Keep current animation, leave empty - } + CrossFadeTo(AvatarAnimation.WALK, walkAnimationName, WALK_TRANSITION_TIME); else if (movementSpeed > WALK_MIN_SPEED) - { CrossFadeTo(AvatarAnimation.WALK, walkAnimationName, WALK_TRANSITION_TIME); - } else - { CrossFadeTo(AvatarAnimation.IDLE, idleAnimationName, IDLE_TRANSITION_TIME); - } - if (!bb.isGrounded) { @@ -335,16 +309,10 @@ private void CrossFadeTo(AvatarAnimation animationState, string animationName, animation.CrossFade(lastCrossFade, runTransitionTime, playMode); } - void State_Air(BlackBoard bb) + private void State_Air(BlackBoard bb) { - if (bb.verticalSpeed > 0) - { - CrossFadeTo(AvatarAnimation.JUMP, jumpAnimationName, JUMP_TRANSITION_TIME, PlayMode.StopAll); - } - else - { - CrossFadeTo(AvatarAnimation.FALL, fallAnimationName, FALL_TRANSITION_TIME, PlayMode.StopAll); - } + if (bb.verticalSpeed > 0) { CrossFadeTo(AvatarAnimation.JUMP, jumpAnimationName, JUMP_TRANSITION_TIME, PlayMode.StopAll); } + else { CrossFadeTo(AvatarAnimation.FALL, fallAnimationName, FALL_TRANSITION_TIME, PlayMode.StopAll); } if (bb.isGrounded) { @@ -386,8 +354,7 @@ private void State_Expression(BlackBoard bb) { int emoteLoop = GetCurrentEmoteLoopCount(); - if (emoteLoop != lastEmoteLoopCount) - UserProfile.GetOwnUserProfile().SetAvatarExpression(bb.expressionTriggerId, UserProfile.EmoteSource.EmoteLoop, true); + if (emoteLoop != lastEmoteLoopCount) { UserProfile.GetOwnUserProfile().SetAvatarExpression(bb.expressionTriggerId, UserProfile.EmoteSource.EmoteLoop, true); } lastEmoteLoopCount = emoteLoop; } @@ -398,26 +365,51 @@ bool ExpressionGroundTransitionCondition(AnimationState animationState) { float timeTillEnd = animationState == null ? 0 : animationState.length - animationState.time; bool isAnimationOver = timeTillEnd < EXPRESSION_EXIT_TRANSITION_TIME && !bb.shouldLoop; - bool isMoving = isOwnPlayer ? DCLCharacterController.i.isMovingByUserInput : Math.Abs(bb.movementSpeed) > OTHER_PLAYER_MOVE_THRESHOLD; + bool isMoving = isOwnPlayer && DCLCharacterController.i.isMovingByUserInput; //Math.Abs(bb.movementSpeed) > OTHER_PLAYER_MOVE_THRESHOLD; - return isAnimationOver || isMoving; + bool expressionGroundTransitionCondition = isAnimationOver || isMoving; + return expressionGroundTransitionCondition; } } - private int GetCurrentEmoteLoopCount() => - Mathf.RoundToInt(currentEmote.time / currentEmote.length); + private int GetCurrentEmoteLoopCount() + { + // Some scenes might use animations with 0 length as loop poses (not ideal) + if (Mathf.Approximately(currentEmote.length, 0)) + { + if (Time.time - lastZeroPoseTime > ZERO_POSE_LOOP_TIME_SECONDS) + { + zeroPoseLoop++; + lastZeroPoseTime = Time.time; + return zeroPoseLoop; + } + } - public void StopEmote() + return Mathf.RoundToInt(currentEmote.time / currentEmote.length); + } + + public void StopEmote(bool immediate) { - StopEmoteInternal(true); + StopEmoteInternal(immediate); } private void StopEmoteInternal(bool immediate) { - if (string.IsNullOrEmpty(blackboard.expressionTriggerId)) return; - if (animation.GetClip(blackboard.expressionTriggerId) == null) return; + 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); + } + + // Instantly replicate our emote status and position + if (isOwnPlayer && !string.IsNullOrEmpty(blackboard.expressionTriggerId)) + { + DCLCharacterController.i.ReportMovement(); + UserProfile.GetOwnUserProfile().SetAvatarExpression("", UserProfile.EmoteSource.EmoteCancel, true); + } - animation.Blend(blackboard.expressionTriggerId, 0, !immediate ? EXPRESSION_EXIT_TRANSITION_TIME : 0); blackboard.expressionTriggerId = null; blackboard.shouldLoop = false; lastExtendedEmoteData?.Stop(); @@ -425,7 +417,6 @@ private void StopEmoteInternal(bool immediate) if (!immediate) OnUpdateWithDeltaTime(blackboard.deltaTime); } - private float lastEmotePlayTime = 0; private void StartEmote(string emoteId, bool spatial, float volume, bool occlude) { if (!string.IsNullOrEmpty(emoteId)) @@ -435,15 +426,11 @@ private void StartEmote(string emoteId, bool spatial, float volume, bool occlude if (emoteClipDataMap.TryGetValue(emoteId, out var emoteClipData)) { lastExtendedEmoteData = emoteClipData; - lastEmotePlayTime = Time.time; emoteClipData.Play(gameObject.layer, spatial, volume, occlude); } } - else - { - lastExtendedEmoteData?.Stop(); - } + else { lastExtendedEmoteData?.Stop(); } } public void Reset() @@ -455,7 +442,10 @@ public void Reset() animation.Stop(); } - public void SetIdleFrame() { animation.Play(currentLocomotions.idle.name); } + public void SetIdleFrame() + { + animation.Play(currentLocomotions.idle.name); + } public void PlayEmote(string emoteId, long timestamps, bool spatial, float volume, bool occlude, bool forcePlay) @@ -505,6 +495,7 @@ public void PlayEmote(string emoteId, long timestamps, bool spatial, float volum public void EquipBaseClip(AnimationClip clip) { var clipId = clip.name; + if (animation == null) return; @@ -551,6 +542,9 @@ public void UnequipEmote(string emoteId) } } + public string GetCurrentEmoteId() => + blackboard.expressionTriggerId; + private void InitializeAvatarAudioAndParticleHandlers(Animation createdAnimation) { //NOTE(Mordi): Adds handler for animation events, and passes in the audioContainer for the avatar @@ -564,10 +558,7 @@ private void InitializeAvatarAudioAndParticleHandlers(Animation createdAnimation //NOTE(Mordi): If this is a remote avatar, pass the animation component so we can keep track of whether it is culled (off-screen) or not AvatarAudioHandlerRemote audioHandlerRemote = audioContainer.GetComponent(); - if (audioHandlerRemote != null) - { - audioHandlerRemote.Init(createdAnimation.gameObject); - } + if (audioHandlerRemote != null) { audioHandlerRemote.Init(createdAnimation.gameObject); } } animEventHandler = animationEventHandler; diff --git a/unity-renderer/Assets/Scripts/MainScripts/DCL/Components/Avatar/AvatarMovementController.cs b/unity-renderer/Assets/Scripts/MainScripts/DCL/Components/Avatar/AvatarMovementController.cs index 4ceb6dd2ad..b3156d15e8 100644 --- a/unity-renderer/Assets/Scripts/MainScripts/DCL/Components/Avatar/AvatarMovementController.cs +++ b/unity-renderer/Assets/Scripts/MainScripts/DCL/Components/Avatar/AvatarMovementController.cs @@ -8,13 +8,15 @@ namespace DCL { public class AvatarMovementController : MonoBehaviour, IPoolLifecycleHandler, IAvatarMovementController { - private const float SPEED_SLOW = 2.0f; - private const float SPEED_FAST = 4.0f; - private const float SPEED_ULTRA_FAST = 8.0f; - private const float SPEED_GRAVITY = 8.0f; + // Speed values are slightly slower than the player + private const float WALK_SPEED = 4f; + private const float RUN_SPEED = 10.0f; + + private const float SPEED_GRAVITY = 11.0f; private const float ROTATION_SPEED = 6.25f; private const float SPEED_EPSILON = 0.0001f; - private float movementSpeed = SPEED_SLOW; + private const float WALK_DISTANCE = 1.5f; + private float movementSpeed = WALK_SPEED; private Transform avatarTransformValue; @@ -123,14 +125,18 @@ public void MoveTo(Vector3 position, Quaternion rotation, bool immediate = false targetPosition = position; targetRotation = rotation; - float distance = Vector3.Distance(targetPosition, currentWorldPosition); + float distance = Vector3.Distance(targetPosition, CurrentPosition); if (distance >= 50) - movementSpeed = float.MaxValue; - else if (distance >= 3) - movementSpeed = Mathf.Lerp(SPEED_SLOW, SPEED_ULTRA_FAST, (distance - 3) / 10.0f); + { + CurrentPosition = position; + AvatarTransform.rotation = rotation; + } + + if (distance >= WALK_DISTANCE) + movementSpeed = Mathf.MoveTowards(movementSpeed, RUN_SPEED, Time.deltaTime * RUN_SPEED * 10); else - movementSpeed = SPEED_SLOW; + movementSpeed = Mathf.MoveTowards(movementSpeed, WALK_SPEED, Time.deltaTime * RUN_SPEED * 30); } void UpdateLerp(float deltaTime) diff --git a/unity-renderer/Assets/Scripts/MainScripts/DCL/Components/Avatar/AvatarSceneEmoteHandler.cs b/unity-renderer/Assets/Scripts/MainScripts/DCL/Components/Avatar/AvatarSceneEmoteHandler.cs index f8c604af0e..3cb19497c2 100644 --- a/unity-renderer/Assets/Scripts/MainScripts/DCL/Components/Avatar/AvatarSceneEmoteHandler.cs +++ b/unity-renderer/Assets/Scripts/MainScripts/DCL/Components/Avatar/AvatarSceneEmoteHandler.cs @@ -14,15 +14,17 @@ public class AvatarSceneEmoteHandler { private readonly IAvatarEmotesController emotesController; private readonly IEmotesService emotesService; + private readonly IUserProfileBridge userProfileBridge; private readonly HashSet equippedEmotes; private long lamportTimestamp; internal CancellationTokenSource cts; - public AvatarSceneEmoteHandler(IAvatarEmotesController emotesController, IEmotesService emotesService) + public AvatarSceneEmoteHandler(IAvatarEmotesController emotesController, IEmotesService emotesService, IUserProfileBridge userProfileBridge) { this.emotesController = emotesController; this.emotesService = emotesService; + this.userProfileBridge = userProfileBridge; this.equippedEmotes = new HashSet(); } @@ -51,7 +53,10 @@ public async UniTask LoadAndPlayEmote(string bodyShapeId, string emoteId) //avoid playing emote if timestamp has change, //meaning a new emote was trigger while this one was loading if (timestamp == lamportTimestamp) + { emotesController.PlayEmote(emoteId, lamportTimestamp); + userProfileBridge.GetOwn().SetAvatarExpression(emoteId, UserProfile.EmoteSource.EmoteLoop, true); + } } catch (OperationCanceledException) { } catch (Exception e) { Debug.LogException(e); } diff --git a/unity-renderer/Assets/Scripts/MainScripts/DCL/Components/Avatar/AvatarShape.cs b/unity-renderer/Assets/Scripts/MainScripts/DCL/Components/Avatar/AvatarShape.cs index 72ef584dae..8a3362a82d 100644 --- a/unity-renderer/Assets/Scripts/MainScripts/DCL/Components/Avatar/AvatarShape.cs +++ b/unity-renderer/Assets/Scripts/MainScripts/DCL/Components/Avatar/AvatarShape.cs @@ -75,7 +75,11 @@ private void Awake() avatar = GetStandardAvatar(); emotesController = avatar.GetEmotesController(); - sceneEmoteHandler = new AvatarSceneEmoteHandler(emotesController, Environment.i.serviceLocator.Get()); + + sceneEmoteHandler = new AvatarSceneEmoteHandler( + emotesController, + Environment.i.serviceLocator.Get(), + new UserProfileWebInterfaceBridge()); if (avatarReporterController == null) { @@ -237,15 +241,10 @@ public override IEnumerator ApplyChanges(BaseModel newModel) sceneEmoteHandler.SetExpressionLamportTimestamp(model.expressionTriggerTimestamp); if (sceneEmoteHandler.IsSceneEmote(model.expressionTriggerId)) - { sceneEmoteHandler .LoadAndPlayEmote(model.bodyShape, model.expressionTriggerId) .Forget(); - } - else - { - emotesController.PlayEmote(model.expressionTriggerId, model.expressionTriggerTimestamp); - } + else { avatar.GetEmotesController().PlayEmote(model.expressionTriggerId, model.expressionTriggerTimestamp); } onPointerDown.OnPointerDownReport -= PlayerClicked; onPointerDown.OnPointerDownReport += PlayerClicked; diff --git a/unity-renderer/Assets/Scripts/MainScripts/DCL/Components/Avatar/AvatarShape.prefab b/unity-renderer/Assets/Scripts/MainScripts/DCL/Components/Avatar/AvatarShape.prefab index 2b514693df..f3fd6050eb 100644 --- a/unity-renderer/Assets/Scripts/MainScripts/DCL/Components/Avatar/AvatarShape.prefab +++ b/unity-renderer/Assets/Scripts/MainScripts/DCL/Components/Avatar/AvatarShape.prefab @@ -23,13 +23,13 @@ Transform: m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} m_GameObject: {fileID: 2845307395157887310} + serializedVersion: 2 m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} m_LocalPosition: {x: 0, y: 0, z: 0} m_LocalScale: {x: 1, y: 1, z: 1} m_ConstrainProportionsScale: 0 m_Children: [] m_Father: {fileID: 4675848658069725358} - m_RootOrder: 2 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} --- !u!1 &3389185268529299172 GameObject: @@ -56,6 +56,7 @@ Transform: m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} m_GameObject: {fileID: 3389185268529299172} + serializedVersion: 2 m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} m_LocalPosition: {x: 0, y: 0, z: 0} m_LocalScale: {x: 1, y: 1, z: 1} @@ -67,7 +68,6 @@ Transform: - {fileID: 3553539495342899975} - {fileID: 7911633839330093525} m_Father: {fileID: 0} - m_RootOrder: 0 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} --- !u!114 &5523974814614327640 MonoBehaviour: @@ -129,6 +129,7 @@ Transform: m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} m_GameObject: {fileID: 5582000225371496597} + serializedVersion: 2 m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} m_LocalPosition: {x: 0, y: 0, z: 0} m_LocalScale: {x: 1, y: 1, z: 1} @@ -138,7 +139,6 @@ Transform: - {fileID: 80406326182283783} - {fileID: 3217162014015595625} m_Father: {fileID: 2842120016485600253} - m_RootOrder: 2 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} --- !u!114 &6790643881566083082 MonoBehaviour: @@ -166,8 +166,8 @@ MonoBehaviour: fall: {fileID: 7400000, guid: cd48d8cde6039fa4fac548ddab2ff277, type: 2} animation: {fileID: 0} blackboard: - walkSpeedFactor: 0.5 - runSpeedFactor: 0.25 + walkSpeedFactor: 0.3 + runSpeedFactor: 0.15 movementSpeed: 0 verticalSpeed: 0 isGrounded: 1 @@ -211,13 +211,13 @@ Transform: m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} m_GameObject: {fileID: 5716359333359460297} + serializedVersion: 2 m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} m_LocalPosition: {x: 0, y: 0, z: 0} m_LocalScale: {x: 1, y: 1, z: 1} m_ConstrainProportionsScale: 0 m_Children: [] m_Father: {fileID: 2842120016485600253} - m_RootOrder: 3 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} --- !u!1 &5854254909640412467 GameObject: @@ -245,13 +245,13 @@ Transform: m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} m_GameObject: {fileID: 5854254909640412467} + serializedVersion: 2 m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} m_LocalPosition: {x: 0, y: 1.8, z: 0} m_LocalScale: {x: 0.5, y: 1.8, z: 0.5} m_ConstrainProportionsScale: 0 m_Children: [] m_Father: {fileID: 2842120016485600253} - m_RootOrder: 0 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} --- !u!114 &3865137627712764486 MonoBehaviour: @@ -274,9 +274,17 @@ BoxCollider: m_PrefabAsset: {fileID: 0} m_GameObject: {fileID: 5854254909640412467} m_Material: {fileID: 0} + m_IncludeLayers: + serializedVersion: 2 + m_Bits: 0 + m_ExcludeLayers: + serializedVersion: 2 + m_Bits: 0 + m_LayerOverridePriority: 0 m_IsTrigger: 1 + m_ProvidesContacts: 0 m_Enabled: 0 - serializedVersion: 2 + serializedVersion: 3 m_Size: {x: 1, y: 1, z: 1} m_Center: {x: 0, y: 0, z: 0} --- !u!114 &1771187575892058067 @@ -314,13 +322,13 @@ Transform: m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} m_GameObject: {fileID: 6448032256406529926} + serializedVersion: 2 m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} m_LocalPosition: {x: 0, y: 0.755, z: 0} m_LocalScale: {x: 1, y: 1, z: 1} m_ConstrainProportionsScale: 0 m_Children: [] m_Father: {fileID: 4675848658069725358} - m_RootOrder: 0 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} --- !u!1 &7213221244455466960 GameObject: @@ -345,6 +353,7 @@ Transform: m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} m_GameObject: {fileID: 7213221244455466960} + serializedVersion: 2 m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} m_LocalPosition: {x: 0, y: 0, z: 0} m_LocalScale: {x: 1, y: 1, z: 1} @@ -352,7 +361,6 @@ Transform: m_Children: - {fileID: 4161845772322530390} m_Father: {fileID: 2842120016485600253} - m_RootOrder: 4 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} --- !u!1 &9158508182074433445 GameObject: @@ -378,13 +386,13 @@ Transform: m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} m_GameObject: {fileID: 9158508182074433445} + serializedVersion: 2 m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} m_LocalPosition: {x: 0, y: 1.8, z: 0} m_LocalScale: {x: 0.5, y: 1.8, z: 0.5} m_ConstrainProportionsScale: 0 m_Children: [] m_Father: {fileID: 2842120016485600253} - m_RootOrder: 1 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} --- !u!65 &7755590202629118220 BoxCollider: @@ -394,9 +402,17 @@ BoxCollider: m_PrefabAsset: {fileID: 0} m_GameObject: {fileID: 9158508182074433445} m_Material: {fileID: 0} + m_IncludeLayers: + serializedVersion: 2 + m_Bits: 0 + m_ExcludeLayers: + serializedVersion: 2 + m_Bits: 0 + m_LayerOverridePriority: 0 m_IsTrigger: 1 + m_ProvidesContacts: 0 m_Enabled: 1 - serializedVersion: 2 + serializedVersion: 3 m_Size: {x: 1, y: 1, z: 1} m_Center: {x: 0, y: 0, z: 0} --- !u!1001 &5777784746421811190 @@ -404,6 +420,7 @@ PrefabInstance: m_ObjectHideFlags: 0 serializedVersion: 2 m_Modification: + serializedVersion: 3 m_TransformParent: {fileID: 4675848658069725358} m_Modifications: - target: {fileID: 1933068967218137769, guid: 256ca49022c0ba84abc2a941931ee350, @@ -482,6 +499,9 @@ PrefabInstance: value: 0 objectReference: {fileID: 0} m_RemovedComponents: [] + m_RemovedGameObjects: [] + m_AddedGameObjects: [] + m_AddedComponents: [] m_SourcePrefab: {fileID: 100100000, guid: 256ca49022c0ba84abc2a941931ee350, type: 3} --- !u!4 &80406326182283783 stripped Transform: @@ -494,6 +514,7 @@ PrefabInstance: m_ObjectHideFlags: 0 serializedVersion: 2 m_Modification: + serializedVersion: 3 m_TransformParent: {fileID: 7911633839330093525} m_Modifications: - target: {fileID: 2343377230149098635, guid: c53ec74589327644bba45b4054fb78dc, @@ -567,6 +588,9 @@ PrefabInstance: value: 0 objectReference: {fileID: 0} m_RemovedComponents: [] + m_RemovedGameObjects: [] + m_AddedGameObjects: [] + m_AddedComponents: [] m_SourcePrefab: {fileID: 100100000, guid: c53ec74589327644bba45b4054fb78dc, type: 3} --- !u!4 &4161845772322530390 stripped Transform: diff --git a/unity-renderer/Assets/Scripts/MainScripts/DCL/Components/Avatar/Tests/AvatarSceneEmoteHandlerShould.cs b/unity-renderer/Assets/Scripts/MainScripts/DCL/Components/Avatar/Tests/AvatarSceneEmoteHandlerShould.cs index e0808939b7..b1dfef081d 100644 --- a/unity-renderer/Assets/Scripts/MainScripts/DCL/Components/Avatar/Tests/AvatarSceneEmoteHandlerShould.cs +++ b/unity-renderer/Assets/Scripts/MainScripts/DCL/Components/Avatar/Tests/AvatarSceneEmoteHandlerShould.cs @@ -16,13 +16,15 @@ public class AvatarSceneEmoteHandlerShould private AvatarSceneEmoteHandler handler; private IAvatarEmotesController emotesController; private IEmotesService emotesService; + private IUserProfileBridge userProfileBridge; [SetUp] public void SetUp() { emotesService = Substitute.For(); emotesController = Substitute.For(); - handler = new AvatarSceneEmoteHandler(emotesController, emotesService); + userProfileBridge = Substitute.For(); + handler = new AvatarSceneEmoteHandler(emotesController, emotesService, userProfileBridge); } [Test] diff --git a/unity-renderer/Assets/Scripts/MainScripts/DCL/Components/Avatar/Tests/AvatarShapeTests.asmdef b/unity-renderer/Assets/Scripts/MainScripts/DCL/Components/Avatar/Tests/AvatarShapeTests.asmdef index b8c7ef1114..f7abdae82e 100644 --- a/unity-renderer/Assets/Scripts/MainScripts/DCL/Components/Avatar/Tests/AvatarShapeTests.asmdef +++ b/unity-renderer/Assets/Scripts/MainScripts/DCL/Components/Avatar/Tests/AvatarShapeTests.asmdef @@ -40,7 +40,8 @@ "GUID:68069f49d86442cd9618861b4d74b1aa", "GUID:fbcc413e192ef9048811d47ab0aca0c0", "GUID:f51ebe6a0ceec4240a699833d6309b23", - "GUID:0c0c18c12967b3944b844b79c47c2320" + "GUID:0c0c18c12967b3944b844b79c47c2320", + "GUID:1de3566cccb280f4a982c59ad0d08c96" ], "includePlatforms": [ "Editor" diff --git a/unity-renderer/Assets/Scripts/MainScripts/DCL/Controllers/CharacterController/DCLCharacterController.cs b/unity-renderer/Assets/Scripts/MainScripts/DCL/Controllers/CharacterController/DCLCharacterController.cs index a4d465dbf9..aeb35ca9f2 100644 --- a/unity-renderer/Assets/Scripts/MainScripts/DCL/Controllers/CharacterController/DCLCharacterController.cs +++ b/unity-renderer/Assets/Scripts/MainScripts/DCL/Controllers/CharacterController/DCLCharacterController.cs @@ -1,8 +1,11 @@ +using Cinemachine; using DCL; using DCL.Configuration; using DCL.Helpers; +using DCL.Interface; +using System; using UnityEngine; -using Cinemachine; +using Environment = DCL.Environment; public class DCLCharacterController : MonoBehaviour { @@ -27,13 +30,13 @@ public class DCLCharacterController : MonoBehaviour [Header("Additional Camera Layers")] public LayerMask cameraLayers; - [System.NonSerialized] + [NonSerialized] public bool initialPositionAlreadySet = false; - [System.NonSerialized] + [NonSerialized] public bool characterAlwaysEnabled = true; - [System.NonSerialized] + [NonSerialized] public CharacterController characterController; FreeMovementController freeMovementController; @@ -78,9 +81,9 @@ public class DCLCharacterController : MonoBehaviour private Vector3NullableVariable characterForward => CommonScriptableObjects.characterForward; - public static System.Action OnCharacterMoved; - public static System.Action OnPositionSet; - public event System.Action OnUpdateFinish; + public static Action OnCharacterMoved; + public static Action OnPositionSet; + public event Action OnUpdateFinish; public GameObject avatarGameObject; public GameObject firstPersonCameraGameObject; @@ -96,13 +99,13 @@ public class DCLCharacterController : MonoBehaviour private readonly DataStore_Player dataStorePlayer = DataStore.i.player; - [System.NonSerialized] + [NonSerialized] public float movingPlatformSpeed; private CollisionFlags lastCharacterControllerCollision; - public event System.Action OnJump; - public event System.Action OnHitGround; - public event System.Action OnMoved; + public event Action OnJump; + public event Action OnHitGround; + public event Action OnMoved; public void SetMovementInputToZero() { @@ -143,7 +146,7 @@ void Awake() if (avatarGameObject == null || firstPersonCameraGameObject == null) { - throw new System.Exception("Both the avatar and first person camera game objects must be set."); + throw new Exception("Both the avatar and first person camera game objects must be set."); } var worldData = DataStore.i.Get(); @@ -252,7 +255,7 @@ private void Teleport(Vector3 newPosition, Vector3 prevPosition) } } - [System.Obsolete("SetPosition is deprecated, please use Teleport instead.", true)] + [Obsolete("SetPosition is deprecated, please use Teleport instead.", true)] public void SetPosition(string positionVector) { Teleport(positionVector); } public void SetEnabled(bool enabled) { this.enabled = enabled; } @@ -551,7 +554,7 @@ public static bool CastGroundCheckingRay(Vector3 origin, out RaycastHit hitInfo, return result; } - void ReportMovement() + public void ReportMovement() { var reportPosition = characterPosition.worldPosition; var compositeRotation = Quaternion.LookRotation(characterForward.HasValue() ? characterForward.Get().Value : cameraForward.Get()); @@ -564,7 +567,7 @@ void ReportMovement() // - Scenes not being sent for loading, making ActivateRenderer never being sent, only in WSS mode. // - Random teleports to 0,0 or other positions that shouldn't happen. if (initialPositionAlreadySet) - DCL.Interface.WebInterface.ReportPosition(reportPosition, compositeRotation, characterController.height, cameraRotation); + WebInterface.ReportPosition(reportPosition, compositeRotation, characterController.height, cameraRotation); lastMovementReportTime = DCLTime.realtimeSinceStartup; } diff --git a/unity-renderer/Assets/Scripts/MainScripts/DCL/Controllers/HUD/CharacterPreview/CharacterPreviewController.cs b/unity-renderer/Assets/Scripts/MainScripts/DCL/Controllers/HUD/CharacterPreview/CharacterPreviewController.cs index bccf072f7b..69c9bc6bfc 100644 --- a/unity-renderer/Assets/Scripts/MainScripts/DCL/Controllers/HUD/CharacterPreview/CharacterPreviewController.cs +++ b/unity-renderer/Assets/Scripts/MainScripts/DCL/Controllers/HUD/CharacterPreview/CharacterPreviewController.cs @@ -1,19 +1,16 @@ using AvatarSystem; using Cysharp.Threading.Tasks; using DCL; -using DCL.Emotes; -using MainScripts.DCL.Components.Avatar.VRMExporter; using System; using System.Collections; using System.Collections.Generic; using System.Linq; using System.Threading; +using UnityEngine; using Environment = DCL.Environment; namespace MainScripts.DCL.Controllers.HUD.CharacterPreview { - using UnityEngine; - public class CharacterPreviewController : MonoBehaviour, ICharacterPreviewController { private const int SNAPSHOT_BODY_WIDTH_RES = 256; @@ -142,7 +139,7 @@ private async UniTask UpdateModelAsync(AvatarModel newModel, CancellationToken c public async UniTask TakeBodySnapshotAsync() { - global::DCL.Environment.i.platform.cullingController.Stop(); + Environment.i.platform.cullingController.Stop(); if (avatar.status != IAvatar.Status.Loaded) return null; @@ -159,7 +156,7 @@ public async UniTask TakeBodySnapshotAsync() SetFocus(PreviewCameraFocus.DefaultEditing, false); cameraController.SetTargetTexture(current); - global::DCL.Environment.i.platform.cullingController.Start(); + Environment.i.platform.cullingController.Start(); return body; } @@ -177,7 +174,7 @@ public void TakeSnapshots(OnSnapshotsReady onSuccess, Action onFailed) private IEnumerator TakeSnapshots_Routine(OnSnapshotsReady callback) { - global::DCL.Environment.i.platform.cullingController.Stop(); + Environment.i.platform.cullingController.Stop(); var current = cameraController.CurrentTargetTexture; cameraController.SetTargetTexture(null); @@ -197,7 +194,7 @@ private IEnumerator TakeSnapshots_Routine(OnSnapshotsReady callback) cameraController.SetTargetTexture(current); - global::DCL.Environment.i.platform.cullingController.Start(); + Environment.i.platform.cullingController.Start(); callback?.Invoke(face256, body); } @@ -232,7 +229,7 @@ public void PlayEmote(string emoteId, long timestamp) public void StopEmote() { - avatar.GetEmotesController().StopEmote(); + avatar.GetEmotesController().StopEmote(true); } public void Dispose() => diff --git a/unity-renderer/Assets/Scripts/MainScripts/DCL/UserProfile/UserProfile.cs b/unity-renderer/Assets/Scripts/MainScripts/DCL/UserProfile/UserProfile.cs index 034351b526..bbd33b77ee 100644 --- a/unity-renderer/Assets/Scripts/MainScripts/DCL/UserProfile/UserProfile.cs +++ b/unity-renderer/Assets/Scripts/MainScripts/DCL/UserProfile/UserProfile.cs @@ -19,6 +19,7 @@ public enum EmoteSource Command, Backpack, EmoteLoop, + EmoteCancel, } private const string FALLBACK_NAME = "fallback"; From b9650b1e8f6d0149dec276fe353584fe7aac2c25 Mon Sep 17 00:00:00 2001 From: Santi Andrade Date: Mon, 13 Nov 2023 13:33:44 +0100 Subject: [PATCH 2/7] =?UTF-8?q?fix:=20backpack=20is=20always=20playing=20t?= =?UTF-8?q?he=20last=20emote=20when=20it=E2=80=99s=20open=20(#5920)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Refresh only the emotes grid when we set the emotes --- .../EmotesCustomizationComponentController.cs | 2 +- .../EmotesCustomization/EmotesCustomizationComponentView.cs | 3 +++ .../EmotesCustomization/IEmotesCustomizationComponentView.cs | 2 ++ 3 files changed, 6 insertions(+), 1 deletion(-) diff --git a/unity-renderer/Assets/Scripts/MainScripts/DCL/Controllers/HUD/AvatarEditorHUD/Scripts/EmotesCustomization/EmotesCustomizationComponentController.cs b/unity-renderer/Assets/Scripts/MainScripts/DCL/Controllers/HUD/AvatarEditorHUD/Scripts/EmotesCustomization/EmotesCustomizationComponentController.cs index dba5b5b586..6ae6ab15e0 100644 --- a/unity-renderer/Assets/Scripts/MainScripts/DCL/Controllers/HUD/AvatarEditorHUD/Scripts/EmotesCustomization/EmotesCustomizationComponentController.cs +++ b/unity-renderer/Assets/Scripts/MainScripts/DCL/Controllers/HUD/AvatarEditorHUD/Scripts/EmotesCustomization/EmotesCustomizationComponentController.cs @@ -100,7 +100,7 @@ public void SetEmotes(WearableItem[] ownedEmotes) UpdateEmoteSlots(); - view.Refresh(); + view.RefreshEmotesGrid(); } public void SetEquippedBodyShape(string bodyShapeId) diff --git a/unity-renderer/Assets/Scripts/MainScripts/DCL/Controllers/HUD/AvatarEditorHUD/Scripts/EmotesCustomization/EmotesCustomizationComponentView.cs b/unity-renderer/Assets/Scripts/MainScripts/DCL/Controllers/HUD/AvatarEditorHUD/Scripts/EmotesCustomization/EmotesCustomizationComponentView.cs index d030e7477b..9deb1461cf 100644 --- a/unity-renderer/Assets/Scripts/MainScripts/DCL/Controllers/HUD/AvatarEditorHUD/Scripts/EmotesCustomization/EmotesCustomizationComponentView.cs +++ b/unity-renderer/Assets/Scripts/MainScripts/DCL/Controllers/HUD/AvatarEditorHUD/Scripts/EmotesCustomization/EmotesCustomizationComponentView.cs @@ -178,6 +178,9 @@ public void Refresh() RefreshControl(); } + public void RefreshEmotesGrid() => + emotesGrid.RefreshControl(); + internal void ClickOnEmote(string emoteId, string emoteName, int slotNumber, bool isAssignedInSelectedSlot) { if (!isAssignedInSelectedSlot) diff --git a/unity-renderer/Assets/Scripts/MainScripts/DCL/Controllers/HUD/AvatarEditorHUD/Scripts/EmotesCustomization/IEmotesCustomizationComponentView.cs b/unity-renderer/Assets/Scripts/MainScripts/DCL/Controllers/HUD/AvatarEditorHUD/Scripts/EmotesCustomization/IEmotesCustomizationComponentView.cs index e455b4fa4a..2aa32b9846 100644 --- a/unity-renderer/Assets/Scripts/MainScripts/DCL/Controllers/HUD/AvatarEditorHUD/Scripts/EmotesCustomization/IEmotesCustomizationComponentView.cs +++ b/unity-renderer/Assets/Scripts/MainScripts/DCL/Controllers/HUD/AvatarEditorHUD/Scripts/EmotesCustomization/IEmotesCustomizationComponentView.cs @@ -120,5 +120,7 @@ public interface IEmotesCustomizationComponentView EmoteSlotCardComponentView GetSlot(int slotNumber); void Refresh(); + + void RefreshEmotesGrid(); } } From 24cafdd8280db30e1ed78bb9498f65ad01ec0626 Mon Sep 17 00:00:00 2001 From: Santi Andrade Date: Mon, 13 Nov 2023 13:34:38 +0100 Subject: [PATCH 3/7] fix: sometimes the passport doesn't load correctly (#5915) Skip the loading of wearables that could not be resolved --- .../PassportNavigation/PassportNavigationComponentView.cs | 3 +++ .../MainScripts/DCL/Models/AvatarAssets/WearableItem.cs | 3 +++ 2 files changed, 6 insertions(+) diff --git a/unity-renderer/Assets/Scripts/MainScripts/DCL/Controllers/HUD/Passport/Passport/PassportNavigation/PassportNavigationComponentView.cs b/unity-renderer/Assets/Scripts/MainScripts/DCL/Controllers/HUD/Passport/Passport/PassportNavigation/PassportNavigationComponentView.cs index fd9609b043..ac1372cea7 100644 --- a/unity-renderer/Assets/Scripts/MainScripts/DCL/Controllers/HUD/Passport/Passport/PassportNavigation/PassportNavigationComponentView.cs +++ b/unity-renderer/Assets/Scripts/MainScripts/DCL/Controllers/HUD/Passport/Passport/PassportNavigation/PassportNavigationComponentView.cs @@ -332,6 +332,9 @@ public void SetEquippedWearables(WearableItem[] wearables, string bodyShapeId) foreach (var wearable in wearables) { + if (wearable == null) + continue; + if (!hidesList.Contains(wearable.data.category)) { PoolableObject poolableObject = nftIconsEntryPool.Get(); diff --git a/unity-renderer/Assets/Scripts/MainScripts/DCL/Models/AvatarAssets/WearableItem.cs b/unity-renderer/Assets/Scripts/MainScripts/DCL/Models/AvatarAssets/WearableItem.cs index 2d18fbb144..3e4653efc0 100644 --- a/unity-renderer/Assets/Scripts/MainScripts/DCL/Models/AvatarAssets/WearableItem.cs +++ b/unity-renderer/Assets/Scripts/MainScripts/DCL/Models/AvatarAssets/WearableItem.cs @@ -344,6 +344,9 @@ public static HashSet ComposeHiddenCategories(string bodyShapeId, List