MergeManagerScene.cs 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157
  1. 
  2. namespace GitMerge
  3. {
  4. using UnityEngine;
  5. using UnityEditor;
  6. using UnityEngine.SceneManagement;
  7. using UnityEditor.SceneManagement;
  8. using System.Collections.Generic;
  9. public class MergeManagerScene : MergeManagerBase
  10. {
  11. private const int NUMBER_OF_INITIALIZATION_STEPS = 3;
  12. private Scene theirScene;
  13. public MergeManagerScene(GitMergeWindow window, VCS vcs)
  14. : base(window, vcs)
  15. {
  16. }
  17. public bool TryInitializeMerge(string path = null)
  18. {
  19. var activeScene = EditorSceneManager.GetActiveScene();
  20. if (activeScene.isDirty)
  21. {
  22. window.ShowNotification(new GUIContent("Please make sure there are no unsaved changes before attempting to merge."));
  23. return false;
  24. }
  25. DisplayProgressBar(0, "Checking out scene...");
  26. isMergingScene = true;
  27. var scenePath = path ?? activeScene.path;
  28. // Overwrite the current scene to prevent the reload/ignore dialog that pops up after the upcoming changes to the file.
  29. // Pressing "reload" on it would invalidate the GameObject references we're about to collect.
  30. EditorSceneManager.NewScene(NewSceneSetup.EmptyScene, NewSceneMode.Single);
  31. Lightmapping.ForceStop();
  32. vcs.CheckoutOurs(scenePath);
  33. CheckoutTheirVersionOf(scenePath);
  34. AssetDatabase.Refresh();
  35. DisplayProgressBar(1, "Opening scene...");
  36. activeScene = EditorSceneManager.OpenScene(scenePath, OpenSceneMode.Single);
  37. MergeAction.inMergePhase = false;
  38. ObjectDictionaries.Clear();
  39. List<GameObject> ourObjects;
  40. try
  41. {
  42. DisplayProgressBar(2, "Collecting differences...");
  43. // Find all of "our" objects
  44. ourObjects = GetAllSceneObjects();
  45. ObjectDictionaries.AddToOurObjects(ourObjects);
  46. // Add "their" objects
  47. theirScene = EditorSceneManager.OpenScene(theirFilename, OpenSceneMode.Additive);
  48. var addedObjects = GetAllNewSceneObjects(ourObjects);
  49. ObjectDictionaries.AddToTheirObjects(addedObjects);
  50. BuildAllMergeActions(ourObjects, addedObjects);
  51. MoveGameObjectsToScene(theirScene.GetRootGameObjects(), activeScene);
  52. }
  53. finally
  54. {
  55. EditorSceneManager.UnloadSceneAsync(theirScene);
  56. AssetDatabase.DeleteAsset(theirFilename);
  57. EditorUtility.ClearProgressBar();
  58. }
  59. if (allMergeActions.Count == 0)
  60. {
  61. window.ShowNotification(new GUIContent("No conflict found for this scene."));
  62. return false;
  63. }
  64. MergeAction.inMergePhase = true;
  65. return true;
  66. }
  67. private static void DisplayProgressBar(int step, string text)
  68. {
  69. var progress = step / (float)NUMBER_OF_INITIALIZATION_STEPS;
  70. EditorUtility.DisplayProgressBar("GitMerge for Unity", text, progress);
  71. }
  72. private static void MoveGameObjectsToScene(IEnumerable<GameObject> addedObjects, Scene scene)
  73. {
  74. foreach (var obj in addedObjects)
  75. {
  76. EditorSceneManager.MoveGameObjectToScene(obj, scene);
  77. }
  78. }
  79. private static List<GameObject> GetAllSceneObjects()
  80. {
  81. var objects = (GameObject[])Object.FindObjectsOfType(typeof(GameObject));
  82. return new List<GameObject>(objects);
  83. }
  84. /// <summary>
  85. /// Finds all GameObjects in the scene, minus the ones passed.
  86. /// </summary>
  87. private static List<GameObject> GetAllNewSceneObjects(List<GameObject> oldObjects)
  88. {
  89. var all = GetAllSceneObjects();
  90. foreach (var obj in oldObjects)
  91. {
  92. all.Remove(obj);
  93. }
  94. return all;
  95. }
  96. /// <summary>
  97. /// Completes the merge process after solving all conflicts.
  98. /// Cleans up the scene by deleting "their" GameObjects, clears merge related data structures,
  99. /// executes git add scene_name.
  100. /// </summary>
  101. public override void CompleteMerge()
  102. {
  103. MergeAction.inMergePhase = false;
  104. ObjectDictionaries.DestroyTheirObjects();
  105. ObjectDictionaries.Clear();
  106. EditorSceneManager.SaveScene(EditorSceneManager.GetActiveScene());
  107. allMergeActions = null;
  108. vcs.MarkAsMerged(fileName);
  109. // Directly committing here might not be that smart, since there might be more conflicts
  110. window.ShowNotification(new GUIContent("Scene successfully merged."));
  111. }
  112. /// <summary>
  113. /// Aborts merge by using "our" version in all conflicts.
  114. /// Cleans up merge related data.
  115. /// </summary>
  116. public override void AbortMerge(bool showNotification = true)
  117. {
  118. base.AbortMerge(showNotification);
  119. EditorSceneManager.CloseScene(theirScene, true);
  120. EditorSceneManager.SaveScene(EditorSceneManager.GetActiveScene());
  121. }
  122. }
  123. }