Search Unity

Question Animation Controller modifications via script not saving on reload.

Discussion in 'Animation' started by Cascadian215, Nov 30, 2022.

  1. Cascadian215

    Cascadian215

    Joined:
    Dec 8, 2018
    Posts:
    2
    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:
    upload_2022-11-30_12-26-20.png

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

    Code:
    Code (CSharp):
    1. private void ApplyToAnimator()
    2.     {
    3.         foreach (var toggle in Toggles)
    4.         {
    5.             // Check if the parameter or layer already exists. If not, add parameter
    6.             bool existParam = doesNameExistParam(toggle.toggleName + "Toggle", controller.parameters);
    7.             if (existParam == false)
    8.             {
    9.                 controller.AddParameter(toggle.toggleName + "Toggle", AnimatorControllerParameterType.Bool);
    10.             }
    11.  
    12.             //Check if a layer already Exists with that name. If so, remove and add new one.
    13.             bool existLayer = doesNameExistLayer(toggle.toggleName, controller.layers);
    14.             if (existLayer)
    15.             {
    16.                 controller.RemoveLayer(controller.layers.Length-1);
    17.             }
    18.            
    19.             controller.AddLayer(toggle.toggleName);
    20.  
    21.             //Creating On and Off states
    22.             AnimatorState stateOn = new AnimatorState
    23.             {
    24.                 name = "ON",
    25.                 motion = (Motion)AssetDatabase.LoadAssetAtPath(saveDir + "ToggleAnimations" + $"/On{toggle.toggleName}.anim", typeof(Motion)),
    26.                 writeDefaultValues = false
    27.             };
    28.             AnimatorState stateOff = new AnimatorState
    29.             {
    30.                 name = "OFF",
    31.                 motion = (Motion)AssetDatabase.LoadAssetAtPath(saveDir + "ToggleAnimations" + $"/Off{toggle.toggleName}.anim", typeof(Motion)),
    32.                 writeDefaultValues = false
    33.             };
    34.             AnimatorState stateIdle = new AnimatorState
    35.             {
    36.                 name = "Idle",
    37.                 motion = (Motion)AssetDatabase.LoadAssetAtPath(saveDir + "ToggleAnimations" + $"/Idle{toggle.toggleName}.anim", typeof(Motion)),
    38.                 writeDefaultValues = true
    39.             };
    40.  
    41.             AnimatorController animatorController = controller;
    42.             var sm = animatorController.layers[controller.layers.Length - 1].stateMachine;
    43.  
    44.             // Adding created states to controller layer
    45.             controller.layers[controller.layers.Length - 1].stateMachine.AddState(stateIdle, new Vector3(300, 0, 0));
    46.             controller.layers[controller.layers.Length - 1].stateMachine.AddState(stateOff, new Vector3(100, -110, 0));
    47.             controller.layers[controller.layers.Length - 1].stateMachine.AddState(stateOn, new Vector3(300, -220, 0));
    48.  
    49.             // If True, go to ON state.
    50.             sm.states[2].state.AddTransition(sm.states[1].state);
    51.             sm.states[2].state.transitions[0].AddCondition(AnimatorConditionMode.IfNot, 0, toggle.toggleName + "Toggle");
    52.             sm.states[2].state.transitions[0].duration = 0.1f;
    53.  
    54.             // If False, go to Off state.
    55.             sm.states[0].state.AddTransition(sm.states[2].state);
    56.             sm.states[0].state.transitions[0].AddCondition(AnimatorConditionMode.If, 0, toggle.toggleName + "Toggle");
    57.             sm.states[0].state.transitions[0].duration = 0.1f;
    58.            
    59.             // Go to Idle after Off state immediately.
    60.             sm.states[1].state.AddTransition(sm.states[0].state);
    61.             sm.states[1].state.transitions[0].duration = 0.1f;
    62.             sm.states[1].state.transitions[0].hasExitTime = true;
    63.            
    64.             AssetDatabase.AddObjectToAsset(stateOn, AssetDatabase.GetAssetPath(controller));
    65.             AssetDatabase.AddObjectToAsset(stateOff, AssetDatabase.GetAssetPath(controller));
    66.             AssetDatabase.AddObjectToAsset(stateIdle, AssetDatabase.GetAssetPath(controller));
    67.            
    68.             //Set Layer Weight
    69.             AnimatorControllerLayer[] layers = controller.layers;
    70.             layers[controller.layers.Length - 1].defaultWeight = 1;
    71.             controller.layers = layers;
    72.         }
    73.         AssetDatabase.SaveAssets();
    74.     }
    Code (CSharp):
    1.     private void Postprocessing() // Ran at end
    2.     {
    3.         AssetDatabase.Refresh();
    4.         EditorUtility.SetDirty(controller);
    5.         AssetDatabase.SaveAssets();
    6.     }
    Update:
    I managed to keep the states on reload by adding this following code:
    Code (CSharp):
    1. AssetDatabase.AddObjectToAsset(stateOn, AssetDatabase.GetAssetPath(controller));
    2.             AssetDatabase.AddObjectToAsset(stateOff, AssetDatabase.GetAssetPath(controller));
    3.             AssetDatabase.AddObjectToAsset(stateIdle, AssetDatabase.GetAssetPath(controller));
     
  2. Cascadian215

    Cascadian215

    Joined:
    Dec 8, 2018
    Posts:
    2
    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!

    Code (CSharp):
    1. private void ApplyToAnimator()
    2.     {
    3.         foreach (var toggle in Toggles)
    4.         {
    5.             // Check if the parameter or layer already exists. If not, add parameter
    6.             bool existParam = doesNameExistParam(toggle.toggleName + "Toggle", controller.parameters);
    7.             if (existParam == false)
    8.             {
    9.                 controller.AddParameter(toggle.toggleName + "Toggle", UnityEngine.AnimatorControllerParameterType.Bool);
    10.             }
    11.  
    12.             //Check if a layer already Exists with that name. If so, remove and add new one.
    13.             bool existLayer = doesNameExistLayer(toggle.toggleName, controller.layers);
    14.             if (existLayer)
    15.             {
    16.                 controller.RemoveLayer(controller.layers.Length-1);
    17.             }
    18.            
    19.             controller.AddLayer(toggle.toggleName);
    20.  
    21.             AnimatorController animatorController = controller as AnimatorController;
    22.             var sm = animatorController.layers[controller.layers.Length - 1].stateMachine;
    23.  
    24.             sm.AddState("stateIdle", new Vector3(300, 0, 0));
    25.             sm.AddState("stateOn", new Vector3(300, -220, 0));
    26.             sm.AddState("stateOff", new Vector3(100, -110, 0));
    27.  
    28.             sm.states[0].state.name = "IDLE" + toggle.toggleName;
    29.             sm.states[0].state.motion = null;
    30.             sm.states[0].state.writeDefaultValues = true;
    31.            
    32.             sm.states[1].state.name = "ON" + toggle.toggleName;
    33.             sm.states[1].state.motion = (Motion)AssetDatabase.LoadAssetAtPath(saveDir + "ToggleAnimations" + $"/On{toggle.toggleName}.anim", typeof(Motion));
    34.             sm.states[1].state.writeDefaultValues = false;
    35.            
    36.             sm.states[2].state.name = "OFF" + toggle.toggleName;
    37.             sm.states[2].state.motion = (Motion)AssetDatabase.LoadAssetAtPath(saveDir + "ToggleAnimations" + $"/Off{toggle.toggleName}.anim", typeof(Motion));
    38.             sm.states[2].state.writeDefaultValues = false;
    39.  
    40.             sm.states[0].state.AddTransition(sm.states[1].state);
    41.             sm.states[0].state.transitions[0].AddCondition(AnimatorConditionMode.If, 0, toggle.toggleName + "Toggle");
    42.             sm.states[1].state.AddTransition(sm.states[2].state);
    43.             sm.states[1].state.transitions[0].AddCondition(AnimatorConditionMode.IfNot, 0, toggle.toggleName + "Toggle");
    44.             sm.states[2].state.AddTransition(sm.states[0].state);
    45.             sm.states[2].state.transitions[0].hasExitTime = true;
    46.  
    47.             //Set Layer Weight
    48.             AnimatorControllerLayer[] layers = controller.layers;
    49.             layers[controller.layers.Length - 1].defaultWeight = 1;
    50.             controller.layers = layers;
    51.         }
    52.     }