static void EnterPrefabModeFromCurrentSelection(PrefabStage.Mode preferredMode)
        {
            var activeGameObject = Selection.activeGameObject;

            if (activeGameObject == null)
            {
                return;
            }

            if (PrefabUtility.IsPartOfAnyPrefab(activeGameObject))
            {
                var prefabPath = PrefabUtility.GetPrefabAssetPathOfNearestInstanceRoot(activeGameObject);
                if (!string.IsNullOrEmpty(prefabPath) && prefabPath.EndsWith(".prefab", StringComparison.OrdinalIgnoreCase))
                {
                    PrefabStage.Mode prefabStageMode    = preferredMode;
                    GameObject       openedFromInstance = null;
                    if (preferredMode == PrefabStage.Mode.InContext)
                    {
                        openedFromInstance = !EditorUtility.IsPersistent(activeGameObject) ? activeGameObject : null;
                        prefabStageMode    = openedFromInstance != null ? PrefabStage.Mode.InContext : PrefabStage.Mode.InIsolation;
                    }

                    OpenPrefab(prefabPath, openedFromInstance, prefabStageMode);
                }
            }
        }
        internal static PrefabStage OpenPrefab(string prefabAssetPath, GameObject openedFromInstance, PrefabStage.Mode prefabStageMode, StageNavigationManager.Analytics.ChangeType changeTypeAnalytics)
        {
            if (string.IsNullOrEmpty(prefabAssetPath))
            {
                throw new ArgumentNullException(nameof(prefabAssetPath));
            }

            if (openedFromInstance != null && !PrefabUtility.IsPartOfPrefabInstance(openedFromInstance))
            {
                throw new ArgumentException("GameObject must be part of a Prefab instance, or null.", nameof(openedFromInstance));
            }

            if (!prefabAssetPath.EndsWith(".prefab", StringComparison.OrdinalIgnoreCase))
            {
                throw new ArgumentException("Incorrect file extension: " + prefabAssetPath + ". Must be '.prefab'", nameof(prefabAssetPath));
            }

            if (AssetDatabase.LoadMainAssetAtPath(prefabAssetPath) == null)
            {
                throw new ArgumentException("Prefab not found at path " + prefabAssetPath, nameof(prefabAssetPath));
            }

            return(OpenPrefabMode(prefabAssetPath, openedFromInstance, prefabStageMode, changeTypeAnalytics));
        }
 public static PrefabStage OpenPrefab(string prefabAssetPath, GameObject openedFromInstance, PrefabStage.Mode prefabStageMode)
 {
     return(OpenPrefab(prefabAssetPath, openedFromInstance, prefabStageMode, StageNavigationManager.Analytics.ChangeType.EnterViaUnknown));
 }
        internal static PrefabStage OpenPrefabMode(string prefabAssetPath, GameObject openedFromInstance, PrefabStage.Mode prefabStageMode, StageNavigationManager.Analytics.ChangeType changeTypeAnalytics)
        {
            if (EditorApplication.isPlaying)
            {
                bool blockPrefabModeInPlaymode = CheckIfAnyComponentShouldBlockPrefabModeInPlayMode(prefabAssetPath);
                if (blockPrefabModeInPlaymode)
                {
                    return(null);
                }
            }

            PrefabStage prevPrefabStage = GetCurrentPrefabStage();
            bool        setAsFirstItemAfterMainStage = prevPrefabStage == null || !IsPartOfPrefabStage(openedFromInstance, prevPrefabStage);

            var    previousSelection = Selection.activeGameObject;
            UInt64 previousFileID    = (openedFromInstance != null) ? GetFileIDForCorrespondingObjectFromSourceAtPath(previousSelection, prefabAssetPath) : 0;

            // Ensure valid prefabStageMode (if no context then do not allow Prefab Mode in Context)
            if (openedFromInstance == null && prefabStageMode != PrefabStage.Mode.InIsolation)
            {
                prefabStageMode = PrefabStage.Mode.InIsolation;
            }

            Stage contextStage = null;

            if (prefabStageMode == PrefabStage.Mode.InContext)
            {
                var stageHistory = StageNavigationManager.instance.stageHistory;
                contextStage = stageHistory[stageHistory.Count - 1].GetContextStage();
            }

            var prefabStage = GetExistingPrefabStage(prefabAssetPath, openedFromInstance, prefabStageMode);

            if (prefabStage == null)
            {
                prefabStage = PrefabStage.CreatePrefabStage(prefabAssetPath, openedFromInstance, prefabStageMode, contextStage);
            }
            if (StageNavigationManager.instance.SwitchToStage(prefabStage, setAsFirstItemAfterMainStage, changeTypeAnalytics))
            {
                // If selection did not change by switching stage by us or user (or if current selection is not part of
                // the opened prefab stage) then handle automatic selection in new prefab mode.
                if (Selection.activeGameObject == previousSelection || !prefabStage.IsPartOfPrefabContents(Selection.activeGameObject))
                {
                    HandleSelectionWhenSwithingToNewPrefabMode(GetCurrentPrefabStage().prefabContentsRoot, previousFileID);
                }

                SceneView.RepaintAll();
                return(prefabStage);
            }
            else
            {
                // Failed to switch to new stage
                return(null);
            }
        }
        static PrefabStage GetExistingPrefabStage(string prefabAssetPath, GameObject openedFromInstance, PrefabStage.Mode prefabStageMode)
        {
            var stageHistory = StageNavigationManager.instance.stageHistory;

            for (int i = 1; i < stageHistory.Count; i++)
            {
                var prefabStage = stageHistory[i] as PrefabStage;
                if (prefabStage != null && prefabStage.assetPath == prefabAssetPath)
                {
                    // If PrefabStage.Mode did not match on existing PrefabStage we do not reuse the stage
                    // so we create a new PrefabStage with the correct mode
                    if (prefabStage.mode == prefabStageMode)
                    {
                        return(prefabStage);
                    }
                }
            }
            return(null);
        }