<|start_filename|>Assets/Hai/Just1Int7Toggles/Scripts/Editor/Internal/Just1Int7TogglesCompilerInternal.cs<|end_filename|>
﻿using Hai.Just1Int7Toggles.Scripts.Editor.Internal.Reused;
using UnityEditor.Animations;
using UnityEngine;
using static Hai.Just1Int7Toggles.Scripts.Editor.Internal.J1I7TParameters;

namespace Hai.Just1Int7Toggles.Scripts.Editor.Internal
{
    public class Just1Int7TogglesCompilerInternal
    {
        private static readonly string EmptyClipPath = "Assets/Hai/Just1Int7Toggles/Hai_Just1Int7Toggles_EmptyClip.anim";
        private static readonly string PluginFolderName = "Just1Int7Toggles";

        private readonly AnimatorGenerator _animatorGenerator;
        private readonly StatefulEmptyClipProvider _emptyClipProvider;
        private readonly ViewCreator _viewCreator;

        public Just1Int7TogglesCompilerInternal(RuntimeAnimatorController animatorController,
            AnimationClip customEmptyClip, TogglesManifest manifest)
        {
            _emptyClipProvider = new StatefulEmptyClipProvider(new ClipGenerator(customEmptyClip, EmptyClipPath, PluginFolderName));
            _animatorGenerator = new AnimatorGenerator((AnimatorController) animatorController, _emptyClipProvider);
            _viewCreator = new ViewCreator(_animatorGenerator, manifest);
        }

        public void DoOverwriteCommonLogic()
        {
            _emptyClipProvider.Get();

            RemoveLegacyParameters();
            CreateParameters();
            _animatorGenerator.RemoveLayerIfExists("Hai_J1I7T_Controller");
            _animatorGenerator.RemoveLayerIfExists("Hai_J1I7T_TransmitA");
            _animatorGenerator.RemoveLayerIfExists("Hai_J1I7T_TransmitB");
            CreateOrReplaceView();
        }

        private void RemoveLegacyParameters()
        {
            _animatorGenerator.RemoveParamsIndiscriminatelyAsNeeded(
                "J1I7T_A_Sync", "J1I7T_B_Sync",
                "J1I7T_A_0", "J1I7T_A_1", "J1I7T_A_2", "J1I7T_A_3", "J1I7T_A_4", "J1I7T_A_5", "J1I7T_A_6",
                "J1I7T_B_0", "J1I7T_B_1", "J1I7T_B_2", "J1I7T_B_3", "J1I7T_B_4", "J1I7T_B_5", "J1I7T_B_6", "J1I7T_B_7",
                "J1I7T_A_0F", "J1I7T_A_1F", "J1I7T_A_2F", "J1I7T_A_3F", "J1I7T_A_4F", "J1I7T_A_5F", "J1I7T_A_6F",
                "J1I7T_B_0F", "J1I7T_B_1F", "J1I7T_B_2F", "J1I7T_B_3F", "J1I7T_B_4F", "J1I7T_B_5F", "J1I7T_B_6F", "J1I7T_B_7F",
                "J1I7T_A_DirtyCheck", "J1I7T_B_DirtyCheck",
                "J1I7T_Internal_One"
            );
        }

        private void CreateOrReplaceView()
        {
            _viewCreator.CreateOrReplaceView();
        }

        private void CreateParameters()
        {
            _animatorGenerator.CreateParamsAsNeeded(InitializedParameterist);
        }
    }
}


<|start_filename|>Assets/Hai/Just1Int7Toggles/Scripts/Editor/Internal/Reused/HaiAnimatorGen.cs<|end_filename|>
﻿using System.Linq;
using UnityEditor;
using UnityEditor.Animations;
using UnityEngine;

namespace Hai.Just1Int7Toggles.Scripts.Editor.Internal.Reused
{
    internal class AnimatorGenerator
    {
        private readonly AnimatorController _animatorController;
        private readonly StatefulEmptyClipProvider _emptyClipProvider;

        internal AnimatorGenerator(AnimatorController animatorController, StatefulEmptyClipProvider emptyClipProvider)
        {
            _animatorController = animatorController;
            _emptyClipProvider = emptyClipProvider;
        }

        internal void CreateParamsAsNeeded(params Parameterist[] parameterists)
        {
            foreach (var parameterist in parameterists)
            {
                switch (parameterist)
                {
                    case IntParameterist p:
                        CreateParamIfNotExists(parameterist.Name, AnimatorControllerParameterType.Int);
                        break;
                    case FloatParameterist p:
                        CreateParamIfNotExists(parameterist.Name, AnimatorControllerParameterType.Float);
                        break;
                    case BoolParameterist p:
                        CreateParamIfNotExists(parameterist.Name, AnimatorControllerParameterType.Bool);
                        break;
                }
            }
        }

        private void CreateParamIfNotExists(string paramName, AnimatorControllerParameterType type)
        {
            if (_animatorController.parameters.FirstOrDefault(param => param.name == paramName) == null)
            {
                _animatorController.AddParameter(paramName, type);
            }
        }

        internal Machinist CreateOrRemakeLayerAtSameIndex(string layerName, float weightWhenCreating)
        {
            var originalIndexToPreserveOrdering = _animatorController.layers.ToList().FindIndex(layer1 => layer1.name == layerName);
            if (originalIndexToPreserveOrdering != -1)
            {
                _animatorController.RemoveLayer(originalIndexToPreserveOrdering);
            }

            AddLayerWithWeight(layerName, weightWhenCreating);
            if (originalIndexToPreserveOrdering != -1)
            {
                var items = _animatorController.layers.ToList();
                var last = items[items.Count - 1];
                items.RemoveAt(items.Count - 1);
                items.Insert(originalIndexToPreserveOrdering, last);
                _animatorController.layers = items.ToArray();
            }

            var layer = TryGetLayer(layerName);
            var machinist = new Machinist(layer.stateMachine, _emptyClipProvider.Get());
            return machinist
                .WithAnyStatePosition(0, 7)
                .WithEntryPosition(0, -1)
                .WithExitPosition(7, -1);
        }

        private AnimatorControllerLayer TryGetLayer(string layerName)
        {
            return _animatorController.layers.FirstOrDefault(it => it.name == layerName);
        }

