using UnityEditor.SceneManagement;
public class BoneHierarchyTool : EditorWindow
private const string RootBoneKey = "BoneHierarchyTool_RootBone";
private const string OmissionListKey = "BoneHierarchyTool_OmissionList";
private const string HierarchyDataKey = "BoneHierarchyTool_HierarchyData";
private const string AddRootKey = "BoneHierarchyTool_AddRoot";
private const string BoneSortingKey = "BoneHierarchyTool_BoneSorting";
private Transform rootBone;
private BoneOmissionList omissionList;
private BoneHierarchyData hierarchyData;
private BoneSorting boneSorting;
[MenuItem("Tools/Bone Hierarchy Tool")]
public static void ShowWindow()
GetWindow<BoneHierarchyTool>("Bone Hierarchy Tool");
int rootBoneInstanceID = EditorPrefs.GetInt(RootBoneKey, 0);
rootBone = EditorUtility.InstanceIDToObject(rootBoneInstanceID) as Transform;
string omissionListGuid = EditorPrefs.GetString(OmissionListKey, string.Empty);
string hierarchyDataGuid = EditorPrefs.GetString(HierarchyDataKey, string.Empty);
omissionList = AssetDatabase.LoadAssetAtPath<BoneOmissionList>(AssetDatabase.GUIDToAssetPath(omissionListGuid));
hierarchyData = AssetDatabase.LoadAssetAtPath<BoneHierarchyData>(AssetDatabase.GUIDToAssetPath(hierarchyDataGuid));
addRoot = EditorPrefs.GetBool(AddRootKey, true);
boneSorting = (BoneSorting)EditorPrefs.GetInt(BoneSortingKey, (int)BoneSorting.BasedOnHierarchy);
int rootBoneInstanceID = rootBone.GetInstanceID();
EditorPrefs.SetInt(RootBoneKey, rootBoneInstanceID);
if (omissionList != null)
string omissionListPath = AssetDatabase.GetAssetPath(omissionList);
string omissionListGuid = AssetDatabase.AssetPathToGUID(omissionListPath);
EditorPrefs.SetString(OmissionListKey, omissionListGuid);
if (hierarchyData != null)
string hierarchyDataPath = AssetDatabase.GetAssetPath(hierarchyData);
string hierarchyDataGuid = AssetDatabase.AssetPathToGUID(hierarchyDataPath);
EditorPrefs.SetString(HierarchyDataKey, hierarchyDataGuid);
EditorPrefs.SetBool(AddRootKey, addRoot);
EditorPrefs.SetInt(BoneSortingKey, (int)boneSorting);
GUILayout.Label("Bone Hierarchy Tool", EditorStyles.boldLabel);
rootBone = (Transform)EditorGUILayout.ObjectField("Root Bone", rootBone, typeof(Transform), true);
omissionList = (BoneOmissionList)EditorGUILayout.ObjectField("Omission List", omissionList, typeof(BoneOmissionList), false);
hierarchyData = (BoneHierarchyData)EditorGUILayout.ObjectField("Hierarchy Data", hierarchyData, typeof(BoneHierarchyData), false);
addRoot = EditorGUILayout.Toggle("Add Root", addRoot);
boneSorting = (BoneSorting)EditorGUILayout.EnumPopup("Bone Sorting", boneSorting);
if (GUILayout.Button("Generate Hierarchy Data"))
if (GUILayout.Button("Resolve Bone References"))
private void GenerateHierarchyData()
if (rootBone == null || omissionList == null || hierarchyData == null)
Debug.LogError("Please assign all required fields.");
var limbIdentifier = new GameObject("LimbIdentifier").AddComponent<LimbIdentifier>();
limbIdentifier.root = rootBone;
limbIdentifier.omittedBonesList = omissionList;
limbIdentifier.addRoot = addRoot;
limbIdentifier.boneSorting = boneSorting;
limbIdentifier.IdentifySkeletonBones();
hierarchyData.bones.Clear();
for (int i = 0; i < limbIdentifier.BoneTransforms.Count; i++)
var bone = limbIdentifier.BoneTransforms[i];
hierarchyData.bones.Add(new BoneHierarchyData.BoneData
position = bone.localPosition,
rotation = bone.localRotation,
parentIndex = limbIdentifier.ParentBoneIndex[i],
path = limbIdentifier.BonePaths[i]
EditorUtility.SetDirty(hierarchyData);
DestroyImmediate(limbIdentifier.gameObject);
Debug.Log("Hierarchy data generated and saved successfully.");
// Select the hierarchyData object to show its contents in the Inspector
Selection.activeObject = hierarchyData;
private void ResolveBoneReferences()
if (hierarchyData == null)
Debug.LogError("Please assign a hierarchy data ScriptableObject.");
hierarchyData.ResolveBoneReferences(out List<Transform> resolvedTransforms);
Debug.Log("Resolved " + resolvedTransforms.Count + " bones.");