public static List <Diff> GetDiffs(GameObject instance, GameObject instanceRoot, GameObject prefab, GameObject prefabRoot) { List <Diff> diffs = new List <Diff>(); if (prefab) { // compare existing components var prefabComponents = prefab.GetComponents <Component>(); var deletedComponents = new List <Component>(); foreach (var prefabComponent in prefabComponents) { var instanceComponentsOfType = instance.GetComponents(prefabComponent.GetType()); Component instanceComponent = instanceComponentsOfType.Length > 0 ? instanceComponentsOfType[0] : null; // if we have more than one same component -> try to get the same by order of GetComponents() if (instanceComponentsOfType.Length > 1) { int indexInPrefab = Array.IndexOf(prefab.GetComponents(prefabComponent.GetType()), prefabComponent); instanceComponent = instanceComponentsOfType[indexInPrefab % instanceComponentsOfType.Length]; } if (instanceComponent) { FillDiffsFromComponent(ref diffs, instanceComponent, prefabComponent, instanceRoot, prefabRoot); } else { deletedComponents.Add(prefabComponent); } } // delete obsolete components foreach (var deletedComponent in deletedComponents) { Component prefabDeletedComponent = deletedComponent; Diff deleteDiff = new Diff(Diff.Operation.Delete, prefabDeletedComponent, null); deleteDiff.Apply = () => { GameObject.DestroyImmediate(prefabDeletedComponent, true); }; deleteDiff.OnGUI = () => { GUI.color = new Color(1, 0.7f, 0.7f); EditorGUILayout.LabelField("Deleted component:", prefabDeletedComponent.GetType().Name); GUI.color = Color.white; EditorGUILayout.ObjectField(prefabDeletedComponent, typeof(Component), false); }; diffs.Add(deleteDiff); } // add new components var instanceComponents = instance.GetComponents <Component>(); foreach (var instanceComponent in instanceComponents) { if (!System.Array.Find <Component>(prefabComponents, (x) => { return(x.GetType() == instanceComponent.GetType()); })) { Component instanceNewComponent = instanceComponent; Diff addDiff = new Diff(Diff.Operation.Add, instanceNewComponent, null); addDiff.Apply = () => { var prefabComponent = prefab.AddComponent(instanceNewComponent.GetType()); UnityEditor.EditorUtility.CopySerialized(instanceNewComponent, prefabComponent); }; addDiff.OnGUI = () => { GUI.color = new Color(0.7f, 1, 0.7f); EditorGUILayout.LabelField("Added component:", instanceNewComponent.GetType().Name); GUI.color = Color.white; EditorGUILayout.ObjectField(instanceNewComponent, typeof(Component), false); }; diffs.Add(addDiff); } } } else { // probably new gameobject GameObjectDiff.Diff d = new GameObjectDiff.Diff(GameObjectDiff.Diff.Operation.New, null, instance.name); d.Apply = () => { GameObject prefabInstance = PrefabUtility.InstantiatePrefab(prefabRoot) as GameObject; GameObject instanceCopy = new GameObject(instance.name); string path = EditorUtils.GetPathForObjectInHierarchy(instance, instanceRoot); instanceCopy.transform.parent = prefabInstance.GetChildByPath(path).transform; foreach (Component c in instance.GetComponents <Component>()) { if (c is Transform) { continue; } EditorUtility.CopySerialized(c, instanceCopy.AddComponent(c.GetType())); } EditorUtility.CopySerialized(instance.transform, instanceCopy.transform); PrefabUtility.ReplacePrefab(prefabInstance, prefabRoot); GameObject.DestroyImmediate(prefabInstance); }; d.OnGUI = () => { GUI.color = new Color(0, 1f, 0); EditorGUILayout.LabelField("New GameObject:", instance.name); GUI.color = Color.white; }; diffs.Add(d); } return(diffs); }
public List <PrefabCandidate> GetPrefabCandidatesForSceneObject(GameObject instance) { List <PrefabCandidate> candidates = new List <PrefabCandidate>(); RefreshIndex(); GameObject instanceRoot = instance; while (instanceRoot != null) { string candidateName = EditorUtils.WithoutClonePostfix(instanceRoot.name); List <string> paths; if (_index.TryGetValue(candidateName, out paths)) { foreach (var path in paths) { GameObject prefabRoot = AssetDatabase.LoadAssetAtPath(path, typeof(GameObject)) as GameObject; if (!prefabRoot) { continue; } var prefabPath = EditorUtils.GetPathForObjectInHierarchy(instance, instanceRoot); GameObject prefab = prefabRoot.GetChildByPath(prefabPath); if (prefab == null) { // ATTENTION: // new gameobjects unsupported yet, comment "continue" to enable continue; // try find prefab for parent prefabPath = EditorUtils.GetParentPath(prefabPath); GameObject prefabParent = prefabRoot.GetChildByPath(prefabPath); if (prefabParent == null) { continue; } } PrefabCandidate candidate; candidate.instanceRoot = instanceRoot; candidate.prefabRoot = prefabRoot; candidate.prefab = prefab; candidate.prefabPath = prefabPath; candidates.Add(candidate); } } instanceRoot = instanceRoot.GetParent(); } // longer path is preferable if (candidates.Count > 0) { candidates.Sort((c1, c2) => c2.prefabPath.Length.CompareTo(c1.prefabPath.Length)); } return(candidates); }
static bool CompareSerializedPropertyObjectReference(SerializedProperty p1, SerializedProperty p2, GameObject root1, GameObject root2, ref Action apply, ref Action onGUI) { // If this is objectReference property, we want to try to find same object in our hierarchy and use it. Otherwise // property is just copied and links same object. onGUI = () => { EditorGUILayout.LabelField(p2.serializedObject.targetObject.GetType().Name + "." + p2.propertyPath + ": reference changed"); EditorGUILayout.ObjectField(p1.objectReferenceValue, typeof(UnityEngine.Object), false, GUILayout.Width(200)); }; if (p1.objectReferenceValue == null || EditorUtility.IsPersistent(p1.objectReferenceValue)) { apply = () => { p2.objectReferenceValue = p1.objectReferenceValue; }; return(p2.objectReferenceValue == p1.objectReferenceValue); } else { GameObject referencedGO = null; if (p1.objectReferenceValue is GameObject) { referencedGO = p1.objectReferenceValue as GameObject; } else if (p1.objectReferenceValue is Component) { referencedGO = (p1.objectReferenceValue as Component).gameObject; } else { Debug.LogWarning(string.Format("Unknown object reference type {0}", p1.objectReferenceValue.GetType()), p1.serializedObject.targetObject); return(true); } if (referencedGO == null) { Debug.LogError(string.Format("Wrong object reference type {0}", p1.objectReferenceValue.GetType()), p1.serializedObject.targetObject); return(true); } string path1 = EditorUtils.GetPathForObjectInHierarchy(referencedGO, root1); if (path1 == null) { // It means it references to some of other assets, leave link as it is. return(true); } //Debug.LogWarning("Path: {0} for: {1}", path, fromProp.objectReferenceValue.name); GameObject newGO = root2.GetChildByPath(path1); if (newGO == null) { //Debug.LogWarning(string.Format("Can't find transform for path {0}", path1), p1.serializedObject.targetObject); return(true); } if (p1.objectReferenceValue is GameObject) { apply = () => { p2.objectReferenceValue = newGO.gameObject; }; return(path1 == EditorUtils.GetPathForObjectInHierarchy(p2.objectReferenceValue as GameObject, root2)); } else if (p1.objectReferenceValue is Component) { Component myComp = newGO.gameObject.GetComponent(p1.objectReferenceValue.GetType()); if (myComp == null) { // Can't apply this change since we can't find needed component in hierarchy //Debug.LogError(string.Format("Can't find component on object {0}", path1), p1.serializedObject.targetObject); } apply = () => { p2.objectReferenceValue = myComp; }; var c2 = p2.objectReferenceValue as Component; if (c2 != null) { return(path1 == EditorUtils.GetPathForObjectInHierarchy(c2.gameObject, root2)); } else { return(false); } } } return(true); }