        private void AddLayerWithWeight(string layerName, float weightWhenCreating)
        {
            // This function is a replication of AnimatorController::AddLayer(string) behavior, in order to change the weight.
            // For some reason I cannot find how to change the layer weight after it has been created.

            var newLayer = new AnimatorControllerLayer();
            newLayer.name = _animatorController.MakeUniqueLayerName(layerName);
            newLayer.stateMachine = new AnimatorStateMachine();
            newLayer.stateMachine.name = newLayer.name;
            newLayer.stateMachine.hideFlags = HideFlags.HideInHierarchy;
            newLayer.defaultWeight = weightWhenCreating;
            if (AssetDatabase.GetAssetPath(_animatorController) != "")
            {
                AssetDatabase.AddObjectToAsset(newLayer.stateMachine,
                    AssetDatabase.GetAssetPath(_animatorController));
            }

            _animatorController.AddLayer(newLayer);
        }

        internal static Vector3 GridPosition(float x, float y)
        {
            return new Vector3(x * 200 , y * 70, 0);
        }

        public void RemoveLayerIfExists(string layerNameToDelete)
        {
            var originalIndexToPreserveOrdering = _animatorController.layers.ToList().FindIndex(layer1 => layer1.name == layerNameToDelete);
            if (originalIndexToPreserveOrdering != -1)
            {
                _animatorController.RemoveLayer(originalIndexToPreserveOrdering);
            }
        }

        public void RemoveParamsIndiscriminatelyAsNeeded(params string[] names)
        {
            var paramsToDelete = _animatorController.parameters
                .Where(parameter => names.Contains(parameter.name))
                .ToList();

            foreach (var parameter in paramsToDelete)
            {
                _animatorController.RemoveParameter(parameter);
            }
        }
    }
}


<|start_filename|>Assets/Hai/Just1Int7Toggles/Scripts/Editor/Internal/Reused/HaiParameterist.cs<|end_filename|>
﻿using System;

namespace Hai.Just1Int7Toggles.Scripts.Editor.Internal.Reused
{
    internal static class AV3Parameterists
    {
        internal static BoolParameterist IsLocal = new BoolParameterist("IsLocal");
        internal static IntParameterist Viseme = new IntParameterist("Viseme");
        internal static IntParameterist GestureLeft = new IntParameterist("GestureLeft");
        internal static IntParameterist GestureRight = new IntParameterist("GestureRight");
        internal static FloatParameterist GestureLeftWeight = new FloatParameterist("GestureLeftWeight");
        internal static FloatParameterist GestureRightWeight = new FloatParameterist("GestureRightWeight");
        internal static FloatParameterist AngularY = new FloatParameterist("AngularY");
        internal static FloatParameterist VelocityX = new FloatParameterist("VelocityX");
        internal static FloatParameterist VelocityY = new FloatParameterist("VelocityY");
        internal static FloatParameterist VelocityZ = new FloatParameterist("VelocityZ");
        internal static FloatParameterist Upright = new FloatParameterist("Upright");
        internal static BoolParameterist Grounded = new BoolParameterist("Grounded");
        internal static BoolParameterist Seated = new BoolParameterist("Seated");
        internal static BoolParameterist AFK = new BoolParameterist("AFK");

        internal static Action<Transitionist.TransitionContinuationist> ItIsRemote()
        {
            return continuationist => continuationist.And(IsLocal).IsFalse();
        }

        internal static Action<Transitionist.TransitionContinuationist> ItIsLocal()
        {
            return continuationist => continuationist.And(IsLocal).IsTrue();
        }
    }
    
    internal abstract class Parameterist
    {
        internal string Name { get; }

        internal Parameterist(string name)
        {
            Name = name;
        }
    }

    internal class FloatParameterist : Parameterist
    {
        internal FloatParameterist(string name) : base(name)
        {
        }
    }

    internal class IntParameterist : Parameterist
    {
        internal IntParameterist(string name) : base(name)
        {
        }
    }

    internal class BoolParameterist : Parameterist
    {
        internal BoolParameterist(string name) : base(name)
        {
        }
    }
}

<|start_filename|>Assets/Hai/Just1Int7Toggles/Scripts/Editor/Internal/StatefulEmptyClipProvider.cs<|end_filename|>
﻿using Hai.Just1Int7Toggles.Scripts.Editor.Internal.Reused;
using UnityEngine;

namespace Hai.Just1Int7Toggles.Scripts.Editor.Internal
{
    public class StatefulEmptyClipProvider
    {
        private readonly ClipGenerator _clipGenerator;
        private AnimationClip _selectedEmptyClip;

        public StatefulEmptyClipProvider(ClipGenerator clipGenerator)
        {
            _clipGenerator = clipGenerator;
        }

        public AnimationClip Get()
        {
            if (_selectedEmptyClip == null) { 
                _selectedEmptyClip = _clipGenerator.GetOrCreateEmptyClip();
            }

            return _selectedEmptyClip;
        }
    }
}

<|start_filename|>Assets/Hai/Just1Int7Toggles/Scripts/Editor/EditorUI/JustHaiToggleGroupEditor.cs<|end_filename|>
﻿using Hai.Just1Int7Toggles.Scripts.Components;
using UnityEditor;
using UnityEditorInternal;
using UnityEngine;

namespace Hai.Just1Int7Toggles.Scripts.Editor.EditorUI
{
    [CustomEditor(typeof(JustHaiToggleGroup))]
    public class JustHaiToggleGroupEditor : UnityEditor.Editor
    {
        public ReorderableList togglablesReorderableList;
        public SerializedProperty parameterName;
        public SerializedProperty hintEnabled;

        private void OnEnable()
        {
            parameterName = serializedObject.FindProperty("parameterName");
            hintEnabled = serializedObject.FindProperty("hintEnabled");

            // reference: https://blog.terresquall.com/2020/03/creating-reorderable-lists-in-the-unity-inspector/
            var reorderableList = new ReorderableList(
                serializedObject,
                serializedObject.FindProperty("togglables"),
                true, true, true, true
            );
            reorderableList.drawElementCallback = (rect, oIndex, active, focused) => TogglablesListElement(rect, oIndex, active, focused);
            reorderableList.drawHeaderCallback = rect => TogglablesListHeader(rect);
            togglablesReorderableList = reorderableList;
        }

        private bool _foldoutAdvanced;

