Animation Controller modifications via script not saving on reload.

Hello,

I am working on an editor script to automatically setup an animation controller in a specific way for myself. I have it all working correctly except for when I reload the project, the states and the transitions are gone (The layers are still there though). Below are images of what happens before and after I reload the editor.

Some help on troubleshooting this would be greatly appreciated. I’m sure it has something to so with my modifying a copy without setting it to the original or something, just can’t seem to fond it.

Thank you!

Before:
8625933--1158984--upload_2022-11-30_12-26-20.png

After reload:
8625933--1158987--upload_2022-11-30_12-26-59.png

Code:

private void ApplyToAnimator()
    {
        foreach (var toggle in Toggles)
        {
            // Check if the parameter or layer already exists. If not, add parameter
            bool existParam = doesNameExistParam(toggle.toggleName + "Toggle", controller.parameters);
            if (existParam == false)
            {
                controller.AddParameter(toggle.toggleName + "Toggle", AnimatorControllerParameterType.Bool);
            }

            //Check if a layer already Exists with that name. If so, remove and add new one.
            bool existLayer = doesNameExistLayer(toggle.toggleName, controller.layers);
            if (existLayer)
            {
                controller.RemoveLayer(controller.layers.Length-1);
            }
           
            controller.AddLayer(toggle.toggleName);

            //Creating On and Off states
            AnimatorState stateOn = new AnimatorState
            {
                name = "ON",
                motion = (Motion)AssetDatabase.LoadAssetAtPath(saveDir + "ToggleAnimations" + $"/On{toggle.toggleName}.anim", typeof(Motion)),
                writeDefaultValues = false
            };
            AnimatorState stateOff = new AnimatorState
            {
                name = "OFF",
                motion = (Motion)AssetDatabase.LoadAssetAtPath(saveDir + "ToggleAnimations" + $"/Off{toggle.toggleName}.anim", typeof(Motion)),
                writeDefaultValues = false
            };
            AnimatorState stateIdle = new AnimatorState
            {
                name = "Idle",
                motion = (Motion)AssetDatabase.LoadAssetAtPath(saveDir + "ToggleAnimations" + $"/Idle{toggle.toggleName}.anim", typeof(Motion)),
                writeDefaultValues = true
            };

            AnimatorController animatorController = controller;
            var sm = animatorController.layers[controller.layers.Length - 1].stateMachine;

            // Adding created states to controller layer
            controller.layers[controller.layers.Length - 1].stateMachine.AddState(stateIdle, new Vector3(300, 0, 0));
            controller.layers[controller.layers.Length - 1].stateMachine.AddState(stateOff, new Vector3(100, -110, 0));
            controller.layers[controller.layers.Length - 1].stateMachine.AddState(stateOn, new Vector3(300, -220, 0));

            // If True, go to ON state.
            sm.states[2].state.AddTransition(sm.states[1].state);
            sm.states[2].state.transitions[0].AddCondition(AnimatorConditionMode.IfNot, 0, toggle.toggleName + "Toggle");
            sm.states[2].state.transitions[0].duration = 0.1f;

            // If False, go to Off state.
            sm.states[0].state.AddTransition(sm.states[2].state);
            sm.states[0].state.transitions[0].AddCondition(AnimatorConditionMode.If, 0, toggle.toggleName + "Toggle");
            sm.states[0].state.transitions[0].duration = 0.1f;
           
            // Go to Idle after Off state immediately.
            sm.states[1].state.AddTransition(sm.states[0].state);
            sm.states[1].state.transitions[0].duration = 0.1f;
            sm.states[1].state.transitions[0].hasExitTime = true;
           
            AssetDatabase.AddObjectToAsset(stateOn, AssetDatabase.GetAssetPath(controller));
            AssetDatabase.AddObjectToAsset(stateOff, AssetDatabase.GetAssetPath(controller));
            AssetDatabase.AddObjectToAsset(stateIdle, AssetDatabase.GetAssetPath(controller));
           
            //Set Layer Weight
            AnimatorControllerLayer[] layers = controller.layers;
            layers[controller.layers.Length - 1].defaultWeight = 1;
            controller.layers = layers;
        }
        AssetDatabase.SaveAssets();
    }
    private void Postprocessing() // Ran at end
    {
        AssetDatabase.Refresh();
        EditorUtility.SetDirty(controller);
        AssetDatabase.SaveAssets();
    }

Update:
I managed to keep the states on reload by adding this following code:

AssetDatabase.AddObjectToAsset(stateOn, AssetDatabase.GetAssetPath(controller));
            AssetDatabase.AddObjectToAsset(stateOff, AssetDatabase.GetAssetPath(controller));
            AssetDatabase.AddObjectToAsset(stateIdle, AssetDatabase.GetAssetPath(controller));

I’ve solved the issue. I’m not sure exactly what it was, but I started from scratch and slowly reimplemented following the instructions form this forum post here .

The changed chunk of code now looks like this below. I hope this help someone else!

private void ApplyToAnimator()
    {
        foreach (var toggle in Toggles)
        {
            // Check if the parameter or layer already exists. If not, add parameter
            bool existParam = doesNameExistParam(toggle.toggleName + "Toggle", controller.parameters);
            if (existParam == false)
            {
                controller.AddParameter(toggle.toggleName + "Toggle", UnityEngine.AnimatorControllerParameterType.Bool);
            }

            //Check if a layer already Exists with that name. If so, remove and add new one.
            bool existLayer = doesNameExistLayer(toggle.toggleName, controller.layers);
            if (existLayer)
            {
                controller.RemoveLayer(controller.layers.Length-1);
            }
           
            controller.AddLayer(toggle.toggleName);

            AnimatorController animatorController = controller as AnimatorController;
            var sm = animatorController.layers[controller.layers.Length - 1].stateMachine;

            sm.AddState("stateIdle", new Vector3(300, 0, 0));
            sm.AddState("stateOn", new Vector3(300, -220, 0));
            sm.AddState("stateOff", new Vector3(100, -110, 0));

            sm.states[0].state.name = "IDLE" + toggle.toggleName;
            sm.states[0].state.motion = null;
            sm.states[0].state.writeDefaultValues = true;
           
            sm.states[1].state.name = "ON" + toggle.toggleName;
            sm.states[1].state.motion = (Motion)AssetDatabase.LoadAssetAtPath(saveDir + "ToggleAnimations" + $"/On{toggle.toggleName}.anim", typeof(Motion));
            sm.states[1].state.writeDefaultValues = false;
           
            sm.states[2].state.name = "OFF" + toggle.toggleName;
            sm.states[2].state.motion = (Motion)AssetDatabase.LoadAssetAtPath(saveDir + "ToggleAnimations" + $"/Off{toggle.toggleName}.anim", typeof(Motion));
            sm.states[2].state.writeDefaultValues = false;

            sm.states[0].state.AddTransition(sm.states[1].state);
            sm.states[0].state.transitions[0].AddCondition(AnimatorConditionMode.If, 0, toggle.toggleName + "Toggle");
            sm.states[1].state.AddTransition(sm.states[2].state);
            sm.states[1].state.transitions[0].AddCondition(AnimatorConditionMode.IfNot, 0, toggle.toggleName + "Toggle");
            sm.states[2].state.AddTransition(sm.states[0].state);
            sm.states[2].state.transitions[0].hasExitTime = true;

            //Set Layer Weight
            AnimatorControllerLayer[] layers = controller.layers;
            layers[controller.layers.Length - 1].defaultWeight = 1;
            controller.layers = layers;
        }
    }