static internal void ApplyChanges(this PEPrefabScript _this, bool buildModifications = false) { if (!_this) { return; } if (PEPrefs.DebugLevel > 0) { Debug.Log(string.Format("[Begin Apply] {0}", _this.name)); } EditorUtility.DisplayProgressBar("Apply changes", _this.name, 0f); if (buildModifications) { foreach (var pi in _this.GetComponentsInChildren <PEPrefabScript>(true)) { pi.BuildModifications(); } } if (recursionCounter++ > 100) { Debug.LogError("Recursion"); recursionCounter = 0; EditorUtility.ClearProgressBar(); return; } _this.BuildLinks(true); _this.BuildModifications(); var newPrefab = !AssetDatabase.Contains(_this.gameObject) ? PrefabUtility.ReplacePrefab(_this.gameObject, _this.Prefab, ReplacePrefabOptions.ConnectToPrefab) : _this.gameObject; var prefabs = _this.GetPrefabsWithInstances(); foreach (var prefab in prefabs) { if (PEPrefs.DebugLevel > 0) { Debug.Log("[Apply] Found Nested instance:" + prefab.name); } var instantiatedPrefabsList = new List <GameObject>(); var instances = new List <PEPrefabScript>(); if (prefab == null) { continue; } var pi = (GameObject)PrefabUtility.InstantiatePrefab(prefab); PrefabUtility.DisconnectPrefabInstance(pi); var nestedInstances = PEUtils.GetNestedInstances(pi).Where(p => p.PrefabGUID == _this.PrefabGUID && p.enabled).ToArray(); instances.AddRange(nestedInstances); var rootInstance = pi.GetComponent <PEPrefabScript>(); if (rootInstance && rootInstance.ParentPrefabGUID == _this.PrefabGUID) { instances.Insert(0, rootInstance); } instantiatedPrefabsList.Add(pi); var counter = 0; foreach (var instance in instances) { if (instance == null || instance.gameObject == null) { Debug.LogWarning("[Apply] Huston we have a problem. Prefab is destroyed before replace"); continue; } instantiatedPrefabsList.Remove(instance.gameObject); var newObject = instance.ReplaceInPlace(newPrefab); if (newObject == null || newObject.gameObject == null) { Debug.LogWarning("[Apply] Huston we have a problem. Prefab is destroyed after replace"); continue; } if (newObject.ParentPrefab == newPrefab) { instantiatedPrefabsList.Add(newObject.gameObject); } PrefabUtility.RecordPrefabInstancePropertyModifications(newObject); EditorUtility.DisplayProgressBar("Apply changes", _this.name + " replaced in " + newObject.gameObject, ((float)counter++) / (float)instances.Count); } foreach (var instantiatedPrefab in instantiatedPrefabsList) { if (instantiatedPrefab == null) { continue; } var instance = instantiatedPrefab.GetComponent <PEPrefabScript>(); if (instance) { instance.ApplyChanges(); } else { PrefabUtility.ReplacePrefab(instantiatedPrefab, PrefabUtility.GetPrefabParent(instantiatedPrefab), ReplacePrefabOptions.ConnectToPrefab); } Object.DestroyImmediate(instantiatedPrefab); } } recursionCounter--; if (PEPrefs.DebugLevel > 0) { Debug.Log(string.Format("[End Apply] {0}", _this.name)); } }
static internal void BuildMenu(GenericMenu menu, PEPrefabScript prefabInstance, bool rootPrefab, string path = "", bool showParent = true, bool showInstances = true) { if (buildMenuRecursionList.Contains(prefabInstance.Prefab)) { buildMenuRecursionList.AddLast(prefabInstance.Prefab); var prefabsArray = buildMenuRecursionList.Select(p => AssetDatabase.GetAssetPath(p)).ToArray(); buildMenuRecursionList.Clear(); throw new System.Exception("Prefab recursion detected:\n" + string.Join("\n", prefabsArray)); } buildMenuRecursionList.AddLast(prefabInstance.Prefab); if (prefabInstance.ParentPrefab == null || !showParent) { menu.AddItem(new GUIContent(path + prefabInstance.Prefab.name), false, () => { }); } else { BuildMenu(menu, prefabInstance.ParentPrefab.GetComponent <PEPrefabScript>(), false, path + prefabInstance.Prefab.name + "/", true, false); menu.AddItem(new GUIContent(path + prefabInstance.Prefab.name), false, () => { }); } menu.AddSeparator(path + ""); var isPrefab = prefabInstance.gameObject == prefabInstance.Prefab.gameObject; menu.AddItem(new GUIContent(path + "Select"), false, SelectPrefab, prefabInstance); var prefabType = PrefabUtility.GetPrefabType(prefabInstance.gameObject); var canApply = rootPrefab && prefabType != PrefabType.ModelPrefab && prefabType != PrefabType.ModelPrefabInstance && prefabType != PrefabType.DisconnectedModelPrefabInstance; if (canApply) { menu.AddItem(new GUIContent(path + "Apply"), false, Apply, prefabInstance); } if (!AssetDatabase.Contains(prefabInstance) || !isPrefab) { menu.AddItem(new GUIContent(path + "Revert"), false, Revert, prefabInstance); if (prefabInstance.ParentPrefab != null) { menu.AddItem(new GUIContent(path + "Revert To Parent"), false, RevertToParent, prefabInstance); } } menu.AddSeparator(path + ""); menu.AddItem(new GUIContent(path + "Create Child"), false, CreateChild, prefabInstance); #if INJECTION if (prefabInstance.ParentPrefab != null) { menu.AddItem(new GUIContent(path + "Insert Parent"), false, InjectParent, prefabInstance); } #endif if (!rootPrefab && !AssetDatabase.Contains(prefabInstance)) { menu.AddSeparator(path); if (prefabInstance.enabled) { menu.AddItem(new GUIContent(path + "Disable"), false, obj => (obj as PEPrefabScript).enabled = false, prefabInstance); } else { menu.AddItem(new GUIContent(path + "Enable"), false, obj => (obj as PEPrefabScript).enabled = true, prefabInstance); } } menu.AddSeparator(path); if (prefabInstance.GetPrefabsWithInstances().Any()) { menu.AddItem(new GUIContent(path + "Instances/Select All Instances"), false, SelectInstances, prefabInstance); } if (showInstances) { foreach (var prefab in prefabInstance.GetPrefabsWithInstances()) { if (prefab == null) { continue; } var pi = prefab.GetComponent <PEPrefabScript>(); var name = prefab.name; name = (pi != null && pi.ParentPrefab == prefabInstance.Prefab) ? "Child: " + name : "Contains in: " + name; if (pi != null) { BuildMenu(menu, prefab.GetComponent <PEPrefabScript>(), false, path + "Instances/" + name + "/", false); } var current = prefab; menu.AddItem(new GUIContent(path + "Instances/" + name), false, () => { Selection.activeObject = current; }); } } menu.AddItem(new GUIContent(path + "Instantiate"), false, pi => Selection.activeObject = PrefabUtility.InstantiatePrefab(((PEPrefabScript)pi).Prefab), prefabInstance); if (!AssetDatabase.Contains(prefabInstance)) { menu.AddItem(new GUIContent(path + "Replace"), false, Replace, prefabInstance); } buildMenuRecursionList.Remove(prefabInstance.Prefab); }