        public override void OnInspectorGUI()
        {
            serializedObject.Update();

            EditorGUILayout.PropertyField(parameterName, new GUIContent("Parameter Name"));
            if (parameterName.stringValue.Length == 0)
            {
                EditorGUILayout.HelpBox("Set a parameter name for use by the Expressions Menu.", MessageType.Error);
            }

            EditorGUILayout.PropertyField(hintEnabled, new GUIContent("Default state"));
            togglablesReorderableList.DoLayoutList();
            EditorGUILayout.Separator();

            serializedObject.ApplyModifiedProperties();
        }

        private void TogglablesListElement(Rect rect, int index, bool isActive, bool isFocused)
        {
            var element = togglablesReorderableList.serializedProperty.GetArrayElementAtIndex(index);

            EditorGUI.PropertyField(
                new Rect(rect.x, rect.y, rect.width - 100, EditorGUIUtility.singleLineHeight),
                element.FindPropertyRelative("item"),
                GUIContent.none
            );

            EditorGUI.PropertyField(
                new Rect(rect.x + rect.width - 100, rect.y, 80, EditorGUIUtility.singleLineHeight),
                element.FindPropertyRelative("initialState"),
                GUIContent.none
            );
        }

        private static void TogglablesListHeader(Rect rect)
        {
            EditorGUI.LabelField(rect, "Togglables");
        }
    }
}


<|start_filename|>Assets/Hai/Just1Int7Toggles/Scripts/Editor/Internal/TogglesManifest.cs<|end_filename|>
﻿using Hai.Just1Int7Toggles.Scripts.Components;
using UnityEngine;

namespace Hai.Just1Int7Toggles.Scripts.Editor.Internal
{
    public readonly struct TogglesManifest
    {
        public JustHaiToggleGroup[] Groups { get; }
        public GameObject Avatar { get; }

        public TogglesManifest(GameObject avatar, JustHaiToggleGroup[] groups)
        {
            Groups = groups;
            Avatar = avatar;
        }
    }
}


<|start_filename|>Assets/Hai/Just1Int7Toggles/Scripts/Editor/Internal/J1I7TParameters.cs<|end_filename|>
﻿using Hai.Just1Int7Toggles.Scripts.Editor.Internal.Reused;

namespace Hai.Just1Int7Toggles.Scripts.Editor.Internal
{
    internal static class J1I7TParameters
    {
        internal static readonly BoolParameterist InitializedParameterist = new BoolParameterist("JHTIS_Internal_Initialized");
    }
}


<|start_filename|>Assets/Hai/Just1Int7Toggles/Scripts/Editor/Internal/Reused/HaiMachinist.cs<|end_filename|>
﻿using System;
using System.Collections.Generic;
using UnityEditor.Animations;
using UnityEngine;
using VRC.SDK3.Avatars.Components;
using VRC.SDKBase;

namespace Hai.Just1Int7Toggles.Scripts.Editor.Internal.Reused
{
    internal class Machinist
    {
        private readonly AnimatorStateMachine _machine;
        private readonly AnimationClip _emptyClip;

        internal Machinist(AnimatorStateMachine machine, AnimationClip emptyClip)
        {
            _machine = machine;
            _emptyClip = emptyClip;
        }

        internal Machinist WithEntryPosition(int x, int y)
        {
            _machine.entryPosition = AnimatorGenerator.GridPosition(x, y);
            return this;
        }

        internal Machinist WithExitPosition(int x, int y)
        {
            _machine.exitPosition = AnimatorGenerator.GridPosition(x, y);
            return this;
        }

        internal Machinist WithAnyStatePosition(int x, int y)
        {
            _machine.anyStatePosition = AnimatorGenerator.GridPosition(x, y);
            return this;
        }

        internal Statist NewState(string name, float x, float y)
        {
            var state = _machine.AddState(name, AnimatorGenerator.GridPosition(x, y));
            state.motion = _emptyClip;
            state.writeDefaultValues = false;

            return new Statist(state);
        }

        public Transitionist AnyTransitionsTo(Statist destination)
        {
            return new Transitionist(Statist.NewDefaultTransition(_machine.AddAnyStateTransition(destination._state)));
        }
    }

    internal class Statist
    {
        internal readonly AnimatorState _state;
        private VRCAvatarParameterDriver _driver;
        private VRCAnimatorTrackingControl _tracking;

        internal Statist(AnimatorState state)
        {
            _state = state;
        }

        internal Statist WithAnimation(Motion clip)
        {
            _state.motion = clip;
            return this;
        }

        internal Transitionist TransitionsTo(Statist destination)
        {
            return new Transitionist(NewDefaultTransition(_state.AddTransition(destination._state)));
        }

        internal Statist AutomaticallyMovesTo(Statist destination)
        {
            var transition = NewDefaultTransition(_state.AddTransition(destination._state));
            transition.hasExitTime = true;
            return this;
        }

        internal Transitionist Exits()
        {
            return new Transitionist(NewDefaultTransition(_state.AddExitTransition()));
        }

        internal static AnimatorStateTransition NewDefaultTransition(AnimatorStateTransition transition)
        {
            transition.duration = 0;
            transition.hasExitTime = false;
            transition.exitTime = 0;
            transition.hasFixedDuration = true;
            transition.offset = 0;
            transition.interruptionSource = TransitionInterruptionSource.None;
            transition.orderedInterruption = true;
            transition.canTransitionToSelf = true;
            return transition;
        }

        internal Statist Drives(IntParameterist parameterist, int value)
        {
            CreateDriverBehaviorIfNotExists();
            _driver.parameters.Add(new VRC_AvatarParameterDriver.Parameter
            {
                name = parameterist.Name, value = value
            });
            return this;
        }

        internal Statist Drives(BoolParameterist parameterist, bool value)
        {
            CreateDriverBehaviorIfNotExists();
            _driver.parameters.Add(new VRC_AvatarParameterDriver.Parameter
            {
                name = parameterist.Name, value = value ? 1 : 0
            });
            return this;
        }

        internal Statist Drives(FloatParameterist parameterist, float value)
        {
            CreateDriverBehaviorIfNotExists();
            _driver.parameters.Add(new VRC_AvatarParameterDriver.Parameter
            {
                name = parameterist.Name, value = value
            });
            return this;
        }

