Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. We have updated the language to the Editor Terms based on feedback from our employees and community. Learn more.
    Dismiss Notice
  3. Join us on November 16th, 2023, between 1 pm and 9 pm CET for Ask the Experts Online on Discord and on Unity Discussions.
    Dismiss Notice

Script to Copy StateMachines/Whole Controllers

Discussion in 'Immediate Mode GUI (IMGUI)' started by mambo_2, Jun 9, 2015.

  1. mambo_2

    mambo_2

    Joined:
    Aug 19, 2013
    Posts:
    19
    Hello,

    Below you can find a script I made to copy state machines with their transitions from one controller to the other, this preserved all the transition exit times, interruption sources, etc... everything I need to use when I wrote it. the code is not clean and a bit clamped so if anyone wants to modify it and make it better by all means.. do so.

    it has not been tested thoroughly and currently it is setup to copy one layer but once you have one layer down it is not too hard to copy the rest.


    a few pointers before using it:

    - modify the clearing script, either to avoid copying or to clear the controller before copying.
    - BlendTrees need testing, I think one of the problem is referencing the same motion from the source.
    - modify to include all layers.
    - if I had the time I would list the states before copying them so I can choose which one I want and which one I do not, maybe even use a node editor inside the window, up to you and how free you are but it's an idea.



    Code (CSharp):
    1. using UnityEngine;
    2. using UnityEditor;
    3. using UnityEditorInternal;
    4. using System.Collections;
    5. using System.Reflection;
    6.  
    7. public class CopyController : EditorWindow
    8. {
    9.     UnityEditor.Animations.AnimatorController source;
    10.     UnityEditor.Animations.AnimatorController destination;
    11.     UnityEditor.Animations.AnimatorState newState;
    12.     UnityEditor.Animations.AnimatorState destinationState;
    13.     UnityEditor.Animations.AnimatorState defaultState;
    14.     UnityEditor.Animations.AnimatorStateMachine newStateMachine;
    15.     UnityEditor.Animations.AnimatorStateTransition newTransition;
    16.     UnityEditor.Animations.AnimatorTransition newEntryTransition;
    17.  
    18.     Vector3 entryStatePosition;
    19.     bool isExit;
    20.     string defaultStateName;
    21.  
    22.     [MenuItem("Helpers/Copy Controller")]
    23.     static void GetWindow()
    24.     {
    25.         EditorWindow.GetWindow(typeof(CopyController));
    26.     }
    27.  
    28.     void OnGUI()
    29.     {
    30.         source = EditorGUILayout.ObjectField("Source", source, typeof(UnityEditor.Animations.AnimatorController), true, GUILayout.ExpandWidth(true)) as UnityEditor.Animations.AnimatorController;
    31.         destination = EditorGUILayout.ObjectField("Destination", destination, typeof(UnityEditor.Animations.AnimatorController), true, GUILayout.ExpandWidth(true)) as UnityEditor.Animations.AnimatorController;
    32.  
    33.         GUILayout.Space(100);
    34.  
    35.  
    36.         if (GUILayout.Button("Copy", GUILayout.ExpandWidth(true), GUILayout.Height(50)))
    37.         {
    38.             if (source != null && destination != null)
    39.                 Copy();
    40.         }
    41.  
    42.  
    43.         GUILayout.Space(10);
    44.  
    45.         //if (GUILayout.Button("Clear", GUILayout.ExpandWidth(true), GUILayout.Height(50)))
    46.         //{
    47.         //    if (source != null && destination != null)
    48.         //        Clear();
    49.         //}
    50.     }
    51.  
    52.  
    53.     void ClearDestination()
    54.     {
    55.         //Clear Transitions.
    56.         for (int j = 0; j < destination.layers[0].stateMachine.states.Length; j++)
    57.         {
    58.             while (destination.layers[0].stateMachine.states[j].state.transitions.Length != 0)
    59.             {
    60.                 for (int k = 0; k < destination.layers[0].stateMachine.states[j].state.transitions.Length; k++)
    61.                 {
    62.                     destination.layers[0].stateMachine.states[j].state.RemoveTransition(destination.layers[0].stateMachine.states[j].state.transitions[k]);
    63.                 }
    64.             }
    65.         }
    66.  
    67.  
    68.         //Clear Parameters.
    69.         while (destination.layers[0].stateMachine.states.Length != 0)
    70.         {
    71.             for (int j = 0; j < destination.layers[0].stateMachine.states.Length; j++)
    72.             {
    73.                 destination.layers[0].stateMachine.RemoveState(destination.layers[0].stateMachine.states[j].state);
    74.  
    75.             }
    76.         }
    77.  
    78.  
    79.         //Clear States.
    80.         while (destination.parameters.Length > 0)
    81.         {
    82.  
    83.             for (int j = 0; j < destination.parameters.Length; j++)
    84.             {
    85.                 destination.RemoveParameter(destination.parameters[j]);
    86.             }
    87.         }
    88.     }
    89.  
    90.     void Copy()
    91.     {
    92.  
    93.         ClearDestination();
    94.  
    95.  
    96.         //Copy Parameters
    97.         for (int i = 0; i < source.parameters.Length; i++)
    98.         {
    99.             destination.AddParameter(source.parameters[i].name, source.parameters[i].type);
    100.         }
    101.  
    102.         CopyStates(source.layers[0].stateMachine, destination.layers[0].stateMachine, destination.layers[0]);
    103.         CopyTransitions(source.layers[0].stateMachine, destination.layers[0].stateMachine, destination.layers[0]);
    104.         SetDefaultState(source.layers[0].stateMachine, destination.layers[0].stateMachine);
    105.     }
    106.  
    107.  
    108.     void SetDefaultState(UnityEditor.Animations.AnimatorStateMachine stateMachine, UnityEditor.Animations.AnimatorStateMachine destinationStateMachine)
    109.     {
    110.         for(int i = 0; i < destinationStateMachine.states.Length ; i++)
    111.         {
    112.             if (destinationStateMachine.states[i].state.name == stateMachine.defaultState.name)
    113.                 destinationStateMachine.defaultState = destinationStateMachine.states[i].state;
    114.         }
    115.  
    116.         for (int i = 0; i < destinationStateMachine.stateMachines.Length; i++)
    117.         {
    118.             for (int j = 0; j < destinationStateMachine.stateMachines[i].stateMachine.states.Length; j++)
    119.             {
    120.                 if (destinationStateMachine.stateMachines[i].stateMachine.states[j].state.name == stateMachine.defaultState.name)
    121.                     destinationStateMachine.defaultState = destinationStateMachine.stateMachines[i].stateMachine.states[j].state;
    122.             }
    123.         }
    124.     }
    125.  
    126.  
    127.  
    128.     void CopyStates(UnityEditor.Animations.AnimatorStateMachine stateMachine, UnityEditor.Animations.AnimatorStateMachine destinationStateMachine, UnityEditor.Animations.AnimatorControllerLayer destinationLayer)
    129.     {
    130.         destinationStateMachine.exitPosition = stateMachine.exitPosition;
    131.         destinationStateMachine.entryPosition = stateMachine.entryPosition;
    132.         destinationStateMachine.anyStatePosition = stateMachine.anyStatePosition;
    133.  
    134.  
    135.         //Copy States
    136.         for (int i = 0; i < stateMachine.states.Length; i++)
    137.         {
    138.             newState = destinationStateMachine.AddState(stateMachine.states[i].state.name, stateMachine.states[i].position);
    139.             newState.speed = stateMachine.states[i].state.speed;
    140.  
    141.  
    142.  
    143.  
    144.             if (stateMachine.states[i].state.motion != null)
    145.             {
    146.                 if (stateMachine.states[i].state.motion.GetType() == typeof(AnimationClip))
    147.                 {
    148.                     newState.motion = stateMachine.states[i].state.motion;
    149.                 }
    150.                 else
    151.                 {
    152.                     if (stateMachine.states[i].state.motion.GetType() == typeof(UnityEditor.Animations.BlendTree))
    153.                     {
    154.                         UnityEditor.Animations.BlendTree oldBlendTree = stateMachine.states[i].state.motion as UnityEditor.Animations.BlendTree;
    155.                         UnityEditor.Animations.BlendTree newBlendTree = new UnityEditor.Animations.BlendTree();
    156.  
    157.  
    158.                         SerializedObject SO = new SerializedObject(newBlendTree);
    159.                         SerializedProperty SP = SO.GetIterator();
    160.  
    161.                         SP = SO.FindProperty("m_UseAutomaticThresholds");
    162.                         SP.boolValue = false;
    163.                         SO.ApplyModifiedProperties();
    164.  
    165.                         newBlendTree.blendParameter = oldBlendTree.blendParameter;
    166.                         newBlendTree.blendType = oldBlendTree.blendType;
    167.  
    168.                         for (int j = 0; j < oldBlendTree.children.Length; j++)
    169.                         {
    170.                             newBlendTree.AddChild(oldBlendTree.children[j].motion, oldBlendTree.children[j].threshold);
    171.                         }
    172.  
    173.                         for (int j = 0; j < oldBlendTree.children.Length; j++)
    174.                         {
    175.                             UnityEditor.Animations.ChildMotion[] newChildren = newBlendTree.children;
    176.                             newChildren[j].timeScale = oldBlendTree.children[j].timeScale;
    177.                             newChildren[j].position = oldBlendTree.children[j].position;
    178.                             newChildren[j].threshold = oldBlendTree.children[j].threshold;
    179.                             newChildren[j].directBlendParameter = oldBlendTree.children[j].directBlendParameter;
    180.                             newBlendTree.children = newChildren;
    181.                         }
    182.  
    183.                         newState.motion = newBlendTree;
    184.                     }
    185.                 }
    186.             }
    187.         }
    188.  
    189.  
    190.  
    191.         //Set Default State
    192.         for (int i = 0; i < destinationStateMachine.states.Length; i++)
    193.         {
    194.             if (destinationStateMachine.states[i].state.name == defaultStateName)
    195.             {
    196.                 destinationStateMachine.defaultState = destinationStateMachine.states[i].state;
    197.                 break;
    198.             }
    199.         }
    200.  
    201.  
    202.         //Copy Substate Machines
    203.         for (int i = 0; i < stateMachine.stateMachines.Length; i++)
    204.         {
    205.             newStateMachine = new UnityEditor.Animations.AnimatorStateMachine();
    206.             newStateMachine.name = stateMachine.stateMachines[i].stateMachine.name;
    207.             destinationStateMachine.AddStateMachine(newStateMachine.name, stateMachine.stateMachines[i].position);
    208.             CopyStates(stateMachine.stateMachines[i].stateMachine, destinationStateMachine.stateMachines[i].stateMachine, destinationLayer);
    209.         }
    210.  
    211.  
    212.         for (int i = 0; i < stateMachine.stateMachines.Length; i++)
    213.         {
    214.             CopyTransitions(stateMachine.stateMachines[i].stateMachine, destinationStateMachine.stateMachines[i].stateMachine, destinationLayer);
    215.         }
    216.        
    217.     }
    218.  
    219.  
    220.     void CopyTransitions(UnityEditor.Animations.AnimatorStateMachine stateMachine, UnityEditor.Animations.AnimatorStateMachine destinationStateMachine, UnityEditor.Animations.AnimatorControllerLayer destinationLayer)
    221.     {
    222.  
    223.         destinationStateMachine.parentStateMachinePosition = stateMachine.parentStateMachinePosition;
    224.  
    225.  
    226.         //Copy Any Transition
    227.         for (int i = 0; i < stateMachine.anyStateTransitions.Length; i++)
    228.         {
    229.             if (stateMachine.anyStateTransitions[i].destinationState != null)
    230.             {
    231.                 for (int n = 0; n < destinationStateMachine.states.Length; n++)
    232.                 {
    233.                     if (destinationStateMachine.states[n].state.name == stateMachine.anyStateTransitions[i].destinationState.name)
    234.                     {
    235.                         destinationState = destinationStateMachine.states[n].state;
    236.                     }
    237.                 }
    238.  
    239.  
    240.                 newTransition = destinationStateMachine.AddAnyStateTransition(destinationState);
    241.                 newTransition.conditions = stateMachine.anyStateTransitions[i].conditions;
    242.                 newTransition.canTransitionToSelf = stateMachine.anyStateTransitions[i].canTransitionToSelf;
    243.                 newTransition.hasExitTime = stateMachine.anyStateTransitions[i].hasExitTime;
    244.                 newTransition.exitTime = stateMachine.anyStateTransitions[i].exitTime;
    245.                 newTransition.duration = stateMachine.anyStateTransitions[i].duration;
    246.                 newTransition.interruptionSource = stateMachine.anyStateTransitions[i].interruptionSource;
    247.             }
    248.             else
    249.             {
    250.                 for (int n = 0; n < destinationStateMachine.stateMachines.Length; n++)
    251.                 {
    252.                     if (destinationStateMachine.stateMachines[n].stateMachine.name == stateMachine.anyStateTransitions[i].destinationStateMachine.name)
    253.                     {
    254.                         newStateMachine = destinationStateMachine.stateMachines[n].stateMachine;
    255.                     }
    256.                 }
    257.  
    258.                 newTransition = destinationStateMachine.AddAnyStateTransition(newStateMachine);
    259.                 newTransition.conditions = stateMachine.anyStateTransitions[i].conditions;
    260.                 newTransition.canTransitionToSelf = stateMachine.anyStateTransitions[i].canTransitionToSelf;
    261.                 newTransition.hasExitTime = stateMachine.anyStateTransitions[i].hasExitTime;
    262.                 newTransition.exitTime = stateMachine.anyStateTransitions[i].exitTime;
    263.                 newTransition.duration = stateMachine.anyStateTransitions[i].duration;
    264.                 newTransition.interruptionSource = stateMachine.anyStateTransitions[i].interruptionSource;
    265.             }
    266.         }
    267.  
    268.  
    269.         //Copy Entry Transitions
    270.         for (int i = 0; i < stateMachine.entryTransitions.Length; i++)
    271.         {
    272.             if (stateMachine.entryTransitions[i].destinationState != null)
    273.             {
    274.                 for (int n = 0; n < destinationStateMachine.states.Length; n++)
    275.                 {
    276.                     if (destinationStateMachine.states[n].state.name == stateMachine.entryTransitions[i].destinationState.name)
    277.                     {
    278.                         destinationState = destinationStateMachine.states[n].state;
    279.                     }
    280.                 }
    281.  
    282.                 newEntryTransition = destinationStateMachine.AddEntryTransition(destinationState);
    283.                 newEntryTransition.conditions = stateMachine.entryTransitions[i].conditions;
    284.             }
    285.             else
    286.             {
    287.                 for (int n = 0; n < destinationStateMachine.stateMachines.Length; n++)
    288.                 {
    289.                     if (destinationStateMachine.stateMachines[n].stateMachine.name == stateMachine.entryTransitions[i].destinationStateMachine.name)
    290.                     {
    291.                         newStateMachine = destinationStateMachine.stateMachines[n].stateMachine;
    292.                     }
    293.                 }
    294.  
    295.                 newEntryTransition = destinationStateMachine.AddEntryTransition(newStateMachine);
    296.                 newEntryTransition.conditions = stateMachine.anyStateTransitions[i].conditions;
    297.             }
    298.         }
    299.  
    300.  
    301.  
    302.         //Copy State Transitions
    303.         for (int i = 0; i < stateMachine.states.Length; i++)
    304.         {
    305.             for (int j = 0; j < stateMachine.states[i].state.transitions.Length; j++)
    306.             {
    307.                 if (stateMachine.states[i].state.transitions[j].destinationState != null)
    308.                 {
    309.                     for (int n = 0; n < destinationStateMachine.states.Length; n++)
    310.                     {
    311.                         if (destinationStateMachine.states[n].state.name == stateMachine.states[i].state.transitions[j].destinationState.name)
    312.                         {
    313.                             newStateMachine = null;
    314.                             destinationState = destinationStateMachine.states[n].state;
    315.                         }
    316.                     }
    317.  
    318.                     for (int n = 0; n < destinationLayer.stateMachine.states.Length; n++)
    319.                     {
    320.                         if (destinationLayer.stateMachine.states[n].state.name == stateMachine.states[i].state.transitions[j].destinationState.name)
    321.                         {
    322.                             newStateMachine = null;
    323.                             destinationState = destinationLayer.stateMachine.states[n].state;
    324.                         }
    325.                     }
    326.  
    327.  
    328.                     for (int n = 0; n < destinationLayer.stateMachine.stateMachines.Length; n++)
    329.                     {
    330.                         for (int m = 0; m < destinationLayer.stateMachine.stateMachines[n].stateMachine.states.Length; m++)
    331.                         {
    332.                             if (destinationLayer.stateMachine.stateMachines[n].stateMachine.states[m].state.name == stateMachine.states[i].state.transitions[j].destinationState.name)
    333.                             {
    334.                                 newStateMachine = null;
    335.                                 destinationState = destinationLayer.stateMachine.stateMachines[n].stateMachine.states[m].state;
    336.                             }
    337.                         }
    338.                     }
    339.  
    340.  
    341.  
    342.  
    343.                  
    344.                    newTransition = destinationStateMachine.states[i].state.AddTransition(destinationState);
    345.  
    346.                    if (stateMachine.states[i].state.transitions[j].isExit)
    347.                        newTransition.isExit = stateMachine.states[i].state.transitions[j].isExit;
    348.  
    349.                    newTransition.hasExitTime = stateMachine.states[i].state.transitions[j].hasExitTime;
    350.                    newTransition.exitTime = stateMachine.states[i].state.transitions[j].exitTime;
    351.                    newTransition.canTransitionToSelf = stateMachine.states[i].state.transitions[j].canTransitionToSelf;
    352.                    newTransition.conditions = stateMachine.states[i].state.transitions[j].conditions;
    353.                    newTransition.duration = stateMachine.states[i].state.transitions[j].duration;
    354.                    newTransition.interruptionSource = stateMachine.states[i].state.transitions[j].interruptionSource;
    355.                    newTransition.orderedInterruption = stateMachine.states[i].state.transitions[j].orderedInterruption;
    356.  
    357.  
    358.                 }
    359.                 else
    360.                 {
    361.                     for (int n = 0; n < destinationStateMachine.stateMachines.Length; n++)
    362.                     {
    363.                         if (destinationStateMachine.stateMachines[n].stateMachine.name == stateMachine.states[i].state.transitions[j].destinationStateMachine.name)
    364.                         {
    365.                             newStateMachine = destinationStateMachine.stateMachines[n].stateMachine;
    366.                             destinationState = null;
    367.                         }
    368.                     }
    369.  
    370.                     newTransition = destinationStateMachine.states[i].state.AddTransition(newStateMachine);
    371.  
    372.                     if (stateMachine.states[i].state.transitions[j].isExit)
    373.                         newTransition.isExit = stateMachine.states[i].state.transitions[j].isExit;
    374.  
    375.                     newTransition.hasExitTime = stateMachine.states[i].state.transitions[j].hasExitTime;
    376.                     newTransition.canTransitionToSelf = stateMachine.states[i].state.transitions[j].canTransitionToSelf;
    377.                     newTransition.conditions = stateMachine.states[i].state.transitions[j].conditions;
    378.                     newTransition.duration = stateMachine.states[i].state.transitions[j].duration;
    379.                     newTransition.interruptionSource = stateMachine.states[i].state.transitions[j].interruptionSource;
    380.                     newTransition.orderedInterruption = stateMachine.states[i].state.transitions[j].orderedInterruption;
    381.                 }
    382.             }
    383.         }
    384.     }
    385. }
     
  2. Deleted User

    Deleted User

    Guest

    Seems like only a few people need this script and I am one of them!
    Recently I made a lot of animations and then I gave up to edit every setting of the transitions.
    I will try this and blend tree, wish I could solve this.
    Thanks so much for your code! Cheers!
     
  3. Aedous

    Aedous

    Joined:
    Jun 20, 2009
    Posts:
    244
    You're not the only one :D, I've actually been thinking to code something like this as I'm working with a lot of animations and need a way to quickly create a base controller when creating a new character, tweak events on animations, modify positioning of frames basically trying to add functionality to the animation window.

    Thanks a lot for this, gives me a head start on trying to wrap my head around it :p.
     
  4. v2-Ton-Studios

    v2-Ton-Studios

    Joined:
    Jul 18, 2012
    Posts:
    237
    Malbers likes this.