< Summary

Class:CharacterPreviewController
Assembly:AvatarEditorHUD
File(s):/tmp/workspace/unity-renderer/unity-renderer/Assets/Scripts/MainScripts/DCL/Controllers/HUD/AvatarEditorHUD/Scripts/CharacterPreviewController.cs
Covered lines:25
Uncovered lines:59
Coverable lines:84
Total lines:219
Line coverage:29.7% (25 of 84)
Covered branches:0
Total branches:0

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity NPath complexity Sequence coverage
CharacterPreviewController()0%110100%
Awake()0%110100%
UpdateModel(...)0%30500%
OnDestroy()0%440100%
UpdateModelRoutine()0%42600%
TakeSnapshots(...)0%12300%
TakeSnapshots_Routine()0%30500%
Snapshot(...)0%2100%
SetFocus(...)0%110100%
SetFocus(...)0%4.543044.44%
CameraTransition()0%4.134080%
Rotate(...)0%2100%
GetCurrentModel()0%2100%
PlayEmote(...)0%110100%

File(s)

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

#LineLine coverage
 1using System;
 2using System.Collections;
 3using System.Collections.Generic;
 4using System.Linq;
 5using System.Threading;
 6using AvatarSystem;
 7using Cysharp.Threading.Tasks;
 8using DCL;
 9using GPUSkinning;
 10using UnityEngine;
 11using Environment = DCL.Environment;
 12
 13public class CharacterPreviewController : MonoBehaviour, ICharacterPreviewController
 14{
 15    private const int SNAPSHOT_BODY_WIDTH_RES = 256;
 16    private const int SNAPSHOT_BODY_HEIGHT_RES = 512;
 17
 18    private const int SNAPSHOT_FACE_256_WIDTH_RES = 256;
 19    private const int SNAPSHOT_FACE_256_HEIGHT_RES = 256;
 20
 21    private const int SUPERSAMPLING = 1;
 22    private const float CAMERA_TRANSITION_TIME = 0.5f;
 23
 24    public delegate void OnSnapshotsReady(Texture2D face256, Texture2D body);
 25
 26    public enum CameraFocus
 27    {
 28        DefaultEditing,
 29        FaceEditing,
 30        FaceSnapshot,
 31        BodySnapshot
 32    }
 33
 34    private System.Collections.Generic.Dictionary<CameraFocus, Transform> cameraFocusLookUp;
 35
 36    public new Camera camera;
 37
 38    public Transform defaultEditingTemplate;
 39    public Transform faceEditingTemplate;
 40
 41    public Transform faceSnapshotTemplate;
 42    public Transform bodySnapshotTemplate;
 43
 44    [SerializeField] private GameObject avatarContainer;
 45    [SerializeField] private Transform avatarRevealContainer;
 46    private IAvatar avatar;
 5047    private readonly AvatarModel currentAvatarModel = new AvatarModel { wearables = new List<string>() };
 5048    private CancellationTokenSource loadingCts = new CancellationTokenSource();
 49
 50
 51    private void Awake()
 52    {
 4853        cameraFocusLookUp = new Dictionary<CameraFocus, Transform>()
 54        {
 55            { CameraFocus.DefaultEditing, defaultEditingTemplate },
 56            { CameraFocus.FaceEditing, faceEditingTemplate },
 57            { CameraFocus.FaceSnapshot, faceSnapshotTemplate },
 58            { CameraFocus.BodySnapshot, bodySnapshotTemplate },
 59        };
 4860        IAnimator animator = avatarContainer.gameObject.GetComponentInChildren<IAnimator>();
 4861        avatar = new AvatarSystem.Avatar(
 62            new AvatarCurator(new WearableItemResolver(), Environment.i.serviceLocator.Get<IEmotesCatalogService>()),
 63            new Loader(new WearableLoaderFactory(), avatarContainer, new AvatarMeshCombinerHelper()),
 64            animator,
 65            new Visibility(),
 66            new NoLODs(),
 67            new SimpleGPUSkinning(),
 68            new GPUSkinningThrottler(),
 69            new EmoteAnimationEquipper(animator, DataStore.i.emotes)
 70        ) ;
 4871    }
 72
 73    public void UpdateModel(AvatarModel newModel,Action onDone)
 74    {
 075        if (newModel.HaveSameWearablesAndColors(currentAvatarModel))
 76        {
 077            onDone?.Invoke();
 078            return;
 79        }
 80
 081        loadingCts?.Cancel();
 082        loadingCts?.Dispose();
 083        loadingCts = new CancellationTokenSource();
 084        UpdateModelRoutine(newModel, onDone, loadingCts.Token);
 085    }
 86
 87    private void OnDestroy()
 88    {
 4889        loadingCts?.Cancel();
 4890        loadingCts?.Dispose();
 4891        loadingCts = null;
 4892        avatar?.Dispose();
 4893    }
 94
 95    private async UniTaskVoid UpdateModelRoutine(AvatarModel newModel, Action onDone, CancellationToken ct)
 96    {
 097        currentAvatarModel.CopyFrom(newModel);
 98        try
 99        {
 0100            ct.ThrowIfCancellationRequested();
 0101            List<string> wearables = new List<string>(newModel.wearables);
 0102            wearables.Add(newModel.bodyShape);
 0103            await avatar.Load(wearables, newModel.emotes.Select(x => x.urn).ToList(), new AvatarSettings
 104            {
 105                bodyshapeId = newModel.bodyShape,
 106                eyesColor = newModel.eyeColor,
 107                hairColor = newModel.hairColor,
 108                skinColor = newModel.skinColor
 109
 110            }, ct);
 0111        }
 0112        catch (OperationCanceledException)
 113        {
 0114            return;
 115        }
 116        catch (Exception e)
 117        {
 0118            Debug.LogException(e);
 0119            return;
 120        }
 0121        onDone?.Invoke();
 0122    }
 123
 124    public void TakeSnapshots(OnSnapshotsReady onSuccess, Action onFailed)
 125    {
 0126        if (avatar.status != IAvatar.Status.Loaded)
 127        {
 0128            onFailed?.Invoke();
 0129            return;
 130        }
 131
 0132        StartCoroutine(TakeSnapshots_Routine(onSuccess));
 0133    }
 134
 135    private IEnumerator TakeSnapshots_Routine(OnSnapshotsReady callback)
 136    {
 0137        DCL.Environment.i.platform.cullingController.Stop();
 138
 0139        var current = camera.targetTexture;
 0140        camera.targetTexture = null;
 0141        var avatarAnimator = avatarContainer.gameObject.GetComponentInChildren<AvatarAnimatorLegacy>();
 142
 0143        SetFocus(CameraFocus.FaceSnapshot, false);
 0144        avatarAnimator.Reset();
 0145        yield return null;
 0146        Texture2D face256 = Snapshot(SNAPSHOT_FACE_256_WIDTH_RES, SNAPSHOT_FACE_256_HEIGHT_RES);
 147
 0148        SetFocus(CameraFocus.BodySnapshot, false);
 0149        avatarAnimator.Reset();
 0150        yield return null;
 0151        Texture2D body = Snapshot(SNAPSHOT_BODY_WIDTH_RES, SNAPSHOT_BODY_HEIGHT_RES);
 152
 0153        SetFocus(CameraFocus.DefaultEditing, false);
 154
 0155        camera.targetTexture = current;
 156
 0157        DCL.Environment.i.platform.cullingController.Start();
 0158        callback?.Invoke(face256, body);
 0159    }
 160
 161    private Texture2D Snapshot(int width, int height)
 162    {
 0163        RenderTexture rt = new RenderTexture(width * SUPERSAMPLING, height * SUPERSAMPLING, 32);
 0164        camera.targetTexture = rt;
 0165        Texture2D screenShot = new Texture2D(rt.width, rt.height, TextureFormat.RGBA32, false);
 0166        camera.Render();
 0167        RenderTexture.active = rt;
 0168        screenShot.ReadPixels(new Rect(0, 0, rt.width, rt.height), 0, 0);
 0169        screenShot.Apply();
 170
 0171        return screenShot;
 172    }
 173
 174    private Coroutine cameraTransitionCoroutine;
 175
 94176    public void SetFocus(CameraFocus focus, bool useTransition = true) { SetFocus(cameraFocusLookUp[focus], useTransitio
 177
 178    private void SetFocus(Transform transform, bool useTransition = true)
 179    {
 47180        if (cameraTransitionCoroutine != null)
 181        {
 0182            StopCoroutine(cameraTransitionCoroutine);
 183        }
 184
 47185        if (useTransition)
 186        {
 47187            cameraTransitionCoroutine = StartCoroutine(CameraTransition(camera.transform.position, transform.position, c
 47188        }
 189        else
 190        {
 0191            var cameraTransform = camera.transform;
 0192            cameraTransform.position = transform.position;
 0193            cameraTransform.rotation = transform.rotation;
 194        }
 0195    }
 196
 197    private IEnumerator CameraTransition(Vector3 initPos, Vector3 endPos, Quaternion initRotation, Quaternion endRotatio
 198    {
 47199        var cameraTransform = camera.transform;
 47200        float currentTime = 0;
 201
 47202        float inverseTime = 1 / time;
 47203        while (currentTime < time)
 204        {
 47205            currentTime = Mathf.Clamp(currentTime + Time.deltaTime, 0, time);
 47206            cameraTransform.position = Vector3.Lerp(initPos, endPos, currentTime * inverseTime);
 47207            cameraTransform.rotation = Quaternion.Lerp(initRotation, endRotation, currentTime * inverseTime);
 47208            yield return null;
 209        }
 210
 0211        cameraTransitionCoroutine = null;
 0212    }
 213
 0214    public void Rotate(float rotationVelocity) { avatarContainer.transform.Rotate(Time.deltaTime * rotationVelocity * Ve
 215
 0216    public AvatarModel GetCurrentModel() { return currentAvatarModel; }
 217
 2218    public void PlayEmote(string emoteId, long timestamp) { avatar.PlayEmote(emoteId, timestamp); }
 219}