Created
May 10, 2024 07:07
-
-
Save unitycoder/53689b2cfac470f7561a283fcd19934b to your computer and use it in GitHub Desktop.
FBX Animation Organizer
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// https://forum.unity.com/threads/reordering-fbx-animation-clips.1168847/#post-9825564 | |
/******************* | |
WARNING: MAKE SURE YOUR METADATA FILES ARE BACKED UP WITH VERSION CONTROL BEFORE USING | |
Installation: | |
Copy this C# script into Scripts\Editor. | |
Usage: | |
1) To open, go to Window -> FBX Animation Organizer | |
2) Enter the local directory location of your fbx meta files in the "Directory" field (Right click on the folder in Project window -> Copy Path) | |
3) Select the meta file to edit from the "File" dropdown | |
4) Press the "Import Metadata" button | |
5) Select the animations and move them with the "Move Up" or "Move Down" buttons | |
6) Press "Overwrite Metadata" button to save and overwrite the old metadata file | |
7) Press "Refresh Inspector" to update your changes | |
Known Bugs: | |
1) Pressing "Overwrite Metadata" 2x in a row will duplicate the animations list. | |
1) Pressing "Overwrite Metadata" again after changing the meta file, but not importing the new metafile will cause errors | |
******************/ | |
using UnityEngine; | |
using UnityEditor; | |
using System.Collections.Generic; | |
using System.Linq; | |
using System.IO; | |
public class FBXAnimationOrganizer : EditorWindow { | |
GUIStyle itemStyle = new GUIStyle(); | |
string inputPath = "Assets\\"; | |
string fileName; | |
List<string> metadataHeader = new List<string>(); | |
List<string> metadata = new List<string>(); | |
List<List<string>> animations = new List<List<string>>(); //List that holds each animation's data as another list | |
List<string> animNames = new List<string>(); //List of animation names | |
int selectedAnimationIndex = -1; | |
int selectedFileNameIndex = -1; | |
[MenuItem("Window/FBX Animation Organizer")] | |
static void Init() { | |
var window = GetWindow(typeof(FBXAnimationOrganizer)); | |
window.titleContent = new GUIContent("FBX Animation Organizer"); | |
window.Show(); | |
} | |
private void OnGUI() { | |
//Directory Field | |
inputPath = EditorGUILayout.TextField("Directory:", inputPath); | |
if (GUI.changed) { | |
inputPath = EditorGUILayout.TextField(inputPath); | |
GUILayout.Label(fileName); | |
} | |
//Metadata File Dropdown | |
GUILayout.BeginHorizontal(); | |
if (Directory.Exists(inputPath)) { | |
GUILayout.Label("File:"); | |
int oldSelectedFileNameIndex = selectedFileNameIndex; | |
string[] filesUnedited = Directory.GetFiles(inputPath, "*meta", SearchOption.AllDirectories); | |
//Edit the filename so it looks nice | |
string[] filesEdited = new string[filesUnedited.Count()]; | |
for (var i = 0; i < filesUnedited.Count(); i++) { | |
filesEdited[i] = filesUnedited[i]; | |
int lastSlash = filesEdited[i].LastIndexOf("\\"); | |
filesEdited[i] = filesEdited[i].Substring(lastSlash + 1, filesEdited[i].Count() - 1 - lastSlash); | |
} | |
selectedFileNameIndex = EditorGUILayout.Popup(selectedFileNameIndex, filesEdited); | |
if (selectedFileNameIndex != -1) fileName = filesEdited[selectedFileNameIndex]; | |
//Clear out data if selecting a new file | |
if (oldSelectedFileNameIndex != selectedFileNameIndex) { | |
ClearData(); | |
} | |
} | |
GUILayout.EndHorizontal(); | |
GUILayout.BeginHorizontal(); | |
//Import Metadata Button | |
if (GUILayout.Button("Import Metadata")) { | |
ClearData(); | |
//Read the input file into a list and copy them to another list for editing | |
var logFile = File.ReadAllLines(inputPath + "\\" + fileName); | |
metadata = new List<string>(logFile); | |
//Get the header of the metadata file | |
int pTo = metadata.IndexOf(" clipAnimations:"); | |
for (int x = 0; x <= pTo; x++) { | |
metadataHeader.Add(metadata[0]); | |
metadata.RemoveAt(0); | |
} | |
//Get all the animation data | |
for (int i = 0; i <= 50; i++) { | |
//Get the start and end points of the animation entry | |
int pFrom = metadata.IndexOf(" - serializedVersion: 16"); | |
pTo = metadata.IndexOf(" additiveReferencePoseFrame: 0"); | |
//Exit when you get the last entry | |
if (pFrom < 0) break; | |
//Add the names and animation entries to the respective lists | |
animNames.Add(metadata[pFrom + 1].Replace(" name: ", "")); | |
//Save the animation entry and remove from the edited metadata | |
List<string> animData = new List<string>(); | |
for (int x = 0; x <= pTo - pFrom; x++) { | |
animData.Insert(0, metadata[pFrom]); | |
metadata.RemoveAt(pFrom); | |
} | |
animations.Add(animData); | |
} | |
} | |
//Overwrite Metadata Button | |
if (GUILayout.Button("Overwrite Metadata")) { | |
string savePath = inputPath + "/" + fileName; | |
using StreamWriter sw = new StreamWriter(savePath, false); | |
//Copy in the animations | |
for (int i = animations.Count() - 1; i >= 0; i--) { | |
foreach (string entry in animations[i]) | |
metadata.Insert(0, entry); | |
} | |
//Copy in the header | |
for (var i = metadataHeader.Count() - 1; i >= 0; i--) { | |
metadata.Insert(0, metadataHeader[i]); | |
} | |
//Write all the lines into the metadata file | |
for (int i = 0; i < metadata.Count(); i++) { | |
sw.WriteLine(metadata[i]); | |
} | |
Debug.Log("Saved " + savePath); | |
} | |
GUILayout.EndHorizontal(); | |
//Refresh Button - updates the inspector | |
if (GUILayout.Button("Refresh Inspector")) { | |
AssetDatabase.Refresh(); | |
} | |
//Lazy spacer | |
GUILayout.Label(""); | |
//Move Up Button | |
GUILayout.BeginHorizontal(); | |
if (GUILayout.Button("Move Up")) { | |
if (selectedAnimationIndex != 0 && selectedAnimationIndex != -1) { | |
List<string> animBackup = new List<string>(); | |
animBackup = animations[selectedAnimationIndex]; | |
animations.RemoveAt(selectedAnimationIndex); | |
animations.Insert(selectedAnimationIndex - 1, animBackup); | |
string nameBackup = animNames[selectedAnimationIndex]; | |
animNames.RemoveAt(selectedAnimationIndex); | |
animNames.Insert(selectedAnimationIndex - 1, nameBackup); | |
selectedAnimationIndex -= 1; | |
} | |
} | |
//Move Down Button | |
if (GUILayout.Button("Move Down")) { | |
if (selectedAnimationIndex != animations.Count() - 1 && selectedAnimationIndex != -1) { | |
List<string> animBackup = new List<string>(); | |
animBackup = animations[selectedAnimationIndex]; | |
animations.RemoveAt(selectedAnimationIndex); | |
animations.Insert(selectedAnimationIndex + 1, animBackup); | |
string nameBackup = animNames[selectedAnimationIndex]; | |
animNames.RemoveAt(selectedAnimationIndex); | |
animNames.Insert(selectedAnimationIndex + 1, nameBackup); | |
selectedAnimationIndex += 1; | |
} | |
} | |
GUILayout.EndHorizontal(); | |
//Selectable Animations List | |
for (int i = 0; i < animNames.Count(); i++) { | |
itemStyle = new GUIStyle(GUI.skin.button); | |
//Set style | |
Color color_default = GUI.backgroundColor; | |
Color color_selected = Color.gray; | |
GUI.changed = false; | |
itemStyle.alignment = TextAnchor.MiddleLeft; | |
itemStyle.active.background = itemStyle.normal.background; | |
itemStyle.margin = new RectOffset(0, 0, 0, 0); | |
GUI.backgroundColor = (selectedAnimationIndex == i) ? color_selected : Color.clear; | |
//Change the index when selecting the animation | |
if (GUILayout.Button(animNames[i], itemStyle)) { | |
selectedAnimationIndex = i; | |
} | |
} | |
} | |
//Resets all the data | |
private void ClearData() { | |
animNames.Clear(); | |
animations.Clear(); | |
metadataHeader.Clear(); | |
metadata.Clear(); | |
selectedAnimationIndex = -1; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment