using UnityEngine; using UnityEditor; using UnityEditor.SceneManagement; using System.Collections.Generic; namespace GitMerge { public class MergeManagerPrefab : MergeManager { //Stuff needed for prefab merging public static GameObject ourPrefab { private set; get; } private static GameObject theirPrefab; public static GameObject ourPrefabInstance { private set; get; } private static string previouslyOpenedScene; public MergeManagerPrefab(GitMergeWindow window, VCS vcs) : base(window, vcs) { } public bool InitializeMerge(GameObject prefab) { if(!EditorSceneManager.SaveCurrentModifiedScenesIfUserWantsTo()) { return false; } isMergingScene = false; MergeAction.inMergePhase = false; ObjectDictionaries.Clear(); //checkout "their" version GetTheirVersionOf(AssetDatabase.GetAssetOrScenePath(prefab)); AssetDatabase.Refresh(); ourPrefab = prefab; //Open a new Scene that will only display the prefab previouslyOpenedScene = EditorSceneManager.GetActiveScene().ToString(); EditorSceneManager.NewScene(NewSceneSetup.DefaultGameObjects); //make the new scene empty Object.DestroyImmediate(Camera.main.gameObject); //instantiate our object in order to view it while merging ourPrefabInstance = PrefabUtility.InstantiatePrefab(prefab) as GameObject; //find all of "our" objects in the prefab var ourObjects = GetAllObjects(prefab); theirPrefab = AssetDatabase.LoadAssetAtPath(theirFilename, typeof(GameObject)) as GameObject; theirPrefab.hideFlags = HideFlags.HideAndDontSave; var theirObjects = GetAllObjects(theirPrefab); //create list of differences that have to be merged BuildAllMergeActions(ourObjects, theirObjects); if(allMergeActions.Count == 0) { AssetDatabase.DeleteAsset(theirFilename); OpenPreviousScene(); window.ShowNotification(new GUIContent("No conflict found for this prefab.")); return false; } MergeAction.inMergePhase = true; ourPrefabInstance.Highlight(); return true; } /// /// Recursively find all GameObjects that are part of the prefab /// /// The prefab to analyze /// The list with all the objects already found. Pass null in the beginning. /// The list with all the objects private static List GetAllObjects(GameObject prefab, List list = null) { if(list == null) { list = new List(); } list.Add(prefab); foreach(Transform t in prefab.transform) { GetAllObjects(t.gameObject, list); } return list; } /// /// Completes the merge process after solving all conflicts. /// Cleans up the scene by deleting "their" GameObjects, clears merge related data structures, /// executes git add scene_name. /// public override void CompleteMerge() { MergeAction.inMergePhase = false; //ObjectDictionaries.Clear(); allMergeActions = null; //TODO: Could we explicitly just save the prefab? AssetDatabase.SaveAssets(); //Mark as merged for git vcs.MarkAsMerged(fileName); //directly committing here might not be that smart, since there might be more conflicts ourPrefab = null; //delete their prefab file AssetDatabase.DeleteAsset(theirFilename); OpenPreviousScene(); window.ShowNotification(new GUIContent("Prefab successfully merged.")); } /// /// Aborts merge by using "our" version in all conflicts. /// Cleans up merge related data. /// public override void AbortMerge() { base.AbortMerge(); //delete prefab file AssetDatabase.DeleteAsset(theirFilename); OpenPreviousScene(); ourPrefab = null; } /// /// Opens the previously opened scene, if there was any. /// private static void OpenPreviousScene() { if(!string.IsNullOrEmpty(previouslyOpenedScene)) { EditorSceneManager.OpenScene(previouslyOpenedScene); previouslyOpenedScene = ""; } } } }