FBX animation properties inspector, events with code

need to edit fbx animations with code:
http://screencast.com/t/eoSdcJzQ
this is the inspector part where it can be edited without changing exported animation
(animation tab of fbx properties inspector)

P.S. there is a way to do it for separate animations, but in this case I would like to change import settings, not the animation itself.

AnimationUtility.SetAnimationEvents(c, new AnimationEvent[] { 
                        new AnimationEvent() { functionName = "onEvent", floatParameter = c.length, intParameter = 0 ,time = 0}
                    });

Made a little Editor Script:

  • Setting Animation Events in export settings

  • Exporting editable clones

  • Setting Clones for Animation component

    using System.Collections.Generic;
    using System.Linq;
    using UnityEditor;
    using UnityEngine;

    public class AnimationProperties
    {
    public readonly string Name;
    public readonly float Length;

     public float procTime = 0;
     public AnimationProperties(string Name, float Length)
     {
         // TODO: Complete member initialization
         this.Name = Name;
         this.Length = Length;
     }
    

    }
    public class FBXEventEditor : EditorWindow
    {
    private const string ANIMATION_FOLDER = “Animation”;

     [MenuItem("Animation/EBX animation events")]
     public static void ShowWindow()
     {
         EditorWindow.GetWindow(typeof(FBXEventEditor));
     }
     Object _targetObject;
     Object obj;
     List<AnimationProperties> animationProperties = new List<AnimationProperties>();
    
    
     void OnGUI()
     {
         obj = EditorGUILayout.ObjectField("FBX Asset", obj, typeof(GameObject), false);
    
    
         if (GUILayout.Button("ReRead"))
         {
             _targetObject = null;
         }
    
         if (obj != _targetObject)
         {
             _targetObject = obj;
             UpdateAnimationList();
         }
    
         EditorGUILayout.BeginHorizontal();
         GUILayout.Label("Name", GUILayout.Width(100));
         GUILayout.Label("Length", GUILayout.Width(43));
         GUILayout.Label("Proc", GUILayout.Width(43));
         EditorGUILayout.EndHorizontal();
         for (int i = 0; i < animationProperties.Count; i++)
         {
             AnimationProperties ap = animationProperties*;*
    

EditorGUILayout.BeginHorizontal();
GUILayout.Label(ap.Name, GUILayout.Width(100));
GUILayout.Label(ap.Length.ToString(), GUILayout.Width(43));
ap.procTime = EditorGUILayout.Slider(ap.procTime, 0, 1);
EditorGUILayout.EndHorizontal();
}

if (GUILayout.Button(“Set import events”))
{
SaveExportSettings();
}
GUILayout.Space(20);
if (GUILayout.Button(“Export Editable”))
{
ExportEditable();
}

if (GUILayout.Button(“Set exported 2 selected”))
{
SetAnimationClips();
}
}

private void ExportEditable()
{

AssetDatabase.Refresh(ImportAssetOptions.ForceUpdate);

string path = AssetDatabase.GetAssetPath(obj);

Object[] assets = AssetDatabase.LoadAllAssetsAtPath(path);
List clips = assets.ToList().Where(x => x is AnimationClip && !x.name.Contains(“preview”)).Cast().ToList();

string clipFolder = System.IO.Path.Combine(System.IO.Directory.GetParent(path).ToString(), ANIMATION_FOLDER);
if (!AssetExtentions.DirectoryExists(clipFolder))
{
Debug.Log(“Create folder”);
AssetDatabase.CreateFolder(System.IO.Directory.GetParent(path).ToString(), ANIMATION_FOLDER);
}

foreach (AnimationClip sourceClip in clips)
{
AnimationProperties ap = animationProperties.Where(x => x.Name == sourceClip.name).FirstOrDefault();
if (ap != null)
{
string clipPath = clipFolder + “/” + sourceClip.name + “.anim”;
Debug.Log(string.Format(“Saving: {0} at {1}”, sourceClip.name, clipPath));
AnimationClip destClip = AssetDatabase.LoadAssetAtPath(clipPath, typeof(AnimationClip)) as AnimationClip;
if (destClip == null)
{
Debug.Log(“new clip”);
destClip = new AnimationClip();
AssetDatabase.CreateAsset(destClip, clipPath);
}
EditorUtility.CopySerialized(sourceClip, destClip);
List events = new List();
events.Add(new AnimationEvent() { time = 0, functionName = “onAnimationEvent”, intParameter = (int)AnimationEventType.Start, stringParameter = destClip.name });
events.Add(new AnimationEvent() { time = destClip.length, functionName = “onAnimationEvent”, intParameter = (int)AnimationEventType.End, stringParameter = destClip.name });
if (ap.procTime != 0)
{
events.Add(new AnimationEvent() { time = destClip.length * ap.procTime, functionName = “onAnimationEvent”, intParameter = (int)AnimationEventType.Proc, stringParameter = destClip.name });
}

AnimationUtility.SetAnimationEvents(destClip, events.ToArray());
}
else
{
Debug.LogWarning(“not found settings WTF?!:” + sourceClip.name);
}

}

Debug.Log(string.Join(“,”, clips.Select(x => x.name).ToArray()));

AssetDatabase.SaveAssets();
AssetDatabase.Refresh(ImportAssetOptions.ForceUpdate);
Debug.Log(“Export Done”);
//AssetDatabase.ImportAsset(AssetDatabase.GetAssetPath(_targetObject));
}

private void SaveExportSettings()
{
ModelImporter modelImporter = (ModelImporter)AssetImporter.GetAtPath(AssetDatabase.GetAssetPath(obj));

SerializedObject so = new SerializedObject(modelImporter);

SerializedProperty clips = so.FindProperty(“m_ClipAnimations”);
List<AnimationEvent[]> animationEvents = new List<AnimationEvent[]>(modelImporter.clipAnimations.Length);

for (int i = 0; i < modelImporter.clipAnimations.Length; i++)
{
modelImporter.clipAnimations*.wrapMode = WrapMode.ClampForever;*
List events = new List();
//events.AddRange(GetEvents(clips.GetArrayElementAtIndex(i)));//if we need 2 use old events
events.Add(new AnimationEvent() { stringParameter = animationProperties*.Name, functionName = “onAnimationEvent”, time = 0, intParameter = 0 });*
if (animationProperties*.procTime != 0)*
events.Add(new AnimationEvent() { stringParameter = animationProperties_.Name, functionName = “onAnimationEvent”, time = animationProperties*.procTime, intParameter = 1 });*_

events.Add(new AnimationEvent() { stringParameter = animationProperties*.Name, functionName = “onAnimationEvent”, time = 1, intParameter = 2 });*
animationEvents.Add(events.ToArray());
}

// Make your changes and write them by setting clipAnimations, destroying the events.
modelImporter.clipAnimations = modelImporter.clipAnimations;

for (int i = 0; i < modelImporter.clipAnimations.Length; i++)
{

SetEvents(clips.GetArrayElementAtIndex(i), animationEvents*);*
}
so.SetIsDifferentCacheDirty();
so.ApplyModifiedProperties();
AssetDatabase.SaveAssets();
AssetDatabase.ImportAsset(AssetDatabase.GetAssetPath(_targetObject));
}

private void UpdateAnimationList()
{
animationProperties.Clear();
ModelImporter modelImporter = (ModelImporter)AssetImporter.GetAtPath(AssetDatabase.GetAssetPath(_targetObject));
SerializedObject so = new SerializedObject(modelImporter);
SerializedProperty clips = so.FindProperty(“m_ClipAnimations”);
for (int i = 0; i < modelImporter.clipAnimations.Length; i++)
{
ModelImporterClipAnimation iClipAnim = modelImporter.clipAnimations*;*
animationProperties.Add(new AnimationProperties(iClipAnim.name, modelImporter.clipAnimations_.lastFrame - modelImporter.clipAnimations*.firstFrame));
}*_

}

private void SetAnimationClips()
{
Animation targetAnimationComponent = Selection.activeGameObject.animation;

if (targetAnimationComponent == null)
{
ShowNotification(new GUIContent(“No animation selected!”, “Select a gameobject with animation component.”));
}
else
{
WrapMode savedWrapMode = targetAnimationComponent.wrapMode;
bool savedPlayAutomaticallyState = targetAnimationComponent.playAutomatically;
bool savedAnimatePhysicsState = targetAnimationComponent.animatePhysics;

DestroyImmediate(targetAnimationComponent);

targetAnimationComponent = Selection.activeGameObject.AddComponent();
targetAnimationComponent.wrapMode = savedWrapMode;
targetAnimationComponent.playAutomatically = savedPlayAutomaticallyState;
targetAnimationComponent.animatePhysics = savedAnimatePhysicsState;

string path = AssetDatabase.GetAssetPath(obj);
Object[] assets = AssetDatabase.LoadAllAssetsAtPath(path);
List clips = assets.ToList().Where(x => x is AnimationClip && !x.name.Contains(“preview”)).Cast().ToList();

string clipFolder = System.IO.Path.Combine(System.IO.Directory.GetParent(path).ToString(), ANIMATION_FOLDER);

foreach (AnimationClip sourceClip in clips)
{
string clipPath = clipFolder + “/” + sourceClip.name + “.anim”;
AnimationClip destClip = AssetDatabase.LoadAssetAtPath(clipPath, typeof(AnimationClip)) as AnimationClip;
targetAnimationComponent.AddClip(destClip, destClip.name);

if (targetAnimationComponent.clip == null)
{
targetAnimationComponent.clip = destClip;
}
}
}
}

public AnimationEvent[] GetEvents(SerializedProperty sp)
{
SerializedProperty serializedProperty = sp.FindPropertyRelative(“events”);
AnimationEvent[] array = null;

if (serializedProperty != null && serializedProperty.isArray)
{
int count = serializedProperty.arraySize;
array = new AnimationEvent[count];

for (int i = 0; i < count; i++)
{
AnimationEvent animationEvent = new AnimationEvent();

SerializedProperty eventProperty = serializedProperty.GetArrayElementAtIndex(i);
animationEvent.floatParameter = eventProperty.FindPropertyRelative(“floatParameter”).floatValue;
animationEvent.functionName = eventProperty.FindPropertyRelative(“functionName”).stringValue;
animationEvent.intParameter = eventProperty.FindPropertyRelative(“intParameter”).intValue;
animationEvent.objectReferenceParameter = eventProperty.FindPropertyRelative(“objectReferenceParameter”).objectReferenceValue;
animationEvent.stringParameter = eventProperty.FindPropertyRelative(“data”).stringValue;
animationEvent.time = eventProperty.FindPropertyRelative(“time”).floatValue;
array = animationEvent;
}
}
return array;
}

public void SetEvents(SerializedProperty sp, AnimationEvent[] newEvents)
{
SerializedProperty serializedProperty = sp.FindPropertyRelative(“events”);
if (serializedProperty != null && serializedProperty.isArray && newEvents != null && newEvents.Length > 0)
{
serializedProperty.ClearArray();
for (int i = 0; i < newEvents.Length; i++)
{
AnimationEvent animationEvent = newEvents*;*
serializedProperty.InsertArrayElementAtIndex(serializedProperty.arraySize);

SerializedProperty eventProperty = serializedProperty.GetArrayElementAtIndex(i);
eventProperty.FindPropertyRelative(“floatParameter”).floatValue = animationEvent.floatParameter;
eventProperty.FindPropertyRelative(“functionName”).stringValue = animationEvent.functionName;
eventProperty.FindPropertyRelative(“intParameter”).intValue = animationEvent.intParameter;
eventProperty.FindPropertyRelative(“objectReferenceParameter”).objectReferenceValue = animationEvent.objectReferenceParameter;
eventProperty.FindPropertyRelative(“data”).stringValue = animationEvent.stringParameter;
eventProperty.FindPropertyRelative(“time”).floatValue = animationEvent.time;
}
}
}
}