< 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:124
Coverable lines:124
Total lines:238
Line coverage:0% (0 of 124)
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%12300%
SetupEyebrows(...)0%12300%
SetupMouth(...)0%12300%
SetFacialFeaturesVisible(...)0%6200%
RefreshFacialFeaturesVisibility()0%56700%
PrepareWearable(...)0%1561200%
UpdateVisibility(...)0%20400%
InitializeAvatarAudioHandlers(...)0%12300%
CleanUp()0%2100%

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    void SetFacialFeaturesVisible(bool visible, bool updateVisibility = false);
 13}
 14
 15public class BodyShapeController : WearableController, IBodyShapeController
 16{
 017    public string bodyShapeId => wearable.id;
 18    private Transform animationTarget;
 019    private bool facialFeaturesVisible = true;
 020    private HashSet<string> currentHiddenList = new HashSet<string>();
 21    public Transform[] bones;
 22    public Transform rootBone;
 23
 024    private bool lowerBodyActive = true;
 025    private bool upperBodyActive = true;
 026    private bool feetActive = true;
 27
 028    public BodyShapeController(WearableItem wearableItem) : base(wearableItem) { }
 29
 030    protected BodyShapeController(BodyShapeController original) : base(original)
 31    {
 032        headRenderer = original.headRenderer;
 033        eyebrowsRenderer = original.eyebrowsRenderer;
 034        eyesRenderer = original.eyesRenderer;
 035        mouthRenderer = original.mouthRenderer;
 036        feetRenderer = original.feetRenderer;
 037        upperBodyRenderer = original.upperBodyRenderer;
 038        lowerBodyRenderer = original.lowerBodyRenderer;
 039        bones = original.bones;
 040        rootBone = original.rootBone;
 041        upperBodyActive = original.upperBodyActive;
 042        lowerBodyActive = original.lowerBodyActive;
 043        feetActive = original.feetActive;
 044    }
 45
 46    public override void Load(string bodyShapeId, Transform parent, Action<WearableController> onSuccess, Action<Wearabl
 47    {
 048        animationTarget = parent;
 049        base.Load(bodyShapeId, parent, onSuccess, onFail);
 050    }
 51
 52    public void SetActiveParts(bool lowerBodyActive, bool upperBodyActive, bool feetActive)
 53    {
 054        this.lowerBodyActive = lowerBodyActive;
 055        this.upperBodyActive = upperBodyActive;
 056        this.feetActive = feetActive;
 057    }
 58
 59    public void SetupEyes(Material material, Texture texture, Texture mask, Color color)
 60    {
 061        if (assetContainer != null && assetContainer.transform == null)
 62        {
 063            Debug.LogWarning("Tried to setup eyes when the asset not ready");
 064            return;
 65        }
 66
 067        material.SetTexture(AvatarUtils._EyesTexture, texture);
 068        material.SetTexture(AvatarUtils._IrisMask, mask);
 069        material.SetColor(AvatarUtils._EyeTint, color);
 70
 071        AvatarUtils.MapSharedMaterialsRecursively(assetContainer.transform,
 072            (mat) => material,
 73            "eyes");
 074    }
 75
 76    public void SetupEyebrows(Material material, Texture texture, Color color)
 77    {
 078        if (assetContainer != null && assetContainer.transform == null)
 79        {
 080            Debug.LogWarning("Tried to setup eyebrows when the asset not ready");
 081            return;
 82        }
 83
 084        material.SetTexture(AvatarUtils._BaseMap, texture);
 85
 86        //NOTE(Brian): This isn't an error, we must also apply hair color to this mat
 087        material.SetColor(AvatarUtils._BaseColor, color);
 88
 089        AvatarUtils.MapSharedMaterialsRecursively(assetContainer.transform,
 090            (mat) => material,
 91            "eyebrows");
 092    }
 93
 94    public void SetupMouth(Material material, Texture texture, Texture mask, Color color)
 95    {
 096        if (assetContainer != null && assetContainer.transform == null)
 97        {
 098            Debug.LogWarning("Tried to setup mouth when the asset not ready");
 099            return;
 100        }
 101
 0102        material.SetTexture(AvatarUtils._BaseMap, texture);
 0103        material.SetTexture(AvatarUtils._TintMask, mask);
 104
 105        //NOTE(Brian): This isn't an error, we must also apply skin color to this mat
 0106        material.SetColor(AvatarUtils._BaseColor, color);
 107
 0108        AvatarUtils.MapSharedMaterialsRecursively(assetContainer.transform,
 0109            (mat) => material,
 110            "mouth");
 0111    }
 112
 113    public void SetFacialFeaturesVisible(bool visible, bool updateVisibility = false)
 114    {
 0115        facialFeaturesVisible = visible;
 116
 0117        if ( updateVisibility )
 0118            RefreshFacialFeaturesVisibility();
 0119    }
 120
 121    void RefreshFacialFeaturesVisibility()
 122    {
 0123        bool headIsVisible = !currentHiddenList.Contains(WearableLiterals.Misc.HEAD);
 0124        eyebrowsRenderer.enabled = headIsVisible && facialFeaturesVisible;
 0125        eyesRenderer.enabled = headIsVisible && facialFeaturesVisible;
 0126        mouthRenderer.enabled = headIsVisible && facialFeaturesVisible;
 0127    }
 128
 129    protected override void PrepareWearable(GameObject assetContainer)
 130    {
 0131        Animation animation = null;
 132
 133        //NOTE(Brian): Fix to support hierarchy difference between AssetBundle and GLTF wearables.
 0134        Utils.ForwardTransformChildTraversal<Transform>((x) =>
 135            {
 0136                if (x.name.Contains("Armature"))
 137                {
 0138                    var armatureGO = x.parent;
 0139                    animation = armatureGO.gameObject.GetOrCreateComponent<Animation>();
 0140                    armatureGO.gameObject.GetOrCreateComponent<StickerAnimationListener>();
 0141                    return false; //NOTE(Brian): If we return false the traversal is stopped.
 142                }
 143
 0144                return true;
 145            },
 146            assetContainer.transform);
 147
 148        // BasedOnRenderers only acts on child renderers. As all child renderers are deactivated, this feature doesn't w
 149        //
 150        // Adding the merged avatar as child require toggling the animation enabled state on/off and is delayed by a fra
 151        // So the avatar can be seen as gigantic in this lapse.
 152        //
 153        // TODO(Brian): Find a better way to cull animations
 0154        animation.cullingType = AnimationCullingType.AlwaysAnimate;
 155
 0156        SkinnedMeshRenderer firstRenderer = null;
 0157        foreach (var r in GetRenderers())
 158        {
 0159            string parentName = r.transform.parent.name.ToLower();
 160
 0161            if ( firstRenderer == null )
 0162                firstRenderer = r;
 163
 0164            if (parentName.Contains("ubody"))
 0165                upperBodyRenderer = r;
 0166            else if (parentName.Contains("lbody"))
 0167                lowerBodyRenderer = r;
 0168            else if (parentName.Contains("feet"))
 0169                feetRenderer = r;
 0170            else if (parentName.Contains("head"))
 0171                headRenderer = r;
 0172            else if (parentName.Contains("eyebrows"))
 0173                eyebrowsRenderer = r;
 0174            else if (parentName.Contains("eyes"))
 0175                eyesRenderer = r;
 0176            else if (parentName.Contains("mouth"))
 0177                mouthRenderer = r;
 178        }
 179
 0180        if ( firstRenderer != null )
 181        {
 0182            bones = firstRenderer.bones;
 0183            rootBone = firstRenderer.rootBone;
 184        }
 185
 0186        var animator = animationTarget.GetComponent<AvatarAnimatorLegacy>();
 0187        animator.BindBodyShape(animation, bodyShapeId, animationTarget);
 188
 0189        InitializeAvatarAudioHandlers(assetContainer, animation);
 0190    }
 191
 0192    public SkinnedMeshRenderer headRenderer { get; private set; }
 0193    public SkinnedMeshRenderer eyebrowsRenderer { get; private set; }
 0194    public SkinnedMeshRenderer eyesRenderer { get; private set; }
 0195    public SkinnedMeshRenderer mouthRenderer { get; private set; }
 0196    public SkinnedMeshRenderer feetRenderer { get; private set; }
 0197    public SkinnedMeshRenderer upperBodyRenderer { get; private set; }
 0198    public SkinnedMeshRenderer lowerBodyRenderer { get; private set; }
 199
 200    public override void UpdateVisibility(HashSet<string> hiddenList)
 201    {
 0202        currentHiddenList = hiddenList;
 203
 0204        bool headIsVisible = !currentHiddenList.Contains(WearableLiterals.Misc.HEAD);
 205
 0206        headRenderer.enabled = headIsVisible;
 207
 0208        RefreshFacialFeaturesVisibility();
 209
 0210        feetRenderer.enabled = feetActive && !currentHiddenList.Contains(WearableLiterals.Categories.FEET);
 0211        upperBodyRenderer.enabled = upperBodyActive && !currentHiddenList.Contains(WearableLiterals.Categories.UPPER_BOD
 0212        lowerBodyRenderer.enabled = lowerBodyActive && !currentHiddenList.Contains(WearableLiterals.Categories.LOWER_BOD
 0213    }
 214
 215    private void InitializeAvatarAudioHandlers(GameObject container, Animation createdAnimation)
 216    {
 217        //NOTE(Mordi): Adds audio handler for animation events, and passes in the audioContainer for the avatar
 0218        AvatarAnimationEventAudioHandler animationEventAudioHandler = createdAnimation.gameObject.AddComponent<AvatarAni
 0219        AudioContainer audioContainer = container.transform.parent.parent.GetComponentInChildren<AudioContainer>();
 0220        if (audioContainer != null)
 221        {
 0222            animationEventAudioHandler.Init(audioContainer);
 223
 224            //NOTE(Mordi): If this is a remote avatar, pass the animation component so we can keep track of whether it i
 0225            AvatarAudioHandlerRemote audioHandlerRemote = audioContainer.GetComponent<AvatarAudioHandlerRemote>();
 0226            if (audioHandlerRemote != null)
 227            {
 0228                audioHandlerRemote.Init(createdAnimation.gameObject);
 229            }
 230        }
 0231    }
 232
 233    public override void CleanUp()
 234    {
 0235        facialFeaturesVisible = true;
 0236        base.CleanUp();
 0237    }
 238}