        private void CreateDriverBehaviorIfNotExists()
        {
            if (_driver != null) return;
            _driver = _state.AddStateMachineBehaviour<VRCAvatarParameterDriver>();
            _driver.parameters = new List<VRC_AvatarParameterDriver.Parameter>();
        }

        public Statist WithWriteDefaultsSetTo(bool shouldWriteDefaults)
        {
            _state.writeDefaultValues = shouldWriteDefaults;
            return this;
        }

        public Statist TrackingTracks(TrackingElement element)
        {
            CreateTrackingBehaviorIfNotExists();
            SettingElementTo(element, VRC_AnimatorTrackingControl.TrackingType.Tracking);

            return this;
        }

        public Statist TrackingAnimates(TrackingElement element)
        {
            CreateTrackingBehaviorIfNotExists();
            SettingElementTo(element, VRC_AnimatorTrackingControl.TrackingType.Animation);

            return this;
        }

        private void SettingElementTo(TrackingElement element, VRC_AnimatorTrackingControl.TrackingType target)
        {
            switch (element)
            {
                case TrackingElement.Head:
                    _tracking.trackingHead = target;
                    break;
                case TrackingElement.LeftHand:
                    _tracking.trackingLeftHand = target;
                    break;
                case TrackingElement.RightHand:
                    _tracking.trackingRightHand = target;
                    break;
                case TrackingElement.Hip:
                    _tracking.trackingHip = target;
                    break;
                case TrackingElement.LeftFoot:
                    _tracking.trackingLeftFoot = target;
                    break;
                case TrackingElement.RightFoot:
                    _tracking.trackingRightFoot = target;
                    break;
                case TrackingElement.LeftFingers:
                    _tracking.trackingLeftFingers = target;
                    break;
                case TrackingElement.RightFingers:
                    _tracking.trackingRightFingers = target;
                    break;
                case TrackingElement.Eyes:
                    _tracking.trackingEyes = target;
                    break;
                case TrackingElement.Mouth:
                    _tracking.trackingMouth = target;
                    break;
                default:
                    throw new ArgumentOutOfRangeException(nameof(element), element, null);
            }
        }

        private void CreateTrackingBehaviorIfNotExists()
        {
            if (_tracking != null) return;
            _tracking = _state.AddStateMachineBehaviour<VRCAnimatorTrackingControl>();
        }

        internal enum TrackingElement
        {
            Head,
            LeftHand,
            RightHand,
            Hip,
            LeftFoot,
            RightFoot,
            LeftFingers,
            RightFingers,
            Eyes,
            Mouth
        }
    }

    internal class Transitionist
    {
        private readonly AnimatorStateTransition _transition;

        internal Transitionist(AnimatorStateTransition transition)
        {
            _transition = transition;
        }

        internal Transitionist WithExitTimeTo(float value)
        {
            _transition.hasExitTime = true;
            _transition.exitTime = value;
            return this;
        }

        internal BuildingIntTransitionist When(IntParameterist parameter)
        {
            return new BuildingIntTransitionist(new TransitionContinuationist(_transition), _transition, parameter);
        }

        internal BuildingFloatTransitionist When(FloatParameterist parameter)
        {
            return new BuildingFloatTransitionist(new TransitionContinuationist(_transition), _transition, parameter);
        }

        internal BuildingBoolTransitionist When(BoolParameterist parameter)
        {
            return new BuildingBoolTransitionist(new TransitionContinuationist(_transition), _transition, parameter);
        }

        internal TransitionContinuationist Whenever(Action<TransitionContinuationist> action)
        {
            var transitionContinuationist = new TransitionContinuationist(_transition);
            action(transitionContinuationist);
            return transitionContinuationist;
        }

        internal TransitionContinuationist Whenever()
        {
            return new TransitionContinuationist(_transition);
        }

        internal class TransitionContinuationist
        {
            private readonly AnimatorStateTransition _transition;

            internal TransitionContinuationist(AnimatorStateTransition transition)
            {
                _transition = transition;
            }

            internal BuildingIntTransitionist And(IntParameterist parameter)
            {
                return new BuildingIntTransitionist(this, _transition, parameter);
            }

            internal BuildingFloatTransitionist And(FloatParameterist parameter)
            {
                return new BuildingFloatTransitionist(this, _transition, parameter);
            }

            internal BuildingBoolTransitionist And(BoolParameterist parameter)
            {
                return new BuildingBoolTransitionist(this, _transition, parameter);
            }

            internal TransitionContinuationist AndWhenever(Action<TransitionContinuationist> action)
            {
                action(this);
                return this;
            }
        }

        internal class BuildingIntTransitionist
        {
            private readonly TransitionContinuationist _transitionist;
            private readonly AnimatorStateTransition _transition;
            private readonly IntParameterist _parameterist;

            internal BuildingIntTransitionist(TransitionContinuationist transitionist, AnimatorStateTransition transition, IntParameterist parameterist)
            {
                _transitionist = transitionist;
                _transition = transition;
                _parameterist = parameterist;
            }

            internal TransitionContinuationist IsEqualTo(int value)
            {
                _transition.AddCondition(AnimatorConditionMode.Equals, value, _parameterist.Name);
                return _transitionist;
            }

            internal TransitionContinuationist IsNotEqualTo(int value)
            {
                _transition.AddCondition(AnimatorConditionMode.NotEqual, value, _parameterist.Name);
                return _transitionist;
            }

            internal TransitionContinuationist IsLesserThan(int value)
            {
                _transition.AddCondition(AnimatorConditionMode.Less, value, _parameterist.Name);
                return _transitionist;
            }

            internal TransitionContinuationist IsGreaterThan(int value)
            {
                _transition.AddCondition(AnimatorConditionMode.Greater, value, _parameterist.Name);
                return _transitionist;
            }
        }

        internal class BuildingFloatTransitionist
        {
            private readonly TransitionContinuationist _transitionist;
            private readonly AnimatorStateTransition _transition;
            private readonly FloatParameterist _parameterist;

            internal BuildingFloatTransitionist(TransitionContinuationist transitionist, AnimatorStateTransition transition, FloatParameterist parameterist)
            {
                _transitionist = transitionist;
                _transition = transition;
                _parameterist = parameterist;
            }

            internal TransitionContinuationist IsLesserThan(float value)
            {
                _transition.AddCondition(AnimatorConditionMode.Less, value, _parameterist.Name);
                return _transitionist;
            }

