// Adds or removes a parameter based on the enabled boolean.
        public void UpdateParameter(AnimatorControllerParameter parameter, bool enabled)
        {
            if (parameter.type == AnimatorControllerParameterType.Int || parameter.type == AnimatorControllerParameterType.Float || parameter.type == AnimatorControllerParameterType.Bool)
            {
                List <Parameter> param             = new List <Parameter>(_avatar.expressionParameters.parameters);
                bool             somethingModified = false;
                if (enabled)
                {
                    param.Add(new Parameter
                    {
                        name         = parameter.name,
                        valueType    = AV3ManagerFunctions.GetValueTypeFromAnimatorParameterType(parameter.type),
                        defaultValue = 0,
                        saved        = false
                    });
                    somethingModified = true;
                }
                else
                {
                    for (int i = 0; i < param.Count; i++)
                    {
                        if (!param[i].name.Equals(parameter.name))
                        {
                            continue;
                        }
                        param.RemoveAt(i);
                        somethingModified = true;
                    }
                }

                if (somethingModified)
                {
                    _avatar.expressionParameters.parameters = param.ToArray();
                    foreach (var layer in _layers)
                    {
                        layer.UpdateParameterList();
                    }
                }
                EditorUtility.SetDirty(_avatar.expressionParameters);
            }
            UsedParameterMemory = _avatar.expressionParameters.CalcTotalCost();
        }
        public void CleanupParametersList()
        {
            var syncedParameters = _layers?.SelectMany(x => x.Parameters)
                                   .Where(x => x.Item2)
                                   .Select(x => x.Item1)
                                   .ToArray();

            if (_useDefaultParameters)
            {
                syncedParameters = (syncedParameters ?? Array.Empty <AnimatorControllerParameter>()).Append(new AnimatorControllerParameter {
                    name = "VRCEmote", type = AnimatorControllerParameterType.Int, defaultInt = 0
                })
                                   .Append(new AnimatorControllerParameter {
                    name = "VRCFaceBlendH", type = AnimatorControllerParameterType.Float, defaultFloat = 0
                })
                                   .Append(new AnimatorControllerParameter {
                    name = "VRCFaceBlendV", type = AnimatorControllerParameterType.Float, defaultFloat = 0
                })
                                   .ToArray();
            }

            var param     = new List <Parameter>(_avatar.expressionParameters.parameters);
            var remaining = new List <Parameter>(param);

            bool somethingModified = false;

            foreach (var parameter in param)
            {
                bool toDelete = syncedParameters?.All(syncedParameter => !parameter.name.Equals(syncedParameter.name)) ?? false;

                if (!toDelete)
                {
                    continue;
                }
                remaining.Remove(parameter);
                somethingModified = true;
            }

            foreach (var syncedParameter in syncedParameters)
            {
                bool toAdd = param.All(parameter => !parameter.name.Equals(syncedParameter.name));
                if (!toAdd)
                {
                    continue;
                }
                remaining.Add(new Parameter
                {
                    name         = syncedParameter.name,
                    valueType    = AV3ManagerFunctions.GetValueTypeFromAnimatorParameterType(syncedParameter.type),
                    defaultValue = 0,
                    saved        = false
                });
                somethingModified = true;
            }

            if (!somethingModified)
            {
                return;
            }

            _avatar.expressionParameters.parameters = remaining.ToArray();
            EditorUtility.SetDirty(_avatar.expressionParameters);
            UsedParameterMemory = _avatar.expressionParameters.CalcTotalCost();
        }
        //Draw GUI
        public void OnGUI()
        {
            // Show message if in play mode
            if (EditorApplication.isPlaying)
            {
                GUILayout.Space(10);
                EditorGUILayout.LabelField(Content.PlaymodeError);
                return;
            }

            GUILayout.Space(10);
            EditorGUI.BeginChangeCheck();
            _avatar = (VRCAvatarDescriptor)EditorGUILayout.ObjectField(Content.Avatar, _avatar, typeof(VRCAvatarDescriptor), true);

            if (EditorGUI.EndChangeCheck())
            {
                _showContent = _avatar != null;
                if (_avatar != null)
                {
                    _avatar.customExpressions = true;
                    if (_avatar.expressionParameters == null)
                    {
                        GenerateNewExpressionParametersAsset();
                    }

                    if (_avatar.expressionsMenu == null)
                    {
                        GenerateNewExpressionMenuAsset();
                    }

                    UsedParameterMemory = _avatar.expressionParameters.CalcTotalCost();

                    _useDefaultParameters = _avatar.expressionParameters.FindParameter("VRCEmote") != null ||
                                            _avatar.expressionParameters.FindParameter("VRCFaceBlendH") != null ||
                                            _avatar.expressionParameters.FindParameter("VRCFaceBlendV") != null;

                    RefreshWDState();

                    RebuildLayers();
                }
            }

            if (!_showContent)
            {
                return;
            }

            if (_layers == null)
            {
                RebuildLayers();
            }

            GUILayout.Space(10);

            EditorGUILayout.HelpBox($"Parameters Memory used: {UsedParameterMemory}/{MAX_PARAMETER_COST}.", MessageType.None);
            if (UsedParameterMemory > MAX_PARAMETER_COST)
            {
                EditorGUILayout.HelpBox("You have too many parameters synced, untick the \"sync\" box of some parameters.", MessageType.Error);
            }

            if (_isMixedWriteDefaults)
            {
                EditorGUILayout.HelpBox("You have mixed Write Defaults in your layers, you may experience weird interactions ingame.", MessageType.Warning);
            }

            EditorGUILayout.BeginHorizontal();
            if (GUILayout.Button(Content.WdOff))
            {
                foreach (var layer in _layers.Where(x => !x.Layer.isDefault))
                {
                    AV3ManagerFunctions.SetWriteDefaults(layer.Controller, false);
                }
                RefreshWDState();
            }

            if (GUILayout.Button(Content.WdOn))
            {
                foreach (var layer in _layers.Where(x => !x.Layer.isDefault))
                {
                    AV3ManagerFunctions.SetWriteDefaults(layer.Controller, true);
                }
                RefreshWDState();
            }

            EditorGUILayout.EndHorizontal();

            GUILayout.Space(10);
            _section = (WindowSection)GUILayout.Toolbar((int)_section, Enum.GetNames(typeof(WindowSection)), EditorStyles.toolbarButton, GUI.ToolbarButtonSize.Fixed);

            _mainScrollingPosition = EditorGUILayout.BeginScrollView(_mainScrollingPosition);

            switch (_section)
            {
            case WindowSection.Layers:
            {
                foreach (var l in _layers)
                {
                    GUILayout.Space(l.Index == _avatar.baseAnimationLayers.Length ? 50 : 10);
                    l.DrawLayerOptions();
                }

                break;
            }

            case WindowSection.Parameters:
            {
                DrawParametersTab();
                break;
            }
            }
            EditorGUILayout.EndScrollView();
        }