< 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:239
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    bool isReady { get; }
 9    string bodyShapeId { get; }
 10    void SetupEyes(Material material, Texture texture, Texture mask, Color color);
 11    void SetupEyebrows(Material material, Texture texture, Color color);
 12    void SetupMouth(Material material, Texture texture, Texture mask, Color color);
 13    void SetFacialFeaturesVisible(bool visible, bool updateVisibility = false);
 14}
 15
 16public class BodyShapeController : WearableController, IBodyShapeController
 17{
 018    public string bodyShapeId => wearable.id;
 19    private Transform animationTarget;
 020    private bool facialFeaturesVisible = true;
 021    private HashSet<string> currentHiddenList = new HashSet<string>();
 22    public Transform[] bones;
 23    public Transform rootBone;
 24
 025    private bool lowerBodyActive = true;
 026    private bool upperBodyActive = true;
 027    private bool feetActive = true;
 28
 029    public BodyShapeController(WearableItem wearableItem) : base(wearableItem) { }
 30
 031    protected BodyShapeController(BodyShapeController original) : base(original)
 32    {
 033        headRenderer = original.headRenderer;
 034        eyebrowsRenderer = original.eyebrowsRenderer;
 035        eyesRenderer = original.eyesRenderer;
 036        mouthRenderer = original.mouthRenderer;
 037        feetRenderer = original.feetRenderer;
 038        upperBodyRenderer = original.upperBodyRenderer;
 039        lowerBodyRenderer = original.lowerBodyRenderer;
 040        bones = original.bones;
 041        rootBone = original.rootBone;
 042        upperBodyActive = original.upperBodyActive;
 043        lowerBodyActive = original.lowerBodyActive;
 044        feetActive = original.feetActive;
 045    }
 46
 47    public override void Load(string bodyShapeId, Transform parent, Action<WearableController> onSuccess, Action<Wearabl
 48    {
 049        animationTarget = parent;
 050        base.Load(bodyShapeId, parent, onSuccess, onFail);
 051    }
 52
 53    public void SetActiveParts(bool lowerBodyActive, bool upperBodyActive, bool feetActive)
 54    {
 055        this.lowerBodyActive = lowerBodyActive;
 056        this.upperBodyActive = upperBodyActive;
 057        this.feetActive = feetActive;
 058    }
 59
 60    public void SetupEyes(Material material, Texture texture, Texture mask, Color color)
 61    {
 062        if (assetContainer == null || assetContainer.transform == null)
 63        {
 064            Debug.LogWarning("Tried to setup eyes when the asset not ready");
 065            return;
 66        }
 67
 068        material.SetTexture(AvatarUtils._EyesTexture, texture);
 069        material.SetTexture(AvatarUtils._IrisMask, mask);
 070        material.SetColor(AvatarUtils._EyeTint, color);
 71
 072        AvatarUtils.MapSharedMaterialsRecursively(assetContainer.transform,
 073            (mat) => material,
 74            "eyes");
 075    }
 76
 77    public void SetupEyebrows(Material material, Texture texture, Color color)
 78    {
 079        if (assetContainer == null || assetContainer.transform == null)
 80        {
 081            Debug.LogWarning("Tried to setup eyebrows when the asset not ready");
 082            return;
 83        }
 84
 085        material.SetTexture(AvatarUtils._BaseMap, texture);
 86
 87        //NOTE(Brian): This isn't an error, we must also apply hair color to this mat
 088        material.SetColor(AvatarUtils._BaseColor, color);
 89
 090        AvatarUtils.MapSharedMaterialsRecursively(assetContainer.transform,
 091            (mat) => material,
 92            "eyebrows");
 093    }
 94
 95    public void SetupMouth(Material material, Texture texture, Texture mask, Color color)
 96    {
 097        if (assetContainer == null || assetContainer.transform == null)
 98        {
 099            Debug.LogWarning("Tried to setup mouth when the asset not ready");
 0100            return;
 101        }
 102
 0103        material.SetTexture(AvatarUtils._BaseMap, texture);
 0104        material.SetTexture(AvatarUtils._TintMask, mask);
 105
 106        //NOTE(Brian): This isn't an error, we must also apply skin color to this mat
 0107        material.SetColor(AvatarUtils._BaseColor, color);
 108
 0109        AvatarUtils.MapSharedMaterialsRecursively(assetContainer.transform,
 0110            (mat) => material,
 111            "mouth");
 0112    }
 113
 114    public void SetFacialFeaturesVisible(bool visible, bool updateVisibility = false)
 115    {
 0116        facialFeaturesVisible = visible;
 117
 0118        if ( updateVisibility )
 0119            RefreshFacialFeaturesVisibility();
 0120    }
 121
 122    void RefreshFacialFeaturesVisibility()
 123    {
 0124        bool headIsVisible = !currentHiddenList.Contains(WearableLiterals.Misc.HEAD);
 0125        eyebrowsRenderer.enabled = headIsVisible && facialFeaturesVisible;
 0126        eyesRenderer.enabled = headIsVisible && facialFeaturesVisible;
 0127        mouthRenderer.enabled = headIsVisible && facialFeaturesVisible;
 0128    }
 129
 130    protected override void PrepareWearable(GameObject assetContainer)
 131    {
 0132        Animation animation = null;
 133
 134        //NOTE(Brian): Fix to support hierarchy difference between AssetBundle and GLTF wearables.
 0135        Utils.ForwardTransformChildTraversal<Transform>((x) =>
 136            {
 0137                if (x.name.Contains("Armature"))
 138                {
 0139                    var armatureGO = x.parent;
 0140                    animation = armatureGO.gameObject.GetOrCreateComponent<Animation>();
 0141                    armatureGO.gameObject.GetOrCreateComponent<StickerAnimationListener>();
 0142                    return false; //NOTE(Brian): If we return false the traversal is stopped.
 143                }
 144
 0145                return true;
 146            },
 147            assetContainer.transform);
 148
 149        // BasedOnRenderers only acts on child renderers. As all child renderers are deactivated, this feature doesn't w
 150        //
 151        // Adding the merged avatar as child require toggling the animation enabled state on/off and is delayed by a fra
 152        // So the avatar can be seen as gigantic in this lapse.
 153        //
 154        // TODO(Brian): Find a better way to cull animations
 0155        animation.cullingType = AnimationCullingType.AlwaysAnimate;
 156
 0157        SkinnedMeshRenderer firstRenderer = null;
 0158        foreach (var r in GetRenderers())
 159        {
 0160            string parentName = r.transform.parent.name.ToLower();
 161
 0162            if ( firstRenderer == null )
 0163                firstRenderer = r;
 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        if ( firstRenderer != null )
 182        {
 0183            bones = firstRenderer.bones;
 0184            rootBone = firstRenderer.rootBone;
 185        }
 186
 0187        var animator = animationTarget.GetComponent<AvatarAnimatorLegacy>();
 0188        animator.BindBodyShape(animation, bodyShapeId, animationTarget);
 189
 0190        InitializeAvatarAudioHandlers(assetContainer, animation);
 0191    }
 192
 0193    public SkinnedMeshRenderer headRenderer { get; private set; }
 0194    public SkinnedMeshRenderer eyebrowsRenderer { get; private set; }
 0195    public SkinnedMeshRenderer eyesRenderer { get; private set; }
 0196    public SkinnedMeshRenderer mouthRenderer { get; private set; }
 0197    public SkinnedMeshRenderer feetRenderer { get; private set; }
 0198    public SkinnedMeshRenderer upperBodyRenderer { get; private set; }
 0199    public SkinnedMeshRenderer lowerBodyRenderer { get; private set; }
 200
 201    public override void UpdateVisibility(HashSet<string> hiddenList)
 202    {
 0203        currentHiddenList = hiddenList;
 204
 0205        bool headIsVisible = !currentHiddenList.Contains(WearableLiterals.Misc.HEAD);
 206
 0207        headRenderer.enabled = headIsVisible;
 208
 0209        RefreshFacialFeaturesVisibility();
 210
 0211        feetRenderer.enabled = feetActive && !currentHiddenList.Contains(WearableLiterals.Categories.FEET);
 0212        upperBodyRenderer.enabled = upperBodyActive && !currentHiddenList.Contains(WearableLiterals.Categories.UPPER_BOD
 0213        lowerBodyRenderer.enabled = lowerBodyActive && !currentHiddenList.Contains(WearableLiterals.Categories.LOWER_BOD
 0214    }
 215
 216    private void InitializeAvatarAudioHandlers(GameObject container, Animation createdAnimation)
 217    {
 218        //NOTE(Mordi): Adds audio handler for animation events, and passes in the audioContainer for the avatar
 0219        AvatarAnimationEventAudioHandler animationEventAudioHandler = createdAnimation.gameObject.AddComponent<AvatarAni
 0220        AudioContainer audioContainer = container.transform.parent.parent.GetComponentInChildren<AudioContainer>();
 0221        if (audioContainer != null)
 222        {
 0223            animationEventAudioHandler.Init(audioContainer);
 224
 225            //NOTE(Mordi): If this is a remote avatar, pass the animation component so we can keep track of whether it i
 0226            AvatarAudioHandlerRemote audioHandlerRemote = audioContainer.GetComponent<AvatarAudioHandlerRemote>();
 0227            if (audioHandlerRemote != null)
 228            {
 0229                audioHandlerRemote.Init(createdAnimation.gameObject);
 230            }
 231        }
 0232    }
 233
 234    public override void CleanUp()
 235    {
 0236        facialFeaturesVisible = true;
 0237        base.CleanUp();
 0238    }
 239}