< 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:217
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%30500%
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;
 11
 12public class CharacterPreviewController : MonoBehaviour
 13{
 14    private const int SNAPSHOT_BODY_WIDTH_RES = 256;
 15    private const int SNAPSHOT_BODY_HEIGHT_RES = 512;
 16
 17    private const int SNAPSHOT_FACE_256_WIDTH_RES = 256;
 18    private const int SNAPSHOT_FACE_256_HEIGHT_RES = 256;
 19
 20    private const int SUPERSAMPLING = 1;
 21    private const float CAMERA_TRANSITION_TIME = 0.5f;
 22
 23    public delegate void OnSnapshotsReady(Texture2D face256, Texture2D body);
 24
 25    public enum CameraFocus
 26    {
 27        DefaultEditing,
 28        FaceEditing,
 29        FaceSnapshot,
 30        BodySnapshot
 31    }
 32
 33    private System.Collections.Generic.Dictionary<CameraFocus, Transform> cameraFocusLookUp;
 34
 35    public new Camera camera;
 36
 37    public Transform defaultEditingTemplate;
 38    public Transform faceEditingTemplate;
 39
 40    public Transform faceSnapshotTemplate;
 41    public Transform bodySnapshotTemplate;
 42
 43    [SerializeField] private GameObject avatarContainer;
 44    [SerializeField] private Transform avatarRevealContainer;
 45    private IAvatar avatar;
 4946    private readonly AvatarModel currentAvatarModel = new AvatarModel { wearables = new List<string>() };
 4947    private CancellationTokenSource loadingCts = new CancellationTokenSource();
 48
 49    private void Awake()
 50    {
 4851        cameraFocusLookUp = new Dictionary<CameraFocus, Transform>()
 52        {
 53            { CameraFocus.DefaultEditing, defaultEditingTemplate },
 54            { CameraFocus.FaceEditing, faceEditingTemplate },
 55            { CameraFocus.FaceSnapshot, faceSnapshotTemplate },
 56            { CameraFocus.BodySnapshot, bodySnapshotTemplate },
 57        };
 4858        IAnimator animator = avatarContainer.gameObject.GetComponentInChildren<IAnimator>();
 4859        avatar = new AvatarSystem.Avatar(
 60            new AvatarCurator(new WearableItemResolver()),
 61            new Loader(new WearableLoaderFactory(), avatarContainer, new AvatarMeshCombinerHelper()),
 62            animator,
 63            new Visibility(),
 64            new NoLODs(),
 65            new SimpleGPUSkinning(),
 66            new GPUSkinningThrottler(),
 67            new EmoteAnimationEquipper(animator, DataStore.i.emotes)
 68        ) ;
 4869    }
 70
 71    public void UpdateModel(AvatarModel newModel, Action onDone)
 72    {
 073        if (newModel.HaveSameWearablesAndColors(currentAvatarModel))
 74        {
 075            onDone?.Invoke();
 076            return;
 77        }
 78
 079        loadingCts?.Cancel();
 080        loadingCts?.Dispose();
 081        loadingCts = new CancellationTokenSource();
 082        UpdateModelRoutine(newModel, onDone, loadingCts.Token);
 083    }
 84
 85    private void OnDestroy()
 86    {
 4887        loadingCts?.Cancel();
 4888        loadingCts?.Dispose();
 4889        loadingCts = null;
 4890        avatar?.Dispose();
 4891    }
 92
 93    private async UniTaskVoid UpdateModelRoutine(AvatarModel newModel, Action onDone, CancellationToken ct)
 94    {
 095        currentAvatarModel.CopyFrom(newModel);
 96        try
 97        {
 098            ct.ThrowIfCancellationRequested();
 099            List<string> wearables = new List<string>(newModel.wearables);
 0100            wearables.Add(newModel.bodyShape);
 0101            await avatar.Load(wearables, new AvatarSettings
 102            {
 103                bodyshapeId = newModel.bodyShape,
 104                eyesColor = newModel.eyeColor,
 105                hairColor = newModel.hairColor,
 106                skinColor = newModel.skinColor
 107
 108            }, ct);
 0109        }
 0110        catch (OperationCanceledException)
 111        {
 0112            return;
 113        }
 114        catch (Exception e)
 115        {
 0116            Debug.LogException(e);
 0117            return;
 118        }
 0119        onDone?.Invoke();
 0120    }
 121
 122    public void TakeSnapshots(OnSnapshotsReady onSuccess, Action onFailed)
 123    {
 0124        if (avatar.status != IAvatar.Status.Loaded)
 125        {
 0126            onFailed?.Invoke();
 0127            return;
 128        }
 129
 0130        StartCoroutine(TakeSnapshots_Routine(onSuccess));
 0131    }
 132
 133    private IEnumerator TakeSnapshots_Routine(OnSnapshotsReady callback)
 134    {
 0135        DCL.Environment.i.platform.cullingController.Stop();
 136
 0137        var current = camera.targetTexture;
 0138        camera.targetTexture = null;
 0139        var avatarAnimator = avatarContainer.gameObject.GetComponentInChildren<AvatarAnimatorLegacy>();
 140
 0141        SetFocus(CameraFocus.FaceSnapshot, false);
 0142        avatarAnimator.Reset();
 0143        yield return null;
 0144        Texture2D face256 = Snapshot(SNAPSHOT_FACE_256_WIDTH_RES, SNAPSHOT_FACE_256_HEIGHT_RES);
 145
 0146        SetFocus(CameraFocus.BodySnapshot, false);
 0147        avatarAnimator.Reset();
 0148        yield return null;
 0149        Texture2D body = Snapshot(SNAPSHOT_BODY_WIDTH_RES, SNAPSHOT_BODY_HEIGHT_RES);
 150
 0151        SetFocus(CameraFocus.DefaultEditing, false);
 152
 0153        camera.targetTexture = current;
 154
 0155        DCL.Environment.i.platform.cullingController.Start();
 0156        callback?.Invoke(face256, body);
 0157    }
 158
 159    private Texture2D Snapshot(int width, int height)
 160    {
 0161        RenderTexture rt = new RenderTexture(width * SUPERSAMPLING, height * SUPERSAMPLING, 32);
 0162        camera.targetTexture = rt;
 0163        Texture2D screenShot = new Texture2D(rt.width, rt.height, TextureFormat.RGBA32, false);
 0164        camera.Render();
 0165        RenderTexture.active = rt;
 0166        screenShot.ReadPixels(new Rect(0, 0, rt.width, rt.height), 0, 0);
 0167        screenShot.Apply();
 168
 0169        return screenShot;
 170    }
 171
 172    private Coroutine cameraTransitionCoroutine;
 173
 94174    public void SetFocus(CameraFocus focus, bool useTransition = true) { SetFocus(cameraFocusLookUp[focus], useTransitio
 175
 176    private void SetFocus(Transform transform, bool useTransition = true)
 177    {
 47178        if (cameraTransitionCoroutine != null)
 179        {
 0180            StopCoroutine(cameraTransitionCoroutine);
 181        }
 182
 47183        if (useTransition)
 184        {
 47185            cameraTransitionCoroutine = StartCoroutine(CameraTransition(camera.transform.position, transform.position, c
 47186        }
 187        else
 188        {
 0189            var cameraTransform = camera.transform;
 0190            cameraTransform.position = transform.position;
 0191            cameraTransform.rotation = transform.rotation;
 192        }
 0193    }
 194
 195    private IEnumerator CameraTransition(Vector3 initPos, Vector3 endPos, Quaternion initRotation, Quaternion endRotatio
 196    {
 47197        var cameraTransform = camera.transform;
 47198        float currentTime = 0;
 199
 47200        float inverseTime = 1 / time;
 47201        while (currentTime < time)
 202        {
 47203            currentTime = Mathf.Clamp(currentTime + Time.deltaTime, 0, time);
 47204            cameraTransform.position = Vector3.Lerp(initPos, endPos, currentTime * inverseTime);
 47205            cameraTransform.rotation = Quaternion.Lerp(initRotation, endRotation, currentTime * inverseTime);
 47206            yield return null;
 207        }
 208
 0209        cameraTransitionCoroutine = null;
 0210    }
 211
 0212    public void Rotate(float rotationVelocity) { avatarContainer.transform.Rotate(Time.deltaTime * rotationVelocity * Ve
 213
 0214    public AvatarModel GetCurrentModel() { return currentAvatarModel; }
 215
 2216    public void PlayEmote(string emoteId, long timestamp) { avatar.PlayEmote(emoteId, timestamp); }
 217}