            internal TransitionContinuationist IsGreaterThan(float value)
            {
                _transition.AddCondition(AnimatorConditionMode.Greater, value, _parameterist.Name);
                return _transitionist;
            }
        }

        internal class BuildingBoolTransitionist
        {
            private readonly TransitionContinuationist _transitionist;
            private readonly AnimatorStateTransition _transition;
            private readonly BoolParameterist _parameterist;

            internal BuildingBoolTransitionist(TransitionContinuationist transitionist, AnimatorStateTransition transition, BoolParameterist parameterist)
            {
                _transitionist = transitionist;
                _transition = transition;
                _parameterist = parameterist;
            }

            internal TransitionContinuationist IsTrue()
            {
                _transition.AddCondition(AnimatorConditionMode.If, 0, _parameterist.Name);
                return _transitionist;
            }

            internal TransitionContinuationist IsFalse()
            {
                _transition.AddCondition(AnimatorConditionMode.IfNot, 0, _parameterist.Name);
                return _transitionist;
            }
        }

        public Transitionist WithSourceInterruption()
        {
            _transition.interruptionSource = TransitionInterruptionSource.Source;
            return this;
        }

        public Transitionist WithTransitionDuration(float transitionDuration)
        {
            _transition.duration = transitionDuration;
            return this;
        }

        public Transitionist WithNoOrderedInterruption()
        {
            _transition.orderedInterruption = false;
            return this;
        }

        public Transitionist WithNoTransitionToSelf()
        {
            _transition.canTransitionToSelf = false;
            return this;
        }
    }
}


<|start_filename|>Assets/Hai/Just1Int7Toggles/Scripts/Editor/EditorUI/Just1Int7TogglesCompilerEditor.cs<|end_filename|>
﻿using System.Linq;
using Hai.Just1Int7Toggles.Scripts.Components;
using Hai.Just1Int7Toggles.Scripts.Editor.Internal;
using UnityEditor;
using UnityEngine;
using UnityEngine.Experimental.PlayerLoop;
using VRC.SDK3.Avatars.ScriptableObjects;

namespace Hai.Just1Int7Toggles.Scripts.Editor.EditorUI
{
    [CustomEditor(typeof(Just1Int7TogglesCompiler))]
    public class Just1Int7TogglesCompilerEditor : UnityEditor.Editor
    {
        public SerializedProperty animatorController;
        public SerializedProperty customEmptyClip;

        public SerializedProperty avatar;

        private void OnEnable()
        {
            AsCompiler().Migrate();

            animatorController = serializedObject.FindProperty("animatorController");
            customEmptyClip = serializedObject.FindProperty("customEmptyClip");

            avatar = serializedObject.FindProperty("avatar");
        }

        private bool _foldoutAdvanced;

        public override void OnInspectorGUI()
        {
            serializedObject.Update();

            if (IsLegacy())
            {
                if (GUILayout.Button("Convert to Just Hai Toggles Inventory System", GUILayout.Height(100)))
                {
                    Convert();
                }

                return;
            }

            var compiler = (Just1Int7TogglesCompiler) target;

            compiler.convertedToInventorySystem = true;

            EditorGUILayout.PropertyField(animatorController, new GUIContent("FX Animator Controller to overwrite"));
            EditorGUILayout.PropertyField(avatar, new GUIContent("Avatar"));

            EditorGUILayout.LabelField("Groups", EditorStyles.boldLabel);
            var toggleGroups = compiler.GetComponents<JustHaiToggleGroup>();
            var expressionParameters = compiler.avatar != null ? compiler.avatar.expressionParameters : null;
            if (avatar.serializedObject.targetObject == null)
            {
                EditorGUILayout.HelpBox("Avatar is missing.", MessageType.Error);
            }
            else if (expressionParameters == null)
            {
                EditorGUILayout.HelpBox("Avatar does not have Expression Parameters.\nPlease add one.", MessageType.Warning);
            }
            var anyEmpty = 0;
            foreach (var group in toggleGroups)
            {
                if (!string.IsNullOrEmpty(@group.parameterName))
                {
                    var param = expressionParameters != null ? expressionParameters.FindParameter(@group.parameterName) : null;

                    EditorGUILayout.LabelField("- " + group.parameterName);
                    if (expressionParameters != null)
                    {
                        ParameterFixes(param, expressionParameters, @group);
                    }
                }
                else
                {
                    anyEmpty++;
                }
            }

            if (anyEmpty > 0)
            {
                EditorGUILayout.HelpBox($"There are {anyEmpty} groups that do not have parameter names yet.", MessageType.Error);
            }

            if (expressionParameters != null)
            {
                LegacyRemoval(expressionParameters);
                NoNameRemoval(expressionParameters);
            }

            EditorGUI.BeginDisabledGroup(anyEmpty > 0);
            if (GUILayout.Button("+ Add group..."))
            {
                compiler.gameObject.AddComponent<JustHaiToggleGroup>();
            }
            EditorGUI.EndDisabledGroup();

            EditorGUILayout.LabelField("Generator", EditorStyles.boldLabel);

            EditorGUI.BeginDisabledGroup(
                ThereIsNoAnimatorController() || ThereIsNoAvatar()
            );

            bool ThereIsNoAnimatorController()
            {
                return animatorController.objectReferenceValue == null;
            }

            bool ThereIsNoAvatar()
            {
                return avatar.objectReferenceValue == null;
            }

            if (GUILayout.Button("Generate FX Animator layers"))
            {
                DoGenerateEverything();
            }

            EditorGUI.EndDisabledGroup();

            EditorGUILayout.Space();

            _foldoutAdvanced = EditorGUILayout.Foldout(_foldoutAdvanced, "Advanced");
            if (_foldoutAdvanced)
            {
                EditorGUILayout.LabelField("Fine tuning", EditorStyles.boldLabel);
                EditorGUILayout.PropertyField(customEmptyClip, new GUIContent("Custom 2-frame empty animation clip (optional)"));
            }

            serializedObject.ApplyModifiedProperties();
        }

