< Summary

Class:BodyShapeController
Assembly:AvatarShape
File(s):/tmp/workspace/unity-renderer/unity-renderer/Assets/Scripts/MainScripts/DCL/Components/Avatar/BodyShapeController.cs
Covered lines:0
Uncovered lines:114
Coverable lines:114
Total lines:223
Line coverage:0% (0 of 114)
Covered branches:0
Total branches:0

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity NPath complexity Sequence coverage
BodyShapeController(...)0%2100%
BodyShapeController(...)0%2100%
Load(...)0%2100%
SetActiveParts(...)0%2100%
SetupEyes(...)0%20400%
SetupEyebrows(...)0%20400%
SetAssetRenderersEnabled(...)0%6200%
SetupMouth(...)0%20400%
PrepareWearable(...)0%1321100%
UpdateVisibility(...)0%2100%
InitializeAvatarAudioHandlers(...)0%12300%

File(s)

/tmp/workspace/unity-renderer/unity-renderer/Assets/Scripts/MainScripts/DCL/Components/Avatar/BodyShapeController.cs

#LineLine coverage
 1using System;
 2using System.Collections.Generic;
 3using DCL.Helpers;
 4using UnityEngine;
 5
 6public interface IBodyShapeController
 7{
 8    string bodyShapeId { get; }
 9    void SetupEyes(Material material, Texture texture, Texture mask, Color color);
 10    void SetupEyebrows(Material material, Texture texture, Color color);
 11    void SetupMouth(Material material, Texture texture, Texture mask, Color color);
 12}
 13
 14public class BodyShapeController : WearableController, IBodyShapeController
 15{
 016    public string bodyShapeId => wearable.id;
 17    private Transform animationTarget;
 18
 019    public BodyShapeController(WearableItem wearableItem) : base(wearableItem) { }
 20
 021    protected BodyShapeController(BodyShapeController original) : base(original)
 22    {
 023        headRenderer = original.headRenderer;
 024        eyebrowsRenderer = original.eyebrowsRenderer;
 025        eyesRenderer = original.eyesRenderer;
 026        mouthRenderer = original.mouthRenderer;
 027        feetRenderer = original.feetRenderer;
 028        upperBodyRenderer = original.upperBodyRenderer;
 029        lowerBodyRenderer = original.lowerBodyRenderer;
 030    }
 31
 032    public SkinnedMeshRenderer skinnedMeshRenderer { get; private set; }
 33
 34    public override void Load(string bodyShapeId, Transform parent, Action<WearableController> onSuccess, Action<Wearabl
 35    {
 036        animationTarget = parent;
 037        base.Load(bodyShapeId, parent, onSuccess, onFail);
 038    }
 39
 40    public void SetActiveParts(bool lowerBodyActive, bool upperBodyActive, bool feetActive)
 41    {
 042        lowerBodyRenderer.gameObject.SetActive(lowerBodyActive);
 043        lowerBodyRenderer.enabled = lowerBodyActive;
 44
 045        upperBodyRenderer.gameObject.SetActive(upperBodyActive);
 046        upperBodyRenderer.enabled = upperBodyActive;
 47
 048        feetRenderer.gameObject.SetActive(feetActive);
 049        feetRenderer.enabled = feetActive;
 050    }
 51
 52    public void SetupEyes(Material material, Texture texture, Texture mask, Color color)
 53    {
 054        if (assetContainer?.transform == null)
 55        {
 056            Debug.LogWarning("Tried to setup eyes when the asset not ready");
 057            return;
 58        }
 59
 060        AvatarUtils.MapSharedMaterialsRecursively(assetContainer.transform,
 61            (mat) =>
 62            {
 063                material.SetTexture(AvatarUtils._EyesTexture, texture);
 064                material.SetTexture(AvatarUtils._IrisMask, mask);
 065                material.SetColor(AvatarUtils._EyeTint, color);
 066                return material;
 67            },
 68            "eyes");
 069    }
 70
 71    public void SetupEyebrows(Material material, Texture texture, Color color)
 72    {
 073        if (assetContainer?.transform == null)
 74        {
 075            Debug.LogWarning("Tried to setup eyebrows when the asset not ready");
 076            return;
 77        }
 78
 079        AvatarUtils.MapSharedMaterialsRecursively(assetContainer.transform,
 80            (mat) =>
 81            {
 082                material.SetTexture(AvatarUtils._BaseMap, texture);
 83
 84                //NOTE(Brian): This isn't an error, we must also apply hair color to this mat
 085                material.SetColor(AvatarUtils._BaseColor, color);
 86
 087                return material;
 88            },
 89            "eyebrows");
 090    }
 91
 92    public override void SetAssetRenderersEnabled(bool active)
 93    {
 094        base.SetAssetRenderersEnabled(active);
 095        if (skinnedMeshRenderer != null)
 096            skinnedMeshRenderer.enabled = true;
 097    }
 98
 99    public void SetupMouth(Material material, Texture texture, Texture mask, Color color)
 100    {
 0101        if (assetContainer?.transform == null)
 102        {
 0103            Debug.LogWarning("Tried to setup mouth when the asset not ready");
 0104            return;
 105        }
 106
 0107        AvatarUtils.MapSharedMaterialsRecursively(assetContainer.transform,
 108            (mat) =>
 109            {
 0110                material.SetTexture(AvatarUtils._BaseMap, texture);
 0111                material.SetTexture(AvatarUtils._TintMask, mask);
 112
 113                //NOTE(Brian): This isn't an error, we must also apply skin color to this mat
 0114                material.SetColor(AvatarUtils._BaseColor, color);
 0115                return material;
 116            },
 117            "mouth");
 0118    }
 119
 120    protected override void PrepareWearable(GameObject assetContainer)
 121    {
 0122        Animation animation = null;
 123
 124        //NOTE(Brian): Fix to support hierarchy difference between AssetBundle and GLTF wearables.
 0125        Utils.ForwardTransformChildTraversal<Transform>((x) =>
 126            {
 0127                if (x.name.Contains("Armature"))
 128                {
 0129                    var armatureGO = x.parent;
 0130                    animation = armatureGO.gameObject.GetOrCreateComponent<Animation>();
 0131                    armatureGO.gameObject.GetOrCreateComponent<StickerAnimationListener>();
 0132                    return false; //NOTE(Brian): If we return false the traversal is stopped.
 133                }
 134
 0135                return true;
 136            },
 137            assetContainer.transform);
 138
 0139        animation.cullingType = AnimationCullingType.BasedOnRenderers;
 140
 141        //We create a mock SkinnedMeshRenderer to hold the bones for the animations,
 142        //since any of the others SkinnedMeshRenderers in the bodyshape can be disabled arbitrarily
 0143        SkinnedMeshRenderer[] skinnedMeshRenderersInChild = assetContainer.GetComponentsInChildren<SkinnedMeshRenderer>(
 0144        skinnedMeshRenderer = animation.gameObject.GetOrCreateComponent<SkinnedMeshRenderer>();
 0145        skinnedMeshRenderer.enabled = true;
 0146        foreach (SkinnedMeshRenderer meshRenderer in skinnedMeshRenderersInChild)
 147        {
 0148            if (skinnedMeshRenderer != meshRenderer)
 149            {
 0150                skinnedMeshRenderer.rootBone = meshRenderer.rootBone;
 0151                skinnedMeshRenderer.bones = meshRenderer.bones;
 0152                break;
 153            }
 154        }
 155
 0156        var animator = animationTarget.GetComponent<AvatarAnimatorLegacy>();
 0157        animator.BindBodyShape(animation, bodyShapeId, animationTarget);
 158
 0159        var allRenderers = assetContainer.GetComponentsInChildren<SkinnedMeshRenderer>(true);
 160
 0161        foreach (var r in allRenderers)
 162        {
 0163            string parentName = r.transform.parent.name.ToLower();
 164
 0165            if (parentName.Contains("ubody"))
 0166                upperBodyRenderer = r;
 0167            else if (parentName.Contains("lbody"))
 0168                lowerBodyRenderer = r;
 0169            else if (parentName.Contains("feet"))
 0170                feetRenderer = r;
 0171            else if (parentName.Contains("head"))
 0172                headRenderer = r;
 0173            else if (parentName.Contains("eyebrows"))
 0174                eyebrowsRenderer = r;
 0175            else if (parentName.Contains("eyes"))
 0176                eyesRenderer = r;
 0177            else if (parentName.Contains("mouth"))
 0178                mouthRenderer = r;
 179        }
 180
 0181        InitializeAvatarAudioHandlers(assetContainer, animation);
 0182    }
 183
 0184    public SkinnedMeshRenderer headRenderer { get; private set; }
 0185    public SkinnedMeshRenderer eyebrowsRenderer { get; private set; }
 0186    public SkinnedMeshRenderer eyesRenderer { get; private set; }
 0187    public SkinnedMeshRenderer mouthRenderer { get; private set; }
 0188    public SkinnedMeshRenderer feetRenderer { get; private set; }
 0189    public SkinnedMeshRenderer upperBodyRenderer { get; private set; }
 0190    public SkinnedMeshRenderer lowerBodyRenderer { get; private set; }
 191
 192    public override void UpdateVisibility(HashSet<string> hiddenList)
 193    {
 0194        bool headIsVisible = !hiddenList.Contains(WearableLiterals.Misc.HEAD);
 195
 0196        headRenderer.enabled = headIsVisible;
 0197        eyebrowsRenderer.enabled = headIsVisible;
 0198        eyesRenderer.enabled = headIsVisible;
 0199        mouthRenderer.enabled = headIsVisible;
 200
 0201        feetRenderer.enabled = !hiddenList.Contains(WearableLiterals.Categories.FEET);
 0202        upperBodyRenderer.enabled = !hiddenList.Contains(WearableLiterals.Categories.UPPER_BODY);
 0203        lowerBodyRenderer.enabled = !hiddenList.Contains(WearableLiterals.Categories.LOWER_BODY);
 0204    }
 205
 206    private void InitializeAvatarAudioHandlers(GameObject container, Animation createdAnimation)
 207    {
 208        //NOTE(Mordi): Adds audio handler for animation events, and passes in the audioContainer for the avatar
 0209        AvatarAnimationEventAudioHandler animationEventAudioHandler = createdAnimation.gameObject.AddComponent<AvatarAni
 0210        AudioContainer audioContainer = container.transform.parent.parent.GetComponentInChildren<AudioContainer>();
 0211        if (audioContainer != null)
 212        {
 0213            animationEventAudioHandler.Init(audioContainer);
 214
 215            //NOTE(Mordi): If this is a remote avatar, pass the animation component so we can keep track of whether it i
 0216            AvatarAudioHandlerRemote audioHandlerRemote = audioContainer.GetComponent<AvatarAudioHandlerRemote>();
 0217            if (audioHandlerRemote != null)
 218            {
 0219                audioHandlerRemote.Init(createdAnimation.gameObject);
 220            }
 221        }
 0222    }
 223}