public static void ApplyManagedPrefabInstancesThenRemoveFromParentPrefab(this ManagesPrefabInstances mpi)
        {
            using (var instances = ListPool <PrefabInstance> .Get()) {
                mpi.GetPrefabInstances(instances);

                for (var i = instances.Count - 1; i >= 0; i--)
                {
                    if (instances[i].instancePolicy == PrefabInstancePolicy.AllowApplyInstanceToParentPrefab)
                    {
                        instances.RemoveAt(i);
                        continue;
                    }

                    if (instances[i].prefab == null)
                    {
                        Debug.LogError("[" + Time.frameCount + "][" + (mpi as Component).Path()
                                       + "] no prefab for instance with type " + instances[i].prefabType);

                        instances.RemoveAt(i);
                        continue;
                    }

                    UnityEditor.PrefabUtility.ReplacePrefab(instances[i].instance, instances[i].prefab, UnityEditor.ReplacePrefabOptions.ReplaceNameBased);
                }

                foreach (var pInst in instances)
                {
                    Object.DestroyImmediate(pInst.instance.gameObject, true);
                }
            }
        }
        public static void OnInspectorGUI_EditPrefabs(this ManagesPrefabInstances p)
        {
            var bkgColorSave = GUI.backgroundColor;

            using (var instances = ListPool <PrefabInstance> .Get()) {
                p.GetPrefabInstances(instances, ensureCreated: false);

                if (instances.Count > 0)
                {
                    switch (p.defaultInstancePolicy)
                    {
                    case PrefabInstancePolicy.AllowApplyInstanceToParentPrefab:

                        EditorGUILayout.HelpBox(@"Be careful with Apply! 

Instance Policy 'AllowApplyInstanceToParentPrefab' means Apply will bake nested prefabs into the parent", MessageType.Warning);
                        break;

                    default:
                        EditorGUILayout.HelpBox(@"About Apply... 

Instance Policy '" + p.defaultInstancePolicy + @"' means 'Apply' will find nested prefabs, apply their changes separately and then remove them from their parent prefab to avoid having them become part of the parent.

NOTE: this behaviour does NOT apply to nested prefabs that aren't managed, e.g. you just added one to the", MessageType.Info);
                        break;
                    }

                    GUI.backgroundColor = Color.green;
                    if (GUILayout.Button(p.supportsMultiplePrefabTypes? "Delete Prefab[s]": "Delete Prefab"))
                    {
                        foreach (var pInst in instances)
                        {
                            if (pInst.instance == null)
                            {
                                continue;
                            }
                            Object.DestroyImmediate(pInst.instance, true);
                        }
                    }
                }
                else
                {
                    GUI.backgroundColor = Color.green;
                    if (GUILayout.Button(p.supportsMultiplePrefabTypes? "Edit Prefab[s]": "Edit Prefab"))
                    {
                        instances.Clear();
                        p.GetPrefabInstances(instances, ensureCreated: true);
                    }
                    if (GUILayout.Button(p.supportsMultiplePrefabTypes? "Edit Prefab[s] and Nested Prefabs": "Edit Prefab and Nested Prefabs"))
                    {
                        p.EditPrefabRecursive();
                    }
                }
            }

            GUI.backgroundColor = bkgColorSave;
        }
        public static void ObjectsToPrefabInstances(this ManagesPrefabInstances mpi, ICollection <GameObject> objects, IList <PrefabType> prefabTypes, ICollection <PrefabInstance> prefabInstances, PrefabInstancePolicy instancePolicy)
        {
            foreach (var i in objects)
            {
                PrefabType pt;
                MatchInstanceToPrefab(i, prefabTypes, out pt);

                prefabInstances.Add(new PrefabInstance {
                    prefab         = pt.prefab,
                    instance       = i.gameObject,
                    instancePolicy = instancePolicy
                });
            }
        }
        public static void FindPrefabInstances(
            this ManagesPrefabInstances manager,
            ICollection <PrefabInstance> instances,
            PrefabInstancePolicy defaultInstancePolicy,
            bool ensureCreated = false,
            AddInstanceDelegate addInstanceDelegate = null,
            Transform parent = null
            )
        {
            using (var foundItems = ListPool <GameObject> .Get())
                using (var foundObjects = ListPool <GameObject> .Get())
                    using (var prefabTypes = ListPool <PrefabType> .Get())
                    {
                        (parent ?? (manager as Component).transform).GetComponentsInDirectChildren(foundItems, true);

                        manager.GetPrefabTypes(prefabTypes);

                        if (ensureCreated && foundItems.Count == 0)
                        {
                            foreach (var pt in prefabTypes)
                            {
                                if (pt.prefab == null)
                                {
                                    Debug.LogWarning("[" + Time.frameCount + "] encountered null prefab for type " + pt.prefabType);
                                    continue;
                                }

                                var prefab = pt.prefab as GameObject ??
                                             (pt.prefab is Component)?(pt.prefab as Component).gameObject: null;

                                if (prefab == null)
                                {
                                    Debug.LogWarning("[" + Time.frameCount + "] unable to find prefab GameObject");
                                    continue;
                                }
                                foundItems.Add(addInstanceDelegate(prefab));
                            }
                        }

                        foreach (var c in foundItems)
                        {
                            foundObjects.Add(c.gameObject);
                        }

                        manager.ObjectsToPrefabInstances(foundObjects, prefabTypes, instances, defaultInstancePolicy);
                    }
        }
        public static void EditPrefabRecursive(this ManagesPrefabInstances p)
        {
            using (var pInstances = ListPool <PrefabInstance> .Get())
            {
                p.GetPrefabInstances(pInstances, ensureCreated: true);

                foreach (var pInst in pInstances)
                {
                    using (var nested = ListPool <ManagesPrefabInstances> .Get())
                    {
                        pInst.instance.GetComponentsInChildren <ManagesPrefabInstances>(true, nested);
                        foreach (var nestedP in nested)
                        {
                            nestedP.EditPrefabRecursive();
                        }
                    }
                }
            }
        }