< Summary

Class:MainScripts.DCL.Controllers.HUD.CharacterPreview.CharacterPreviewController
Assembly:CharacterPreviewController
File(s):/tmp/workspace/unity-renderer/unity-renderer/Assets/Scripts/MainScripts/DCL/Controllers/HUD/CharacterPreview/CharacterPreviewController.cs
Covered lines:2
Uncovered lines:91
Coverable lines:93
Total lines:238
Line coverage:2.1% (2 of 93)
Covered branches:0
Total branches:0
Covered methods:1
Total methods:24
Method coverage:4.1% (1 of 24)

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity NPath complexity Sequence coverage
CharacterPreviewController()0%110100%
Awake()0%2100%
SetEnabled(...)0%2100%
Initialize(...)0%20400%
TryUpdateModelAsync()0%72800%
OnDestroy()0%20400%
CreateAvatar()0%2100%
CreateAvatarWithHologram()0%6200%
UpdateModelAsync()0%56700%
TakeBodySnapshotAsync()0%20400%
TakeSnapshots(...)0%12300%
TakeSnapshots_Routine()0%30500%
SetFocus(...)0%2100%
Rotate(...)0%2100%
ResetRotation()0%2100%
MoveCamera(...)0%2100%
SetCameraLimits(...)0%2100%
ConfigureZoom(...)0%2100%
SetCharacterShadowActive(...)0%2100%
GetEmotesController()0%2100%
PlayEmote(...)0%2100%
StopEmote()0%2100%
Dispose()0%2100%

File(s)

/tmp/workspace/unity-renderer/unity-renderer/Assets/Scripts/MainScripts/DCL/Controllers/HUD/CharacterPreview/CharacterPreviewController.cs

