< Summary

Class:AvatarSystem.BodyShapeLoader
Assembly:AvatarSystem
File(s):/tmp/workspace/unity-renderer/unity-renderer/Assets/Scripts/MainScripts/DCL/AvatarSystem/Loader/BodyShapeLoader.cs
Covered lines:98
Uncovered lines:23
Coverable lines:121
Total lines:201
Line coverage:80.9% (98 of 121)
Covered branches:0
Total branches:0

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity NPath complexity Sequence coverage
BodyShapeLoader(...)0%110100%
Load()0%11.3810076%
SetBones(...)0%2100%
LoadMouth()0%8.66058.33%
LoadEyebrows()0%8.66058.33%
LoadEyes()0%8.66058.33%
UpdateColors(...)0%770100%
LoadWearable()0%5.395075%
IsValid(...)0%3801900%
DisableFacialRenderers()0%440100%
Dispose()0%990100%

File(s)

/tmp/workspace/unity-renderer/unity-renderer/Assets/Scripts/MainScripts/DCL/AvatarSystem/Loader/BodyShapeLoader.cs

#LineLine coverage
 1using System;
 2using System.Collections.Generic;
 3using System.Linq;
 4using System.Threading;
 5using Cysharp.Threading.Tasks;
 6using DCL;
 7using DCL.Helpers;
 8using UnityEngine;
 9using Object = UnityEngine.Object;
 10
 11namespace AvatarSystem
 12{
 13    public class BodyShapeLoader : IBodyshapeLoader
 14    {
 115        public WearableItem wearable { get; }
 116        public Rendereable rendereable => bodyshapeRetriever?.rendereable;
 017        public IWearableLoader.Status status { get; private set; }
 118        public WearableItem eyes { get; }
 119        public WearableItem eyebrows { get; }
 120        public WearableItem mouth { get; }
 021        public SkinnedMeshRenderer eyesRenderer { get; internal set; }
 022        public SkinnedMeshRenderer eyebrowsRenderer { get; internal set; }
 023        public SkinnedMeshRenderer mouthRenderer { get; internal set; }
 024        public SkinnedMeshRenderer headRenderer { get; private set; }
 025        public SkinnedMeshRenderer feetRenderer { get; private set; }
 026        public SkinnedMeshRenderer upperBodyRenderer { get; private set; }
 027        public SkinnedMeshRenderer lowerBodyRenderer { get; private set; }
 28
 29        internal readonly IWearableRetriever bodyshapeRetriever;
 30        internal readonly IFacialFeatureRetriever eyesRetriever;
 31        internal readonly IFacialFeatureRetriever eyebrowsRetriever;
 32        internal readonly IFacialFeatureRetriever mouthRetriever;
 33
 1234        private readonly Dictionary<SkinnedMeshRenderer, (Transform rootBone, Transform[] bones)> originalBones = new Di
 35
 1236        public BodyShapeLoader(IRetrieverFactory retrieverFactory, WearableItem bodyshape, WearableItem eyes, WearableIt
 37        {
 1238            wearable = bodyshape;
 1239            this.eyes = eyes;
 1240            this.eyebrows = eyebrows;
 1241            this.mouth = mouth;
 42
 1243            bodyshapeRetriever = retrieverFactory.GetWearableRetriever();
 1244            eyesRetriever = retrieverFactory.GetFacialFeatureRetriever();
 1245            eyebrowsRetriever = retrieverFactory.GetFacialFeatureRetriever();
 1246            mouthRetriever = retrieverFactory.GetFacialFeatureRetriever();
 1247        }
 48
 49        public async UniTask Load(GameObject container, AvatarSettings avatarSettings, CancellationToken ct = default)
 50        {
 1051            ct.ThrowIfCancellationRequested();
 52
 53            try
 54            {
 955                if (status == IWearableLoader.Status.Succeeded)
 56                {
 057                    UpdateColors(avatarSettings);
 058                    return;
 59                }
 60
 961                status = IWearableLoader.Status.Idle;
 962                await LoadWearable(container, ct);
 63                // Store the original bones.
 164                originalBones.Clear();
 1665                foreach (SkinnedMeshRenderer skm in bodyshapeRetriever.rendereable.renderers.OfType<SkinnedMeshRenderer>
 66                {
 767                    originalBones[skm] = (skm.rootBone, skm.bones);
 68                }
 69
 170                (headRenderer, upperBodyRenderer, lowerBodyRenderer, feetRenderer, eyesRenderer, eyebrowsRenderer, mouth
 71
 172                await (LoadEyes(ct), LoadEyebrows(ct), LoadMouth(ct));
 73
 174                UpdateColors(avatarSettings);
 175                status = IWearableLoader.Status.Succeeded;
 176            }
 877            catch (Exception)
 78            {
 879                status = IWearableLoader.Status.Failed;
 880                Dispose();
 881                throw;
 82            }
 183        }
 84
 085        public void SetBones(Transform rootBone, Transform[] bones) { AvatarSystemUtils.CopyBones(rootBone, bones, rende
 86
 87        private async UniTask LoadMouth(CancellationToken ct)
 88        {
 189            if (mouth == null) return;
 190            (Texture main, Texture mask) = await mouthRetriever.Retrieve(mouth, wearable.id, ct);
 191            mouthRenderer.material = new Material(Resources.Load<Material>("Mouth Material"));
 192            if (main == null)
 093                throw new Exception($"Couldn't fetch main texture for {mouth.id}");
 194            mouthRenderer.material.SetTexture(ShaderUtils.BaseMap, main);
 195            if (mask != null)
 096                mouthRenderer.material.SetTexture(ShaderUtils.TintMask, mask);
 197        }
 98
 99        private async UniTask LoadEyebrows(CancellationToken ct)
 100        {
 1101            if (eyebrows == null) return;
 1102            (Texture main, Texture mask) = await eyebrowsRetriever.Retrieve(eyebrows, wearable.id, ct);
 1103            eyebrowsRenderer.material = new Material(Resources.Load<Material>("Eyebrow Material"));
 1104            if (main == null)
 0105                throw new Exception($"Couldn't fetch main texture for {eyebrows.id}");
 1106            eyebrowsRenderer.material.SetTexture(ShaderUtils.BaseMap, main);
 1107            if (mask != null)
 0108                eyebrowsRenderer.material.SetTexture(ShaderUtils.BaseMap, mask);
 1109        }
 110
 111        private async UniTask LoadEyes(CancellationToken ct)
 112        {
 1113            if (eyes == null) return;
 1114            (Texture main, Texture mask) = await eyesRetriever.Retrieve(eyes, wearable.id, ct);
 1115            eyesRenderer.material = new Material(Resources.Load<Material>("Eye Material"));
 1116            if (main == null)
 0117                throw new Exception($"Couldn't fetch main texture for {eyes.id}");
 1118            eyesRenderer.material.SetTexture(ShaderUtils.EyesTexture, main);
 1119            if (mask != null)
 0120                eyesRenderer.material.SetTexture(ShaderUtils.IrisMask, mask);
 1121        }
 122
 123        private void UpdateColors(AvatarSettings avatarSettings)
 124        {
 1125            AvatarSystemUtils.PrepareMaterialColors(rendereable, avatarSettings.skinColor, avatarSettings.hairColor);
 1126            eyesRenderer?.material?.SetColor(ShaderUtils.EyeTint, avatarSettings.eyesColor);
 1127            eyebrowsRenderer?.material?.SetColor(ShaderUtils.BaseColor, avatarSettings.hairColor);
 1128            mouthRenderer?.material?.SetColor(ShaderUtils.BaseColor, avatarSettings.skinColor);
 1129        }
 130
 131        private async UniTask<Rendereable> LoadWearable(GameObject container, CancellationToken ct)
 132        {
 9133            ct.ThrowIfCancellationRequested();
 134
 9135            bodyshapeRetriever.Dispose();
 136
 9137            WearableItem.Representation representation = wearable.GetRepresentation(wearable.id);
 9138            if (representation == null)
 0139                throw new Exception("Couldn't find a representation for this bodyshape");
 140
 9141            Rendereable bodyshapeRenderable = await bodyshapeRetriever.Retrieve(container, wearable.GetContentProvider(w
 142
 8143            if (bodyshapeRenderable == null) // fail safe, we shouldnt reach this since .Retrieve should throw if anythi
 7144                throw new Exception("Couldn't load bodyshape");
 145
 1146            return bodyshapeRenderable;
 1147        }
 148
 149        public bool IsValid(WearableItem bodyshape, WearableItem eyebrows, WearableItem eyes, WearableItem mouth)
 150        {
 0151            if (wearable.id != bodyshape?.id) return false;
 0152            if (this.eyebrows?.id != eyebrows?.id) return false;
 0153            if (this.mouth?.id != mouth?.id) return false;
 0154            if (this.eyes?.id != eyes?.id) return false;
 0155            return true;
 156        }
 157
 158        public void DisableFacialRenderers()
 159        {
 1160            if (eyesRenderer != null)
 1161                eyesRenderer.enabled = false;
 1162            if (eyebrowsRenderer != null)
 1163                eyebrowsRenderer.enabled = false;
 1164            if (mouthRenderer != null)
 1165                mouthRenderer.enabled = false;
 1166        }
 167
 168        public void Dispose()
 169        {
 19170            status = IWearableLoader.Status.Idle;
 171
 172            //Restore bones
 52173            foreach ((SkinnedMeshRenderer skm, (Transform rootBone, Transform[] bones)) in originalBones)
 174            {
 7175                skm.rootBone = rootBone;
 7176                skm.bones = bones;
 177            }
 19178            originalBones.Clear();
 179
 19180            bodyshapeRetriever?.Dispose();
 19181            eyesRetriever?.Dispose();
 19182            eyebrowsRetriever?.Dispose();
 19183            mouthRetriever?.Dispose();
 184
 19185            if (eyesRenderer != null)
 2186                Object.Destroy(eyesRenderer.material);
 19187            if (eyebrowsRenderer != null)
 2188                Object.Destroy(eyebrowsRenderer.material);
 19189            if (mouthRenderer != null)
 2190                Object.Destroy(mouthRenderer.material);
 191
 19192            upperBodyRenderer = null;
 19193            lowerBodyRenderer = null;
 19194            feetRenderer = null;
 19195            headRenderer = null;
 19196            eyesRenderer = null;
 19197            eyebrowsRenderer = null;
 19198            mouthRenderer = null;
 19199        }
 200    }
 201}