        private static void NoNameRemoval(VRCExpressionParameters expressionParameters)
        {
            var anyBlankParameter = expressionParameters.parameters.Any(parameter => parameter.name == "");

            if (anyBlankParameter)
            {
                EditorGUILayout.LabelField("Clean up", EditorStyles.boldLabel);
                EditorGUILayout.HelpBox("Your avatar has Expression Parameters with no name. This will take up unnecessary memory that Just Hai Toggles Inventory System won't be able to use.", MessageType.Error);
                if (GUILayout.Button("Fix: Remove empty Expression Parameters"))
                {
                    expressionParameters.parameters = expressionParameters.parameters
                        .Where(parameter => parameter.name != "")
                        .ToArray();
                    ForceSaveAsset(expressionParameters);
                }
            }
        }

        private static void LegacyRemoval(VRCExpressionParameters expressionParameters)
        {
            var legacyParamA = expressionParameters.FindParameter("J1I7T_A_Sync");
            var legacyParamB = expressionParameters.FindParameter("J1I7T_B_Sync");
            if (legacyParamA != null || legacyParamB != null)
            {
                EditorGUILayout.LabelField("Legacy", EditorStyles.boldLabel);
                if (legacyParamA != null)
                {
                    EditorGUILayout.HelpBox("Your avatar has an Expression Parameter with name J1I7T_A_Sync. It is no longer used.", MessageType.Error);
                }

                if (legacyParamB != null)
                {
                    EditorGUILayout.HelpBox("Your avatar has an Expression Parameter with name J1I7T_B_Sync. It is no longer used.", MessageType.Error);
                }

                if (GUILayout.Button("Fix: Remove legacy Expression Parameters"))
                {
                    expressionParameters.parameters = expressionParameters.parameters
                        .Where(parameter => parameter.name != "J1I7T_A_Sync")
                        .Where(parameter => parameter.name != "J1I7T_B_Sync")
                        .ToArray();
                    ForceSaveAsset(expressionParameters);
                }
            }
        }

        private static void ParameterFixes(VRCExpressionParameters.Parameter param, VRCExpressionParameters expressionParameters, JustHaiToggleGroup @group)
        {
            if (param == null)
            {
                EditorGUILayout.HelpBox("Expression Parameter does not exist", MessageType.Error);
                if (GUILayout.Button("Fix: Create Expression Parameter"))
                {
                    var newParameters = new VRCExpressionParameters.Parameter[expressionParameters.parameters.Length + 1];
                    expressionParameters.parameters.CopyTo(newParameters, 0);
                    expressionParameters.parameters = newParameters;
                    expressionParameters.parameters[expressionParameters.parameters.Length - 1] = new VRCExpressionParameters.Parameter()
                    {
                        name = @group.parameterName,
                        defaultValue = @group.hintEnabled ? 1f : 0f,
                        saved = true,
                        valueType = VRCExpressionParameters.ValueType.Bool
                    };
                    ForceSaveAsset(expressionParameters);
                }
            }
            else if (param.valueType != VRCExpressionParameters.ValueType.Bool)
            {
                EditorGUILayout.HelpBox($"Expression Parameter exists but it is not a Bool (currently: {param.valueType})", MessageType.Error);
                if (GUILayout.Button("Fix: Change Expression Parameter Type to Bool"))
                {
                    param.valueType = VRCExpressionParameters.ValueType.Bool;
                    param.defaultValue = @group.hintEnabled ? 1f : 0f;
                    ForceSaveAsset(expressionParameters);
                }
            }
            else if (param.defaultValue != (@group.hintEnabled ? 1f : 0f))
            {
                EditorGUILayout.HelpBox($"Expression Parameter default value is not the same", MessageType.Warning);
                if (GUILayout.Button("Fix: Change Expression Parameter Default Value"))
                {
                    param.defaultValue = @group.hintEnabled ? 1f : 0f;
                    ForceSaveAsset(expressionParameters);
                }
            }
        }

        private static void ForceSaveAsset(VRCExpressionParameters expressionParameters)
        {
            var assetPath = AssetDatabase.GetAssetPath(expressionParameters);
            AssetDatabase.ForceReserializeAssets(new []{assetPath});
        }

        private Just1Int7TogglesCompiler AsCompiler()
        {
            return (Just1Int7TogglesCompiler) target;
        }

        private void DoGenerateEverything()
        {
            var compiler = AsCompiler();
            new Just1Int7TogglesCompilerInternal(
                    compiler.animatorController,
                    compiler.customEmptyClip,
                    new TogglesManifest(
                        compiler.avatar.gameObject,
                        compiler.GetComponents<JustHaiToggleGroup>()
                    )
            ).DoOverwriteCommonLogic();
        }

        private bool IsLegacy()
        {
            return !((Just1Int7TogglesCompiler)target).convertedToInventorySystem && ((Just1Int7TogglesCompiler)target).togglables != null && ((Just1Int7TogglesCompiler)target).togglables.Length > 0;
        }

        private void Convert()
        {
            if (!IsLegacy()) return;

            var compiler = (Just1Int7TogglesCompiler) serializedObject.targetObject;

            for (var index = 0; index < compiler.togglables.Length; index++)
            {
                var togglableContainer = compiler.togglables[index];
                var enabled = compiler.enableds[index];
                var items = togglableContainer.values;
                if (items.Count > 0)
                {
                    var jhtg = CreateNewToggleGroup();
                    jhtg.hintEnabled = enabled;
                    jhtg.togglables = items.Select(togglable => new TogglableItemV2
                    {
                        item = togglable.item,
                        initialState = togglable.initialState == J1I7TToggleableInitialState.Normal ? ToggleableInitialStateV2.Normal : ToggleableInitialStateV2.Inverse,
                    }).ToList();
                }
            }

            compiler.togglables = new TogglableContainer[0];
            compiler.convertedToInventorySystem = true;
        }

        private JustHaiToggleGroup CreateNewToggleGroup()
        {
            return ((Just1Int7TogglesCompiler) serializedObject.targetObject).gameObject.AddComponent<JustHaiToggleGroup>();
        }
    }
}


<|start_filename|>Assets/Hai/Just1Int7Toggles/Scripts/Editor/Internal/ViewCreator.cs<|end_filename|>
﻿using System;
using System.Collections.Generic;
using System.Linq;
using Hai.Just1Int7Toggles.Scripts.Components;
using Hai.Just1Int7Toggles.Scripts.Editor.Internal.Reused;
using UnityEditor;
using UnityEditor.Animations;
using UnityEngine;
using static Hai.Just1Int7Toggles.Scripts.Editor.Internal.J1I7TParameters;

