< 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:126
Coverable lines:126
Total lines:244
Line coverage:0% (0 of 126)
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%
InitializeAvatarAudioAndParticleHandlers(...)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
 29    private AvatarAnimationEventHandler animEventHandler;
 30
 031    public BodyShapeController(WearableItem wearableItem) : base(wearableItem) { }
 32
 033    protected BodyShapeController(BodyShapeController original) : base(original)
 34    {
 035        headRenderer = original.headRenderer;
 036        eyebrowsRenderer = original.eyebrowsRenderer;
 037        eyesRenderer = original.eyesRenderer;
 038        mouthRenderer = original.mouthRenderer;
 039        feetRenderer = original.feetRenderer;
 040        upperBodyRenderer = original.upperBodyRenderer;
 041        lowerBodyRenderer = original.lowerBodyRenderer;
 042        bones = original.bones;
 043        rootBone = original.rootBone;
 044        upperBodyActive = original.upperBodyActive;
 045        lowerBodyActive = original.lowerBodyActive;
 046        feetActive = original.feetActive;
 047    }
 48
 49    public override void Load(string bodyShapeId, Transform parent, Action<WearableController> onSuccess, Action<Wearabl
 50    {
 051        animationTarget = parent;
 052        base.Load(bodyShapeId, parent, onSuccess, onFail);
 053    }
 54
 55    public void SetActiveParts(bool lowerBodyActive, bool upperBodyActive, bool feetActive)
 56    {
 057        this.lowerBodyActive = lowerBodyActive;
 058        this.upperBodyActive = upperBodyActive;
 059        this.feetActive = feetActive;
 060    }
 61
 62    public void SetupEyes(Material material, Texture texture, Texture mask, Color color)
 63    {
 064        if (assetContainer == null || assetContainer.transform == null)
 65        {
 066            Debug.LogWarning("Tried to setup eyes when the asset not ready");
 067            return;
 68        }
 69
 070        material.SetTexture(AvatarUtils._EyesTexture, texture);
 071        material.SetTexture(AvatarUtils._IrisMask, mask);
 072        material.SetColor(AvatarUtils._EyeTint, color);
 73
 074        AvatarUtils.MapSharedMaterialsRecursively(assetContainer.transform,
 075            (mat) => material,
 76            "eyes");
 077    }
 78
 79    public void SetupEyebrows(Material material, Texture texture, Color color)
 80    {
 081        if (assetContainer == null || assetContainer.transform == null)
 82        {
 083            Debug.LogWarning("Tried to setup eyebrows when the asset not ready");
 084            return;
 85        }
 86
 087        material.SetTexture(AvatarUtils._BaseMap, texture);
 88
 89        //NOTE(Brian): This isn't an error, we must also apply hair color to this mat
 090        material.SetColor(AvatarUtils._BaseColor, color);
 91
 092        AvatarUtils.MapSharedMaterialsRecursively(assetContainer.transform,
 093            (mat) => material,
 94            "eyebrows");
 095    }
 96
 97    public void SetupMouth(Material material, Texture texture, Texture mask, Color color)
 98    {
 099        if (assetContainer == null || assetContainer.transform == null)
 100        {
 0101            Debug.LogWarning("Tried to setup mouth when the asset not ready");
 0102            return;
 103        }
 104
 0105        material.SetTexture(AvatarUtils._BaseMap, texture);
 0106        material.SetTexture(AvatarUtils._TintMask, mask);
 107
 108        //NOTE(Brian): This isn't an error, we must also apply skin color to this mat
 0109        material.SetColor(AvatarUtils._BaseColor, color);
 110
 0111        AvatarUtils.MapSharedMaterialsRecursively(assetContainer.transform,
 0112            (mat) => material,
 113            "mouth");
 0114    }
 115
 116    public void SetFacialFeaturesVisible(bool visible, bool updateVisibility = false)
 117    {
 0118        facialFeaturesVisible = visible;
 119
 0120        if ( updateVisibility )
 0121            RefreshFacialFeaturesVisibility();
 0122    }
 123
 124    void RefreshFacialFeaturesVisibility()
 125    {
 0126        bool headIsVisible = !currentHiddenList.Contains(WearableLiterals.Misc.HEAD);
 0127        eyebrowsRenderer.enabled = headIsVisible && facialFeaturesVisible;
 0128        eyesRenderer.enabled = headIsVisible && facialFeaturesVisible;
 0129        mouthRenderer.enabled = headIsVisible && facialFeaturesVisible;
 0130    }
 131
 132    protected override void PrepareWearable(GameObject assetContainer)
 133    {
 0134        Animation animation = null;
 135
 136        //NOTE(Brian): Fix to support hierarchy difference between AssetBundle and GLTF wearables.
 0137        Utils.ForwardTransformChildTraversal<Transform>((x) =>
 138            {
 0139                if (x.name.Contains("Armature"))
 140                {
 0141                    var armatureGO = x.parent;
 0142                    animation = armatureGO.gameObject.GetOrCreateComponent<Animation>();
 0143                    armatureGO.gameObject.GetOrCreateComponent<StickerAnimationListener>();
 0144                    return false; //NOTE(Brian): If we return false the traversal is stopped.
 145                }
 146
 0147                return true;
 148            },
 149            assetContainer.transform);
 150
 151        // BasedOnRenderers only acts on child renderers. As all child renderers are deactivated, this feature doesn't w
 152        //
 153        // Adding the merged avatar as child require toggling the animation enabled state on/off and is delayed by a fra
 154        // So the avatar can be seen as gigantic in this lapse.
 155        //
 156        // TODO(Brian): Find a better way to cull animations
 0157        animation.cullingType = AnimationCullingType.AlwaysAnimate;
 158
 0159        SkinnedMeshRenderer firstRenderer = null;
 0160        foreach (var r in GetRenderers())
 161        {
 0162            string parentName = r.transform.parent.name.ToLower();
 163
 0164            if ( firstRenderer == null )
 0165                firstRenderer = r;
 166
 0167            if (parentName.Contains("ubody"))
 0168                upperBodyRenderer = r;
 0169            else if (parentName.Contains("lbody"))
 0170                lowerBodyRenderer = r;
 0171            else if (parentName.Contains("feet"))
 0172                feetRenderer = r;
 0173            else if (parentName.Contains("head"))
 0174                headRenderer = r;
 0175            else if (parentName.Contains("eyebrows"))
 0176                eyebrowsRenderer = r;
 0177            else if (parentName.Contains("eyes"))
 0178                eyesRenderer = r;
 0179            else if (parentName.Contains("mouth"))
 0180                mouthRenderer = r;
 181        }
 182
 0183        if ( firstRenderer != null )
 184        {
 0185            bones = firstRenderer.bones;
 0186            rootBone = firstRenderer.rootBone;
 187        }
 188
 0189        var animator = animationTarget.GetComponent<AvatarAnimatorLegacy>();
 0190        animator.BindBodyShape(animation, bodyShapeId, animationTarget);
 191
 0192        InitializeAvatarAudioAndParticleHandlers(assetContainer, animation);
 0193    }
 194
 0195    public SkinnedMeshRenderer headRenderer { get; private set; }
 0196    public SkinnedMeshRenderer eyebrowsRenderer { get; private set; }
 0197    public SkinnedMeshRenderer eyesRenderer { get; private set; }
 0198    public SkinnedMeshRenderer mouthRenderer { get; private set; }
 0199    public SkinnedMeshRenderer feetRenderer { get; private set; }
 0200    public SkinnedMeshRenderer upperBodyRenderer { get; private set; }
 0201    public SkinnedMeshRenderer lowerBodyRenderer { get; private set; }
 202
 203    public override void UpdateVisibility(HashSet<string> hiddenList)
 204    {
 0205        currentHiddenList = hiddenList;
 206
 0207        bool headIsVisible = !currentHiddenList.Contains(WearableLiterals.Misc.HEAD);
 208
 0209        headRenderer.enabled = headIsVisible;
 210
 0211        RefreshFacialFeaturesVisibility();
 212
 0213        feetRenderer.enabled = feetActive && !currentHiddenList.Contains(WearableLiterals.Categories.FEET);
 0214        upperBodyRenderer.enabled = upperBodyActive && !currentHiddenList.Contains(WearableLiterals.Categories.UPPER_BOD
 0215        lowerBodyRenderer.enabled = lowerBodyActive && !currentHiddenList.Contains(WearableLiterals.Categories.LOWER_BOD
 0216    }
 217
 218    private void InitializeAvatarAudioAndParticleHandlers(GameObject container, Animation createdAnimation)
 219    {
 220        //NOTE(Mordi): Adds handler for animation events, and passes in the audioContainer for the avatar
 0221        AvatarAnimationEventHandler animationEventHandler = createdAnimation.gameObject.AddComponent<AvatarAnimationEven
 0222        AudioContainer audioContainer = container.transform.parent.parent.GetComponentInChildren<AudioContainer>();
 0223        if (audioContainer != null)
 224        {
 0225            animationEventHandler.Init(audioContainer);
 226
 227            //NOTE(Mordi): If this is a remote avatar, pass the animation component so we can keep track of whether it i
 0228            AvatarAudioHandlerRemote audioHandlerRemote = audioContainer.GetComponent<AvatarAudioHandlerRemote>();
 0229            if (audioHandlerRemote != null)
 230            {
 0231                audioHandlerRemote.Init(createdAnimation.gameObject);
 232            }
 233        }
 234
 0235        animEventHandler = animationEventHandler;
 0236    }
 237
 238    public override void CleanUp()
 239    {
 0240        UnityEngine.Object.Destroy(animEventHandler);
 0241        facialFeaturesVisible = true;
 0242        base.CleanUp();
 0243    }
 244}