using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Reflection; using UnityEditor; using UnityEditor.Experimental.SceneManagement; using UnityEditor.SceneManagement; using UnityEditorInternal; using UnityEngine; public static class EditorUtils { public static void OpenAllScene(Func editFunc){ var currentScenePath = EditorSceneManager.GetActiveScene().path; var scenes = EditorBuildSettings.scenes.Where(s => s.enabled).ToArray(); for(int i = 0; i < scenes.Length; ++i){ var scene = scenes[i]; EditorSceneManager.OpenScene(scene.path); var gameObjectArray = Resources.FindObjectsOfTypeAll().Where(go => string.IsNullOrEmpty(AssetDatabase.GetAssetPath(go)) && go.hideFlags == HideFlags.None).ToArray(); var isChanged = editFunc((float)i / scenes.Length, scene, gameObjectArray); if(isChanged){ EditorSceneManager.SaveScene(EditorSceneManager.GetActiveScene()); } } EditorSceneManager.OpenScene(currentScenePath); } public static GameObject[] GetAllAssets(){ var pathArray = AssetDatabase.GetAllAssetPaths().Where(path => path.StartsWith("Assets/")).ToArray(); return pathArray.Select(a => AssetDatabase.LoadAssetAtPath(a, typeof(GameObject)) as GameObject).Where(a => a != null).ToArray(); } public static void FindAllPrefabPath(string folderPath, Action action){ var pathArray = Directory.GetFiles(folderPath, "*.prefab"); for(int i = 0; i < pathArray.Length; ++i){ action((float)i / pathArray.Length, pathArray[i].Replace(Application.dataPath, "Assets")); } } public static void FindAllChildrensPrefabPath(string folderPath, Action action){ FindAllPrefabPath(folderPath, action); foreach(var childPath in Directory.GetDirectories(folderPath)){ FindAllChildrensPrefabPath(childPath, action); } } public static void EditPrefab(string folderPath, Func editFunc){ var prefab = PrefabUtility.LoadPrefabContents(folderPath); var isChanged = editFunc(prefab); if(isChanged){ PrefabUtility.SaveAsPrefabAsset(prefab, folderPath); } PrefabUtility.UnloadPrefabContents(prefab); } public static void FindAllChildrensPrefab(Transform transform, Action action){ for(int i = transform.childCount - 1; i >= 0; --i){ Transform child = transform.GetChild(i); if(PrefabUtility.IsAnyPrefabInstanceRoot(child.gameObject)){ action(child); }else{ FindAllChildrensPrefab(child, action); } } } public static void SwapPrefab(Transform target, GameObject swapPrefab){ var to = (UnityEditor.PrefabUtility.InstantiatePrefab(swapPrefab) as GameObject).transform; to.parent = target.parent; to.localPosition = target.localPosition; to.localRotation = target.localRotation; to.localScale = target.localScale; GameObject.DestroyImmediate(target.gameObject); } public static string MigratePrefabToPrefabVariant(GameObject basePrefab, GameObject migrationPrefab){ var basePath = AssetDatabase.GetAssetPath(basePrefab); var path = AssetDatabase.GetAssetPath(migrationPrefab).Replace(".prefab", " Variant.prefab"); var instance = PrefabUtility.InstantiatePrefab(basePrefab) as GameObject; PrefabUtility.SaveAsPrefabAsset(instance, path); GameObject.DestroyImmediate(instance); var prefab = PrefabUtility.LoadPrefabContents(path); var result = Migrate(prefab.transform, migrationPrefab.transform); if(!result){ FixField(prefab.transform, migrationPrefab.transform); PrefabUtility.SaveAsPrefabAsset(prefab, path); } PrefabUtility.UnloadPrefabContents(prefab); return path; } private static bool Migrate(Transform targetTransform, Transform migrationTransform){ var targetChildCount = targetTransform.childCount; for(int i = 0; i < migrationTransform.childCount; ++i){ var migrationChild = migrationTransform.GetChild(i); Transform targetChild; if(i < targetChildCount){ targetChild = targetTransform.GetChild(i); if(migrationChild.name != targetChild.name){ var containsNameCount = ChildContaintsNameCount(targetTransform, migrationChild.name); if(containsNameCount == 0){ targetChild = GameObject.Instantiate(migrationChild.gameObject, targetTransform).transform; targetChild.name = migrationChild.name; targetChild.SetSiblingIndex(migrationChild.GetSiblingIndex()); ++targetChildCount; }else if(containsNameCount == 1){ for(int j = 0; j < targetChildCount; ++j){ if(targetTransform.GetChild(j).name == migrationChild.name){ targetChild = targetTransform.GetChild(j); targetChild.SetSiblingIndex(migrationChild.GetSiblingIndex()); break; } } }else{ Debug.LogError("同一階層に同じ名前のオブジェクトがある為中止します。"); return true; } } }else{ targetChild = GameObject.Instantiate(migrationChild.gameObject, targetTransform).transform; targetChild.name = migrationChild.name; ++targetChildCount; } CopyComponents(targetChild, migrationChild); var result = Migrate(targetChild, migrationChild); if(result){ return true; } targetChild.gameObject.SetActive(migrationChild.gameObject.activeSelf); } for(int i = 0; i < targetChildCount; ++i){ var toChild = targetTransform.GetChild(i); var containsNameCount = ChildContaintsNameCount(migrationTransform, toChild.name); if(containsNameCount == 0){ toChild.gameObject.SetActive(false); Debug.LogWarning("Change disable " + toChild.GetPath()); } } return false; } private static void FixField(Transform targetTransform, Transform migrationTransform){ var targetChildCount = targetTransform.childCount; for(int i = 0; i < migrationTransform.childCount; ++i){ var migrationChild = migrationTransform.GetChild(i); var targetChild = targetTransform.GetChild(i); if(migrationChild.name != targetChild.name){ for(int j = 0; j < targetChildCount; ++j){ if(targetTransform.GetChild(j).name == migrationChild.name){ targetChild = targetTransform.GetChild(j); break; } } } FixField(targetChild, migrationChild); ProcessReflection(migrationChild, targetChild, targetTransform); migrationChild.FindComponent(fromPS => { if(fromPS.subEmitters.enabled){ var fromSub = fromPS.subEmitters; FindChildrensByPath(targetTransform, migrationChild.GetPath(), t => { t.FindComponent(toPS => { var toSub = toPS.subEmitters; for(int index = 0; index < fromSub.subEmittersCount; ++index){ var fromTarget = fromSub.GetSubEmitterSystem(index); FindChildrensByPath(targetTransform, fromTarget.transform.GetPath(), toTarget => { toSub.SetSubEmitterSystem(index, toTarget.GetComponent()); }); } }); }); } }); } } private static int ChildContaintsNameCount(Transform transform, string name){ var counter = 0; foreach(Transform child in transform){ if(child.name == name){ ++counter; } } return counter; } private static void CopyComponents(Transform to, Transform from){ var components = from.gameObject.GetComponents(); var targetComponents = to.gameObject.GetComponents(); var currentComponentCount = new Dictionary(); foreach(var component in components){ var componentType = component.GetType(); var componentCount = targetComponents.Count(c => c.GetType() == componentType); ComponentUtility.CopyComponent(component); if(componentCount == 0){ ComponentUtility.PasteComponentAsNew(to.gameObject); }else if(componentCount == 1){ var targetComponent = targetComponents.First(c => c.GetType() == componentType); ComponentUtility.PasteComponentValues(targetComponent); }else{ if(!currentComponentCount.ContainsKey(componentType)){ currentComponentCount.Add(componentType, 0); } var count = currentComponentCount[componentType]; var targetComponentsWithType = targetComponents.Where(c => c.GetType() == componentType); if(count < targetComponentsWithType.Count()){ var targetComponent = targetComponents.Where(c => c.GetType() == componentType).ElementAt(count); currentComponentCount[componentType] += 1; ComponentUtility.PasteComponentValues(targetComponent); }else{ ComponentUtility.PasteComponentAsNew(to.gameObject); } } } foreach(var component in targetComponents){ var componentType = component.GetType(); var componentCount = components.Count(c => c.GetType() == componentType); if(componentCount == 0){ Debug.LogWarning("Deestroy component " + to.GetPath() + " " + componentType); GameObject.DestroyImmediate(component); } } } private static void ProcessReflection(Transform from, Transform to, Transform parent){ var fromComponents = from.GetComponents(); for(int i = 0; i < fromComponents.Length; ++i){ var fromType = fromComponents[i].GetType(); var toComponent = to.GetComponent(fromType); if(toComponent == null){ continue; } MemberInfo[] members = fromType.GetMembers(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance); foreach(var m in members){ if(m.MemberType != MemberTypes.Field){ continue; } System.Type fieldType = ((FieldInfo)m).FieldType; if(fieldType == typeof(Transform) || fieldType == typeof(GameObject)){ string targetPath; FieldInfo field = fromType.GetField(m.Name, BindingFlags.Public | BindingFlags.Instance | BindingFlags.NonPublic); if(fieldType == typeof(Transform)){ Transform t = (Transform)field.GetValue(fromComponents[i]); if(t == null){ continue; } targetPath = t.GetPath(); }else if(fieldType == typeof(GameObject)){ GameObject obj = (GameObject)field.GetValue(fromComponents[i]); if(obj == null){ continue; } targetPath = obj.transform.GetPath(); }else{ continue; } FindChildrensByPath(parent, targetPath, targetTransform => { FieldInfo setField = fromType.GetField(m.Name, BindingFlags.Public | BindingFlags.Instance | BindingFlags.NonPublic); if(setField == null){ Debug.Log("setField is null " + m.Name); }else{ if(fieldType == typeof(Transform)){ setField.SetValue(toComponent, targetTransform); }else if(fieldType == typeof(GameObject)){ setField.SetValue(toComponent, targetTransform.gameObject); } } }); }else if(fieldType == typeof(Transform[])){ FieldInfo field = fromType.GetField(m.Name, BindingFlags.Public | BindingFlags.Instance | BindingFlags.NonPublic); Transform[] t = (Transform[])field.GetValue(fromComponents[i]); if(t == null){ continue; } var targetPathArray = new string[t.Length]; for(int j = 0; j < t.Length; ++j){ if(t[j] == null){ targetPathArray[j] = null; }else{ targetPathArray[j] = t[j].GetPath(); } } var newTransformArray = new Transform[t.Length]; for(int j = 0; j < t.Length; ++j){ if(targetPathArray[j] == null){ continue; } FindChildrensByPath(parent, targetPathArray[j], targetTransform => { newTransformArray[j] = targetTransform; }); } FieldInfo setField = fromType.GetField(m.Name, BindingFlags.Public | BindingFlags.Instance | BindingFlags.NonPublic); if(setField == null){ Debug.Log("setField is null " + m.Name); }else{ setField.SetValue(toComponent, newTransformArray); } }else if(fieldType == typeof(GameObject[])){ FieldInfo field = fromType.GetField(m.Name, BindingFlags.Public | BindingFlags.Instance | BindingFlags.NonPublic); GameObject[] t = (GameObject[])field.GetValue(fromComponents[i]); if(t == null){ continue; } var targetPathArray = new string[t.Length]; for(int j = 0; j < t.Length; ++j){ if(t[j] == null){ targetPathArray[j] = null; }else{ targetPathArray[j] = t[j].transform.GetPath(); } } var newArray = new GameObject[t.Length]; for(int j = 0; j < t.Length; ++j){ if(targetPathArray[j] == null){ continue; } FindChildrensByPath(parent, targetPathArray[j], targetTransform => { newArray[j] = targetTransform.gameObject; }); } FieldInfo setField = fromType.GetField(m.Name, BindingFlags.Public | BindingFlags.Instance | BindingFlags.NonPublic); if(setField == null){ Debug.Log("setField is null " + m.Name); }else{ setField.SetValue(toComponent, newArray); } } } } } private static bool FindChildrensByPath(Transform t, string path, Action callback){ for(int i = 0; i < t.childCount; ++i){ Transform child = t.GetChild(i); if(child.GetPath().Replace(" Variant", "") == path){ callback(child); return true; } } for(int i = 0; i < t.childCount; ++i){ Transform child = t.GetChild(i); if(FindChildrensByPath(child, path, callback)){ return true; } } return false; } }