namespace Hai.Just1Int7Toggles.Scripts.Editor.Internal
{
    internal class ViewCreator
    {
        private readonly AnimatorGenerator _animatorGenerator;
        private readonly TogglesManifest _manifest;

        internal ViewCreator(AnimatorGenerator animatorGenerator, TogglesManifest manifest)
        {
            _animatorGenerator = animatorGenerator;
            _manifest = manifest;
        }

        internal void CreateOrReplaceView()
        {
            var machinist = _animatorGenerator.CreateOrRemakeLayerAtSameIndex("Hai_J1I7T_View", 1f)
                .WithEntryPosition(0, -3)
                .WithExitPosition(0, -5);
            var init = machinist.NewState("Init", 1, -2)
                .Drives(InitializedParameterist, false);
            var waiting = machinist.NewState("Waiting", 0, 0)
                .Drives(InitializedParameterist, true);

            var assetContainer_Base = new AnimatorController();
            var assetContainer = new AssetContainerist(assetContainer_Base)
                .GenerateAssetFileIn("", "GeneratedJ1I7T__", "");

            int height = 0;
            Statist previousOn = init;
            Statist previousOff = null;
            foreach (var group in _manifest.Groups)
            {
                var groupParam = new BoolParameterist(group.parameterName);
                var internalParam = new BoolParameterist("JHTIS_T_" + group.parameterName);
                var itemName = group.parameterName;

                _animatorGenerator.CreateParamsAsNeeded(groupParam, internalParam);

                if (group.togglables.Count != 0)
                {
                    Dictionary<string, ToggleableInitialStateV2> subgroup = group.togglables
                        .Where(togglable => togglable.item != null)
                        .GroupBy(togglable => ResolveRelativePath(_manifest.Avatar.transform, togglable.item.transform))
                        .ToDictionary(items => items.Key, items => items.First().initialState);

                    if (subgroup.Count != 0)
                    {
                        var clipForOn = CreateClipToEnable(itemName, subgroup);
                        var clipForOff = CreateClipToDisable(itemName, subgroup);

                        var off = machinist.NewState($"{itemName} OFF", 2, height)
                            .WithAnimation(clipForOff.Expose())
                            .Drives(internalParam, false);
                        var on = machinist.NewState($"{itemName} ON", 3, height)
                            .WithAnimation(clipForOn.Expose())
                            .Drives(internalParam, true);

                        waiting.TransitionsTo(off).WithExitTimeTo(1f)
                            .When(groupParam).IsFalse()
                            .And(internalParam).IsTrue();
                        waiting.TransitionsTo(on).WithExitTimeTo(1f)
                            .When(groupParam).IsTrue()
                            .And(internalParam).IsFalse();

                        off.TransitionsTo(waiting).WithExitTimeTo(1f)
                            .When(InitializedParameterist).IsTrue();
                        on.TransitionsTo(waiting).WithExitTimeTo(1f)
                            .When(InitializedParameterist).IsTrue();

                        previousOn.TransitionsTo(off).WithExitTimeTo(1f)
                            .When(InitializedParameterist).IsFalse()
                            .And(groupParam).IsFalse();
                        previousOn.TransitionsTo(on).WithExitTimeTo(1f)
                            .When(InitializedParameterist).IsFalse()
                            .And(groupParam).IsTrue();

                        previousOff?.TransitionsTo(off).WithExitTimeTo(1f)
                            .When(InitializedParameterist).IsFalse()
                            .And(groupParam).IsFalse();
                        previousOff?.TransitionsTo(on).WithExitTimeTo(1f)
                            .When(InitializedParameterist).IsFalse()
                            .And(groupParam).IsTrue();

                        previousOff = off;
                        previousOn = on;

                        assetContainer.Include(clipForOn);
                        assetContainer.Include(clipForOff);

                        height++;
                    }
                }
            }

            previousOn.AutomaticallyMovesTo(waiting);
            previousOff?.AutomaticallyMovesTo(waiting);

            AssetDatabase.SaveAssets();
            AssetDatabase.Refresh();
        }

        private static Motionist CreateClipToDisable(string itemName, Dictionary<string, ToggleableInitialStateV2> relativePaths)
        {
            var motionist = Motionist.FromScratch()
                .WithName("Disable " + itemName)
                .NonLooping();
            foreach (var path in relativePaths)
            {
                switch (path.Value)
                {
                    case ToggleableInitialStateV2.Normal:
                        motionist.TogglesGameObjectOff(path.Key);
                        break;
                    case ToggleableInitialStateV2.Inverse:
                        motionist.TogglesGameObjectOn(path.Key);
                        break;
                    default:
                        throw new ArgumentOutOfRangeException();
                }
            }

            return motionist;
        }

        private static Motionist CreateClipToEnable(string itemName, Dictionary<string, ToggleableInitialStateV2> relativePaths)
        {
            var motionist = Motionist.FromScratch()
                .WithName("Enable " + itemName)
                .NonLooping();

            foreach (var path in relativePaths)
            {
                switch (path.Value)
                {
                    case ToggleableInitialStateV2.Normal:
                        motionist.TogglesGameObjectOn(path.Key);
                        break;
                    case ToggleableInitialStateV2.Inverse:
                        motionist.TogglesGameObjectOff(path.Key);
                        break;
                    default:
                        throw new ArgumentOutOfRangeException();
                }
            }

            return motionist;
        }

        private static string ResolveRelativePath(Transform avatar, Transform item)
        {
            if (item.parent != avatar && item.parent != null)
            {
                return ResolveRelativePath(avatar, item.parent) + "/" + item.name;
            }

            return item.name;
        }
    }
}


<|start_filename|>Assets/Hai/Just1Int7Toggles/Scripts/Components/JustHaiToggleGroup.cs<|end_filename|>
﻿using System;
using System.Collections.Generic;
using UnityEngine;

namespace Hai.Just1Int7Toggles.Scripts.Components
{
    public class JustHaiToggleGroup : MonoBehaviour
    {
        public int internalVersion;

        public List<TogglableItemV2> togglables;
        public bool hintEnabled;
        public string parameterName;
    }

    [Serializable]
    public struct TogglableItemV2
    {
        public GameObject item;
        public ToggleableInitialStateV2 initialState;
    }