#LineLine coverage
 1using AvatarSystem;
 2using Cysharp.Threading.Tasks;
 3using DCL;
 4using System;
 5using System.Collections;
 6using System.Collections.Generic;
 7using System.Linq;
 8using System.Threading;
 9using UnityEngine;
 10using Environment = DCL.Environment;
 11
 12namespace MainScripts.DCL.Controllers.HUD.CharacterPreview
 13{
 14    public class CharacterPreviewController : MonoBehaviour, ICharacterPreviewController
 15    {
 16        private const int SNAPSHOT_BODY_WIDTH_RES = 256;
 17        private const int SNAPSHOT_BODY_HEIGHT_RES = 512;
 18        private const int SNAPSHOT_FACE_256_WIDTH_RES = 256;
 19        private const int SNAPSHOT_FACE_256_HEIGHT_RES = 256;
 20
 21        public delegate void OnSnapshotsReady(Texture2D face256, Texture2D body);
 022        public IReadOnlyList<SkinnedMeshRenderer> originalVisibleRenderers => avatar?.originalVisibleRenderers;
 23
 24        private Dictionary<PreviewCameraFocus, Transform> cameraFocusLookUp;
 25
 26        [SerializeField] private new Camera camera;
 27        [SerializeField] private Transform defaultEditingTemplate;
 28        [SerializeField] private Transform faceEditingTemplate;
 29        [SerializeField] private Transform faceSnapshotTemplate;
 30        [SerializeField] private Transform bodySnapshotTemplate;
 31        [SerializeField] private Transform previewTemplate;
 32        [SerializeField] private GameObject avatarContainer;
 33        [SerializeField] private Transform baseAvatarContainer;
 34        [SerializeField] private BaseAvatarReferences baseAvatarReferencesPrefab;
 35        [SerializeField] private GameObject avatarShadow;
 36        private Service<IAvatarFactory> avatarFactory;
 37
 38        private IAvatar avatar;
 239        private readonly AvatarModel currentAvatarModel = new () { wearables = new List<string>() };
 240        private CancellationTokenSource loadingCts = new ();
 41        private IAnimator animator;
 42        private Quaternion avatarContainerDefaultRotation;
 43        private Transform cameraTransform;
 44        private IPreviewCameraController cameraController;
 45
 46        private void Awake()
 47        {
 048            cameraFocusLookUp = new Dictionary<PreviewCameraFocus, Transform>()
 49            {
 50                { PreviewCameraFocus.DefaultEditing, defaultEditingTemplate },
 51                { PreviewCameraFocus.FaceEditing, faceEditingTemplate },
 52                { PreviewCameraFocus.FaceSnapshot, faceSnapshotTemplate },
 53                { PreviewCameraFocus.BodySnapshot, bodySnapshotTemplate },
 54                { PreviewCameraFocus.Preview, previewTemplate }
 55            };
 56
 057            this.animator = GetComponentInChildren<IAnimator>();
 058            avatarContainerDefaultRotation = avatarContainer.transform.rotation;
 059        }
 60
 61        public void SetEnabled(bool isEnabled)
 62        {
 063            gameObject.SetActive(isEnabled);
 064            cameraController.SetCameraEnabled(isEnabled);
 065            Cursor.SetCursor(null, Vector2.zero, CursorMode.Auto);
 066        }
 67
 68        public void Initialize(
 69            CharacterPreviewMode loadingMode,
 70            RenderTexture targetTexture,
 71            IPreviewCameraController previewCameraController)
 72        {
 073            avatar?.Dispose();
 074            avatar = loadingMode switch
 75                     {
 076                         CharacterPreviewMode.WithHologram => CreateAvatarWithHologram(),
 077                         CharacterPreviewMode.WithoutHologram => CreateAvatar(),
 078                         _ => avatar,
 79                     };
 80
 081            this.cameraController = previewCameraController;
 082            cameraController.SetCamera(camera, targetTexture);
 083        }
 84
 85        public async UniTask TryUpdateModelAsync(AvatarModel newModel, CancellationToken cancellationToken = default)
 86        {
 087            if (newModel.HaveSameWearablesAndColors(currentAvatarModel) && avatar.status == IAvatar.Status.Loaded)
 088                return;
 89
 090            loadingCts?.Cancel();
 091            loadingCts?.Dispose();
 092            loadingCts = new CancellationTokenSource();
 93
 094            cancellationToken = cancellationToken == default
 95                ? loadingCts.Token
 96                : CancellationTokenSource.CreateLinkedTokenSource(loadingCts.Token, cancellationToken).Token;
 97
 098            await UpdateModelAsync(newModel, cancellationToken);
 099        }
 100
 101        private void OnDestroy()
 102        {
 0103            loadingCts?.Cancel();
 0104            loadingCts?.Dispose();
 0105            loadingCts = null;
 0106            avatar?.Dispose();
 0107            cameraController.Dispose();
 0108        }
 109
 110        private IAvatar CreateAvatar() =>
 0111            avatarFactory.Ref.CreateAvatar(avatarContainer, this.animator, NoLODs.i, new Visibility());
 112
 113        private IAvatar CreateAvatarWithHologram()
 114        {
 0115            var baseAvatarReferences = baseAvatarContainer.GetComponentInChildren<IBaseAvatarReferences>() ?? Instantiat
 0116            return avatarFactory.Ref.CreateAvatarWithHologram(avatarContainer, new BaseAvatar(baseAvatarReferences), thi
 117        }
 118
 119        private async UniTask UpdateModelAsync(AvatarModel newModel, CancellationToken ct)
 120        {
 0121            currentAvatarModel.CopyFrom(newModel);
 122
 123            try
 124            {
 0125                ct.ThrowIfCancellationRequested();
 0126                List<string> wearables = new List<string>(newModel.wearables) { newModel.bodyShape };
 127
 0128                await avatar.Load(wearables, newModel.emotes.Select(x => x.urn).ToList(), new AvatarSettings
 129                {
 130                    bodyshapeId = newModel.bodyShape,
 131                    eyesColor = newModel.eyeColor,
 132                    hairColor = newModel.hairColor,
 133                    skinColor = newModel.skinColor,
 134                    forceRender = new HashSet<string>(newModel.forceRender)
 135                }, ct);
 0136            }
 0137            catch (Exception e) when (e is not OperationCanceledException) { Debug.LogException(e); }
 0138        }
 139
 140        public async UniTask<Texture2D> TakeBodySnapshotAsync()
 141        {
 0142            Environment.i.platform.cullingController.Stop();
 0143            if (avatar.status != IAvatar.Status.Loaded)
 0144                return null;
 145
 0146            var current = cameraController.CurrentTargetTexture;
 0147            cameraController.SetTargetTexture(null);
 0148            var avatarAnimator = avatarContainer.gameObject.GetComponentInChildren<AvatarAnimatorLegacy>();
 149
 0150            SetFocus(PreviewCameraFocus.BodySnapshot, false);
 0151            avatarAnimator.Reset();
 0152            await UniTask.Yield();
 153
 0154            Texture2D body = cameraController.TakeSnapshot(SNAPSHOT_BODY_WIDTH_RES, SNAPSHOT_BODY_HEIGHT_RES);
 155
 0156            SetFocus(PreviewCameraFocus.DefaultEditing, false);
 157
 0158            cameraController.SetTargetTexture(current);
 0159            Environment.i.platform.cullingController.Start();
 160
 0161            return body;
 0162        }
 163
 164        public void TakeSnapshots(OnSnapshotsReady onSuccess, Action onFailed)
 165        {
 0166            if (avatar.status != IAvatar.Status.Loaded)
 167            {
 0168                onFailed?.Invoke();
 0169                return;
 170            }
 171
 0172            StartCoroutine(TakeSnapshots_Routine(onSuccess));
 0173        }
 174
 175        private IEnumerator TakeSnapshots_Routine(OnSnapshotsReady callback)
 176        {
 0177            Environment.i.platform.cullingController.Stop();
 178
 0179            var current = cameraController.CurrentTargetTexture;
 0180            cameraController.SetTargetTexture(null);
 0181            var avatarAnimator = avatarContainer.gameObject.GetComponentInChildren<AvatarAnimatorLegacy>();
 182
 0183            SetFocus(PreviewCameraFocus.FaceSnapshot, false);
 0184            avatarAnimator.Reset();
 0185            yield return null;
 0186            Texture2D face256 = cameraController.TakeSnapshot(SNAPSHOT_FACE_256_WIDTH_RES, SNAPSHOT_FACE_256_HEIGHT_RES)
 187
 0188            SetFocus(PreviewCameraFocus.BodySnapshot, false);
 0189            avatarAnimator.Reset();
 0190            yield return null;
 0191            Texture2D body = cameraController.TakeSnapshot(SNAPSHOT_BODY_WIDTH_RES, SNAPSHOT_BODY_HEIGHT_RES);
 192
 0193            SetFocus(PreviewCameraFocus.DefaultEditing, false);
 194
 0195            cameraController.SetTargetTexture(current);
 196
 0197            Environment.i.platform.cullingController.Start();
 0198            callback?.Invoke(face256, body);
 0199        }
 200
 201        public void SetFocus(PreviewCameraFocus focus, bool useTransition = true) =>
 0202            cameraController.SetFocus(cameraFocusLookUp[focus], useTransition);
 203
 204        public void Rotate(float rotationVelocity) =>
 0205            avatarContainer.transform.Rotate(Time.deltaTime * rotationVelocity * Vector3.up);
 206
 207        public void ResetRotation() =>
 0208            avatarContainer.transform.rotation = avatarContainerDefaultRotation;
 209
 210        public void MoveCamera(Vector3 positionDelta, bool changeYLimitsDependingOnZPosition) =>
 0211            cameraController.MoveCamera(positionDelta, changeYLimitsDependingOnZPosition);
 212
 213        public void SetCameraLimits(Bounds limits) =>
 0214            cameraController.SetCameraLimits(limits);
 215
 216        public void ConfigureZoom(float verticalCenterRef, float bottomMaxOffset, float topMaxOffset) =>
 0217            cameraController.ConfigureZoom(verticalCenterRef, bottomMaxOffset, topMaxOffset);
 218
 219        public void SetCharacterShadowActive(bool isActive) =>
 0220            avatarShadow.SetActive(isActive);
 221
 222        public IAvatarEmotesController GetEmotesController() =>
 0223            avatar.GetEmotesController();
 224
 225        public void PlayEmote(string emoteId, long timestamp)
 226        {
 0227            avatar.GetEmotesController().PlayEmote(emoteId, timestamp, false, false, true);
 0228        }
 229
 230        public void StopEmote()
 231        {
 0232            avatar.GetEmotesController().StopEmote(true);
 0233        }
 234
 235        public void Dispose() =>
 0236            Destroy(gameObject);
 237    }
 238}