< 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:246
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;
 4using DCL.Helpers;
 5using UnityEngine;
 6using Object = UnityEngine.Object;
 7
 8public interface IBodyShapeController
 9{
 10    bool isReady { get; }
 11    string bodyShapeId { get; }
 12    void SetupEyes(Material material, Texture texture, Texture mask, Color color);
 13    void SetupEyebrows(Material material, Texture texture, Color color);
 14    void SetupMouth(Material material, Texture texture, Texture mask, Color color);
 15    void SetFacialFeaturesVisible(bool visible, bool updateVisibility = false);
 16}
 17
 18public class BodyShapeController : WearableController, IBodyShapeController
 19{
 020    public string bodyShapeId => wearable.id;
 21    private Transform animationTarget;
 022    private bool facialFeaturesVisible = true;
 023    private HashSet<string> currentHiddenList = new HashSet<string>();
 24    public Transform[] bones;
 25    public Transform rootBone;
 26
 027    private bool lowerBodyActive = true;
 028    private bool upperBodyActive = true;
 029    private bool feetActive = true;
 30
 31    private AvatarAnimationEventHandler animEventHandler;
 32
 033    public BodyShapeController(WearableItem wearableItem) : base(wearableItem) { }
 34
 035    protected BodyShapeController(BodyShapeController original) : base(original)
 36    {
 037        headRenderer = original.headRenderer;
 038        eyebrowsRenderer = original.eyebrowsRenderer;
 039        eyesRenderer = original.eyesRenderer;
 040        mouthRenderer = original.mouthRenderer;
 041        feetRenderer = original.feetRenderer;
 042        upperBodyRenderer = original.upperBodyRenderer;
 043        lowerBodyRenderer = original.lowerBodyRenderer;
 044        bones = original.bones;
 045        rootBone = original.rootBone;
 046        upperBodyActive = original.upperBodyActive;
 047        lowerBodyActive = original.lowerBodyActive;
 048        feetActive = original.feetActive;
 049    }
 50
 51    public override void Load(string bodyShapeId, Transform parent, Action<WearableController> onSuccess, Action<Wearabl
 52    {
 053        animationTarget = parent;
 054        base.Load(bodyShapeId, parent, onSuccess, onFail);
 055    }
 56
 57    public void SetActiveParts(bool lowerBodyActive, bool upperBodyActive, bool feetActive)
 58    {
 059        this.lowerBodyActive = lowerBodyActive;
 060        this.upperBodyActive = upperBodyActive;
 061        this.feetActive = feetActive;
 062    }
 63
 64    public void SetupEyes(Material material, Texture texture, Texture mask, Color color)
 65    {
 066        if (assetContainer == null || assetContainer.transform == null)
 67        {
 068            Debug.LogWarning("Tried to setup eyes when the asset not ready");
 069            return;
 70        }
 71
 072        material.SetTexture(AvatarUtils._EyesTexture, texture);
 073        material.SetTexture(AvatarUtils._IrisMask, mask);
 074        material.SetColor(AvatarUtils._EyeTint, color);
 75
 076        AvatarUtils.MapSharedMaterialsRecursively(assetContainer.transform,
 077            (mat) => material,
 78            "eyes");
 079    }
 80
 81    public void SetupEyebrows(Material material, Texture texture, Color color)
 82    {
 083        if (assetContainer == null || assetContainer.transform == null)
 84        {
 085            Debug.LogWarning("Tried to setup eyebrows when the asset not ready");
 086            return;
 87        }
 88
 089        material.SetTexture(AvatarUtils._BaseMap, texture);
 90
 91        //NOTE(Brian): This isn't an error, we must also apply hair color to this mat
 092        material.SetColor(AvatarUtils._BaseColor, color);
 93
 094        AvatarUtils.MapSharedMaterialsRecursively(assetContainer.transform,
 095            (mat) => material,
 96            "eyebrows");
 097    }
 98
 99    public void SetupMouth(Material material, Texture texture, Texture mask, Color color)
 100    {
 0101        if (assetContainer == null || assetContainer.transform == null)
 102        {
 0103            Debug.LogWarning("Tried to setup mouth when the asset not ready");
 0104            return;
 105        }
 106
 0107        material.SetTexture(AvatarUtils._BaseMap, texture);
 0108        material.SetTexture(AvatarUtils._TintMask, mask);
 109
 110        //NOTE(Brian): This isn't an error, we must also apply skin color to this mat
 0111        material.SetColor(AvatarUtils._BaseColor, color);
 112
 0113        AvatarUtils.MapSharedMaterialsRecursively(assetContainer.transform,
 0114            (mat) => material,
 115            "mouth");
 0116    }
 117
 118    public void SetFacialFeaturesVisible(bool visible, bool updateVisibility = false)
 119    {
 0120        facialFeaturesVisible = visible;
 121
 0122        if ( updateVisibility )
 0123            RefreshFacialFeaturesVisibility();
 0124    }
 125
 126    void RefreshFacialFeaturesVisibility()
 127    {
 0128        bool headIsVisible = !currentHiddenList.Contains(WearableLiterals.Misc.HEAD);
 0129        eyebrowsRenderer.enabled = headIsVisible && facialFeaturesVisible;
 0130        eyesRenderer.enabled = headIsVisible && facialFeaturesVisible;
 0131        mouthRenderer.enabled = headIsVisible && facialFeaturesVisible;
 0132    }
 133
 134    protected override void PrepareWearable(GameObject assetContainer)
 135    {
 0136        Animation animation = null;
 137
 138        //NOTE(Brian): Fix to support hierarchy difference between AssetBundle and GLTF wearables.
 0139        Utils.ForwardTransformChildTraversal<Transform>((x) =>
 140            {
 0141                if (x.name.Contains("Armature"))
 142                {
 0143                    var armatureGO = x.parent;
 0144                    animation = armatureGO.gameObject.GetOrCreateComponent<Animation>();
 0145                    armatureGO.gameObject.GetOrCreateComponent<StickerAnimationListener>();
 0146                    return false; //NOTE(Brian): If we return false the traversal is stopped.
 147                }
 148
 0149                return true;
 150            },
 151            assetContainer.transform);
 152
 153        // BasedOnRenderers only acts on child renderers. As all child renderers are deactivated, this feature doesn't w
 154        //
 155        // Adding the merged avatar as child require toggling the animation enabled state on/off and is delayed by a fra
 156        // So the avatar can be seen as gigantic in this lapse.
 157        //
 158        // TODO(Brian): Find a better way to cull animations
 0159        animation.cullingType = AnimationCullingType.AlwaysAnimate;
 160
 0161        SkinnedMeshRenderer firstRenderer = null;
 0162        foreach (var r in GetRenderers())
 163        {
 0164            string parentName = r.transform.parent.name.ToLower();
 165
 0166            if ( firstRenderer == null )
 0167                firstRenderer = r;
 168
 0169            if (parentName.Contains("ubody"))
 0170                upperBodyRenderer = r;
 0171            else if (parentName.Contains("lbody"))
 0172                lowerBodyRenderer = r;
 0173            else if (parentName.Contains("feet"))
 0174                feetRenderer = r;
 0175            else if (parentName.Contains("head"))
 0176                headRenderer = r;
 0177            else if (parentName.Contains("eyebrows"))
 0178                eyebrowsRenderer = r;
 0179            else if (parentName.Contains("eyes"))
 0180                eyesRenderer = r;
 0181            else if (parentName.Contains("mouth"))
 0182                mouthRenderer = r;
 183        }
 184
 0185        if ( firstRenderer != null )
 186        {
 0187            bones = firstRenderer.bones;
 0188            rootBone = firstRenderer.rootBone;
 189        }
 190
 0191        var animator = animationTarget.GetComponent<AvatarAnimatorLegacy>();
 0192        animator.BindBodyShape(animation, bodyShapeId, animationTarget);
 193
 0194        InitializeAvatarAudioAndParticleHandlers(assetContainer, animation);
 0195    }
 196
 0197    public SkinnedMeshRenderer headRenderer { get; private set; }
 0198    public SkinnedMeshRenderer eyebrowsRenderer { get; private set; }
 0199    public SkinnedMeshRenderer eyesRenderer { get; private set; }
 0200    public SkinnedMeshRenderer mouthRenderer { get; private set; }
 0201    public SkinnedMeshRenderer feetRenderer { get; private set; }
 0202    public SkinnedMeshRenderer upperBodyRenderer { get; private set; }
 0203    public SkinnedMeshRenderer lowerBodyRenderer { get; private set; }
 204
 205    public override void UpdateVisibility(HashSet<string> hiddenList)
 206    {
 0207        currentHiddenList = hiddenList;
 208
 0209        bool headIsVisible = !currentHiddenList.Contains(WearableLiterals.Misc.HEAD);
 210
 0211        headRenderer.enabled = headIsVisible;
 212
 0213        RefreshFacialFeaturesVisibility();
 214
 0215        feetRenderer.enabled = feetActive && !currentHiddenList.Contains(WearableLiterals.Categories.FEET);
 0216        upperBodyRenderer.enabled = upperBodyActive && !currentHiddenList.Contains(WearableLiterals.Categories.UPPER_BOD
 0217        lowerBodyRenderer.enabled = lowerBodyActive && !currentHiddenList.Contains(WearableLiterals.Categories.LOWER_BOD
 0218    }
 219
 220    private void InitializeAvatarAudioAndParticleHandlers(GameObject container, Animation createdAnimation)
 221    {
 222        //NOTE(Mordi): Adds handler for animation events, and passes in the audioContainer for the avatar
 0223        AvatarAnimationEventHandler animationEventHandler = createdAnimation.gameObject.AddComponent<AvatarAnimationEven
 0224        AudioContainer audioContainer = container.transform.parent.parent.GetComponentInChildren<AudioContainer>();
 0225        if (audioContainer != null)
 226        {
 0227            animationEventHandler.Init(audioContainer);
 228
 229            //NOTE(Mordi): If this is a remote avatar, pass the animation component so we can keep track of whether it i
 0230            AvatarAudioHandlerRemote audioHandlerRemote = audioContainer.GetComponent<AvatarAudioHandlerRemote>();
 0231            if (audioHandlerRemote != null)
 232            {
 0233                audioHandlerRemote.Init(createdAnimation.gameObject);
 234            }
 235        }
 236
 0237        animEventHandler = animationEventHandler;
 0238    }
 239
 240    public override void CleanUp()
 241    {
 0242        Object.Destroy(animEventHandler);
 0243        facialFeaturesVisible = true;
 0244        base.CleanUp();
 0245    }
 246}