    [Serializable]
    public enum ToggleableInitialStateV2
    {
        Normal,
        Inverse
    }
}


<|start_filename|>Assets/Hai/Just1Int7Toggles/Scripts/Editor/Internal/Reused/AssetContainerist.cs<|end_filename|>
﻿using System;
using UnityEditor;
using UnityEditor.Animations;

namespace Hai.Just1Int7Toggles.Scripts.Editor.Internal.Reused
{
    internal class AssetContainerist
    {
        private readonly AnimatorController _assetContainer;
        private string _datetimeForAssetPack;

        public AssetContainerist(AnimatorController assetContainer)
        {
            _assetContainer = assetContainer;
            _datetimeForAssetPack = DateTime.Now.ToString("yyyy'-'MM'-'dd'_'HHmmss");
        }

        public AssetContainerist GenerateAssetFileIn(string pathWithNoLeadingNorTrailingSlash, string prefix, string suffix)
        {
            string separator = "";
            if (pathWithNoLeadingNorTrailingSlash.Length != 0)
            {
                separator = "/";
            }
            AssetDatabase.CreateAsset(_assetContainer, "Assets/" + pathWithNoLeadingNorTrailingSlash + separator + prefix + _datetimeForAssetPack + suffix + ".asset");

            return this;
        }

        public void Include(Assetist assetist)
        {
            AssetDatabase.AddObjectToAsset(assetist.AsAsset(), _assetContainer);
        }
    }
}

<|start_filename|>Assets/Hai/Just1Int7Toggles/Scripts/Editor/Internal/Reused/Motionist.cs<|end_filename|>
﻿using UnityEditor;
using UnityEngine;

namespace Hai.Just1Int7Toggles.Scripts.Editor.Internal.Reused
{
    internal interface Assetist
    {
        Object AsAsset();
    }
    
    internal class Motionist : Assetist
    {
        private readonly AnimationClip _animationClip;

        public static Motionist FromScratch()
        {
            return new Motionist(new AnimationClip())
                .NonLooping();
        }
        
        public Motionist(AnimationClip animationClip)
        {
            _animationClip = animationClip;
        }

        public Motionist WithName(string name)
        {
            _animationClip.name = name;
            return this;
        }

        public Motionist NonLooping()
        {
            var settings = AnimationUtility.GetAnimationClipSettings(_animationClip);
            settings.loopTime = false;

            return this;
        }

        public Motionist Looping()
        {
            var settings = AnimationUtility.GetAnimationClipSettings(_animationClip);
            settings.loopTime = true;

            return this;
        }

        public Motionist TogglesGameObjectOff(string relativePath)
        {
            _animationClip.SetCurve( relativePath, typeof(GameObject), "m_IsActive", TwoKeyframesWithValue(0));
            return this;
        }

        public Motionist TogglesGameObjectOn(string relativePath)
        {
            _animationClip.SetCurve( relativePath, typeof(GameObject), "m_IsActive", TwoKeyframesWithValue(1));
            return this;
        }

        private static AnimationCurve TwoKeyframesWithValue(float value)
        {
            return new AnimationCurve(new Keyframe(0, value), new Keyframe(1 / 60f, value));
        }

        public Object AsAsset()
        {
            return _animationClip;
        }

        public Motion Expose()
        {
            return _animationClip;
        }
    }
}

<|start_filename|>Assets/Hai/Just1Int7Toggles/Scripts/Components/Just1Int7TogglesCompiler.cs<|end_filename|>
﻿using System.Collections.Generic;
using System.Linq;
using UnityEngine;
using VRC.SDK3.Avatars.Components;

namespace Hai.Just1Int7Toggles.Scripts.Components
{
    public class Just1Int7TogglesCompiler : MonoBehaviour
    {
        public RuntimeAnimatorController animatorController;
        public AnimationClip customEmptyClip;

        public VRCAvatarDescriptor avatar;

        public int internalVersion;

        public bool convertedToInventorySystem;

        public TogglableContainer[] togglables;
        public bool[] enableds;

        public GameObject item1;
        public bool enabled1;

        public GameObject item2;
        public bool enabled2;

        public GameObject item3;
        public bool enabled3;

        public GameObject item4;
        public bool enabled4;

        public GameObject item5;
        public bool enabled5;

        public GameObject item6;
        public bool enabled6;

        public GameObject item7;
        public bool enabled7;

        public bool alsoGenerateLayerB;

        public GameObject item8;
        public bool enabled8;

        public GameObject item9;
        public bool enabled9;

        public GameObject item10;
        public bool enabled10;

        public GameObject item11;
        public bool enabled11;

        public GameObject item12;
        public bool enabled12;

        public GameObject item13;
        public bool enabled13;

        public GameObject item14;
        public bool enabled14;

        public GameObject item15;
        public bool enabled15;

        public void Migrate()
        {
            if (internalVersion != 0)
            {
                return;
            }

            togglables = Enumerable.Repeat(0, 15).Select(i => new TogglableContainer { values = new List<TogglableItem>() }).ToArray();
            enableds = Enumerable.Repeat(0, 15).Select(i => false).ToArray();

            var prevItems = new[]
            {
                item1, item2, item3, item4, item5, item6,
                item7, item8, item9, item10, item11,
                item12, item13, item14, item15
            };
            for (var index = 0; index < prevItems.Length; index++)
            {
                var item = prevItems[index];
                if (item != null)
                {
                    togglables[index].values.Add(new TogglableItem
                        {item = item, initialState = J1I7TToggleableInitialState.Normal});
                }
            }

            var prevEnableds = new[]
            {
                enabled1, enabled2, enabled3, enabled4, enabled5, enabled6,
                enabled7, enabled8, enabled9, enabled10, enabled11,
                enabled12, enabled13, enabled14, enabled15
            };
            for (var index = 0; index < prevEnableds.Length; index++)
            {
                var item = prevEnableds[index];
                enableds[index] = item;
            }

            internalVersion = 1;
        }
    }

    [System.Serializable]
    public struct TogglableContainer
    {
        public List<TogglableItem> values;
    }

    [System.Serializable]
    public struct TogglableItem
    {
        public GameObject item;
        public J1I7TToggleableInitialState initialState;
    }

    [System.Serializable]
    public enum J1I7TToggleableInitialState
    {
        Normal, Inverse
    }
}
