< 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:218
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
 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;
 4947    private readonly AvatarModel currentAvatarModel = new AvatarModel { wearables = new List<string>() };
 4948    private CancellationTokenSource loadingCts = new CancellationTokenSource();
 49
 50    private void Awake()
 51    {
 4852        cameraFocusLookUp = new Dictionary<CameraFocus, Transform>()
 53        {
 54            { CameraFocus.DefaultEditing, defaultEditingTemplate },
 55            { CameraFocus.FaceEditing, faceEditingTemplate },
 56            { CameraFocus.FaceSnapshot, faceSnapshotTemplate },
 57            { CameraFocus.BodySnapshot, bodySnapshotTemplate },
 58        };
 4859        IAnimator animator = avatarContainer.gameObject.GetComponentInChildren<IAnimator>();
 4860        avatar = new AvatarSystem.Avatar(
 61            new AvatarCurator(new WearableItemResolver(), Environment.i.serviceLocator.Get<IEmotesCatalogService>()),
 62            new Loader(new WearableLoaderFactory(), avatarContainer, new AvatarMeshCombinerHelper()),
 63            animator,
 64            new Visibility(),
 65            new NoLODs(),
 66            new SimpleGPUSkinning(),
 67            new GPUSkinningThrottler(),
 68            new EmoteAnimationEquipper(animator, DataStore.i.emotes)
 69        ) ;
 4870    }
 71
 72    public void UpdateModel(AvatarModel newModel, Action onDone)
 73    {
 074        if (newModel.HaveSameWearablesAndColors(currentAvatarModel))
 75        {
 076            onDone?.Invoke();
 077            return;
 78        }
 79
 080        loadingCts?.Cancel();
 081        loadingCts?.Dispose();
 082        loadingCts = new CancellationTokenSource();
 083        UpdateModelRoutine(newModel, onDone, loadingCts.Token);
 084    }
 85
 86    private void OnDestroy()
 87    {
 4888        loadingCts?.Cancel();
 4889        loadingCts?.Dispose();
 4890        loadingCts = null;
 4891        avatar?.Dispose();
 4892    }
 93
 94    private async UniTaskVoid UpdateModelRoutine(AvatarModel newModel, Action onDone, CancellationToken ct)
 95    {
 096        currentAvatarModel.CopyFrom(newModel);
 97        try
 98        {
 099            ct.ThrowIfCancellationRequested();
 0100            List<string> wearables = new List<string>(newModel.wearables);
 0101            wearables.Add(newModel.bodyShape);
 0102            await avatar.Load(wearables, newModel.emotes.Select(x => x.urn).ToList(), new AvatarSettings
 103            {
 104                bodyshapeId = newModel.bodyShape,
 105                eyesColor = newModel.eyeColor,
 106                hairColor = newModel.hairColor,
 107                skinColor = newModel.skinColor
 108
 109            }, ct);
 0110        }
 0111        catch (OperationCanceledException)
 112        {
 0113            return;
 114        }
 115        catch (Exception e)
 116        {
 0117            Debug.LogException(e);
 0118            return;
 119        }
 0120        onDone?.Invoke();
 0121    }
 122
 123    public void TakeSnapshots(OnSnapshotsReady onSuccess, Action onFailed)
 124    {
 0125        if (avatar.status != IAvatar.Status.Loaded)
 126        {
 0127            onFailed?.Invoke();
 0128            return;
 129        }
 130
 0131        StartCoroutine(TakeSnapshots_Routine(onSuccess));
 0132    }
 133
 134    private IEnumerator TakeSnapshots_Routine(OnSnapshotsReady callback)
 135    {
 0136        DCL.Environment.i.platform.cullingController.Stop();
 137
 0138        var current = camera.targetTexture;
 0139        camera.targetTexture = null;
 0140        var avatarAnimator = avatarContainer.gameObject.GetComponentInChildren<AvatarAnimatorLegacy>();
 141
 0142        SetFocus(CameraFocus.FaceSnapshot, false);
 0143        avatarAnimator.Reset();
 0144        yield return null;
 0145        Texture2D face256 = Snapshot(SNAPSHOT_FACE_256_WIDTH_RES, SNAPSHOT_FACE_256_HEIGHT_RES);
 146
 0147        SetFocus(CameraFocus.BodySnapshot, false);
 0148        avatarAnimator.Reset();
 0149        yield return null;
 0150        Texture2D body = Snapshot(SNAPSHOT_BODY_WIDTH_RES, SNAPSHOT_BODY_HEIGHT_RES);
 151
 0152        SetFocus(CameraFocus.DefaultEditing, false);
 153
 0154        camera.targetTexture = current;
 155
 0156        DCL.Environment.i.platform.cullingController.Start();
 0157        callback?.Invoke(face256, body);
 0158    }
 159
 160    private Texture2D Snapshot(int width, int height)
 161    {
 0162        RenderTexture rt = new RenderTexture(width * SUPERSAMPLING, height * SUPERSAMPLING, 32);
 0163        camera.targetTexture = rt;
 0164        Texture2D screenShot = new Texture2D(rt.width, rt.height, TextureFormat.RGBA32, false);
 0165        camera.Render();
 0166        RenderTexture.active = rt;
 0167        screenShot.ReadPixels(new Rect(0, 0, rt.width, rt.height), 0, 0);
 0168        screenShot.Apply();
 169
 0170        return screenShot;
 171    }
 172
 173    private Coroutine cameraTransitionCoroutine;
 174
 94175    public void SetFocus(CameraFocus focus, bool useTransition = true) { SetFocus(cameraFocusLookUp[focus], useTransitio
 176
 177    private void SetFocus(Transform transform, bool useTransition = true)
 178    {
 47179        if (cameraTransitionCoroutine != null)
 180        {
 0181            StopCoroutine(cameraTransitionCoroutine);
 182        }
 183
 47184        if (useTransition)
 185        {
 47186            cameraTransitionCoroutine = StartCoroutine(CameraTransition(camera.transform.position, transform.position, c
 47187        }
 188        else
 189        {
 0190            var cameraTransform = camera.transform;
 0191            cameraTransform.position = transform.position;
 0192            cameraTransform.rotation = transform.rotation;
 193        }
 0194    }
 195
 196    private IEnumerator CameraTransition(Vector3 initPos, Vector3 endPos, Quaternion initRotation, Quaternion endRotatio
 197    {
 47198        var cameraTransform = camera.transform;
 47199        float currentTime = 0;
 200
 47201        float inverseTime = 1 / time;
 47202        while (currentTime < time)
 203        {
 47204            currentTime = Mathf.Clamp(currentTime + Time.deltaTime, 0, time);
 47205            cameraTransform.position = Vector3.Lerp(initPos, endPos, currentTime * inverseTime);
 47206            cameraTransform.rotation = Quaternion.Lerp(initRotation, endRotation, currentTime * inverseTime);
 47207            yield return null;
 208        }
 209
 0210        cameraTransitionCoroutine = null;
 0211    }
 212
 0213    public void Rotate(float rotationVelocity) { avatarContainer.transform.Rotate(Time.deltaTime * rotationVelocity * Ve
 214
 0215    public AvatarModel GetCurrentModel() { return currentAvatarModel; }
 216
 2217    public void PlayEmote(string emoteId, long timestamp) { avatar.PlayEmote(emoteId, timestamp); }
 218}