Search Unity

Breaking connection from gameObject to prefab for good.

Discussion in 'Editor & General Support' started by VivienS, Mar 23, 2011.

  1. VivienS

    VivienS

    Joined:
    Mar 25, 2010
    Posts:
    24
    Hi there!

    Pretty basic question, but I can't seem to find an answer in the forums and documentation:

    Is there a way to break the connection from a GameObject in a scene to the prefab in the asset database for good? To make Unity forget that it once was an instance of a prefab? No more apply button and no more information about it via the AssetDatabase class methods?

    thanks,
    vivien
     
  2. fktt

    fktt

    Joined:
    Jul 5, 2009
    Posts:
    29
    Don't know about the Asset database, but to break prefab status,
    try adding or removing a component such as the mesh collider to/from the object.

    I ended up using a script to mass remove mesh colliders from
    a lot of object that were parented to an empty rather effortlessly.

    The hard part was manually adding mesh colliders onto them all again. :D

    also please support this idea @ unity feedback:
    http://feedback.unity3d.com/forums/15792-unity/suggestions/1614601-create-destroy-prefab-s-under-game-object-menu ;)
     
  3. VivienS

    VivienS

    Joined:
    Mar 25, 2010
    Posts:
    24
    Hi there!
    Thanks for the response. I meant something a little different. To clarify:
    Yes, breaking the link is quite easy. The blue text turns white (or black, in case you use Unity's bright interface) and the object becomes a "broken prefab". It looks like a simple game object in the hierarchy, but if you select it you get those 3 "Select", "Revert" and "Apply" buttons at the top of the inspector to reconnect it to its prefab.
    I want to go a little further than that. I want the prefab to become a simple game object again, without the apply and reconnect buttons.
     
  4. VivienS

    VivienS

    Joined:
    Mar 25, 2010
    Posts:
    24
    Hi there. The problem just came up once again and so I thought about bumping this thread ;)
     
  5. artician

    artician

    Joined:
    Nov 27, 2009
    Posts:
    345
    I am also interested in this, so *bump* again.
     
  6. sampenguin

    sampenguin

    Joined:
    Feb 1, 2011
    Posts:
    64
    Been looking for a solution to this for a while too. Hey Unity, how about a new button in inspector to "Remove Link" or something?
     
  7. Rod-Green

    Rod-Green

    Joined:
    Apr 19, 2010
    Posts:
    51
    This works - I've tried it. However be warned that it will active gameObjects and their children. So what I did was store the list of active values for the whole hierarchy and then reapply the active values on the clone

    Code (csharp):
    1.  
    2. string name = prefabedGO.name;
    3. Transform parent = prefabedGO.transform.parent;
    4.  
    5. // unparent the GO so that world transforms are preserved
    6. prefabedGO.transform.parent = null;
    7.  
    8. // clears prefab link
    9. GameObject unprefabedGO = (GameObject)Object.Instantiate(prefabedGO);
    10.  
    11. // assigned reverted values
    12. unprefabedGO.name = prefabedGO.name;
    13. unprefabedGO.active = prefabedGO.active;
    14.  
    15. // remove old
    16. DestroyImmediate(prefabedGO); // or this could just hide the old one .active = false;
    17.  
    18. // reparent clone
    19. unprefabedGO.transform.parent = parent;
    20.  
     
    Last edited: Oct 26, 2011
    black843 likes this.
  8. Moonjump

    Moonjump

    Joined:
    Apr 15, 2010
    Posts:
    2,572
    I appear to be getting errors because of prefabs not being permanently breaking the connection.

    My project had 2 prefabs with multiple elements in them. I only needed 1 prefab with some elements from each. So I dragged one into the scene, then broke the prefab. I then dragged the other in and broke that prefab. I moved the elements I wanted from one prefab into the other, then re-established the prefab on that one, and deleted the unused prefab in the Project view for the other.

    That should be fine, but I am getting errors such as:

    I have also edited several other prefabs, and they all appear to be corrupt now. I have submitted a bug about this before. Unity doesn't appear to like elements from one prefab being used in another. Breaking a prefab instance isn't enough to stop this. I'm using Unity 3.5.3.
     
  9. dval

    dval

    Joined:
    Jul 25, 2012
    Posts:
    24
    It seems the entire 'Prefabs' part of unity is buggy. I am also having the problem where "Break Prefab Instance" doesn't actually break the instance from the prefab, it just changes the color of the label in hierarchy.
    Further more, if I duplicate a prefab, break instance, rename, and create prefab with 'new' object, I now have two prefabs that get updated when I click the 'Apply' button. This is stupid. if were stuck with 'duplicate' creating linked objects, then there should also be an option to 'duplicate' as unlinked objects. or full copy. Maybe I'll make that a feature request....
     
  10. funasylum

    funasylum

    Joined:
    Feb 5, 2011
    Posts:
    48
    I concur. This is a big unnecessary headache. When I break a prefab instance I want it completely and totally broken. Otherwise it leads to all sorts of nightmares if 'broken' prefabs are accidently reconnected etc.
     
  11. stechmann

    stechmann

    Joined:
    Feb 24, 2012
    Posts:
    34
    Same problem here. WTF
     
  12. ddvgames

    ddvgames

    Joined:
    Apr 12, 2013
    Posts:
    3
    if you delete the prefab in the Project tab, and then select the object in Hierarchy tab, click GameObject>Break Prefab Instance. the object will become a GameObject without connection from the old prefab.

    if you don't want to lost your old prefab, just use that object to make a new prefab, and then delete the new prefab.
     
    Last edited: Jun 13, 2013
    Julian-Glenn and FernandoRCosta like this.
  13. iossif

    iossif

    Joined:
    Mar 4, 2011
    Posts:
    332
    why don't you instantiate the prefab? that should give you "just" the gameobject with no connection.
     
  14. AaronBiddlecom

    AaronBiddlecom

    Joined:
    Jan 28, 2013
    Posts:
    1
    This won't help if you already have an instance whose connection you want broken (particularly if you've made instance-level changes across multiple components/children).

    At any rate, here's the solution I came up with. Hacky, but works well with no erratic behavior that I've been able to tell. Basically, you just create a temporary dummy prefab to connect the GameObject to, which you can then delete in order to have a total break.

    Obviously, you should name this prefab something that doesn't conflict with an existing one.

    Code (csharp):
    1.  
    2. GameObject disconnectingObj;
    3. PrefabUtility.DisconnectPrefabInstance(disconnectingObj);
    4. Object prefab = PrefabUtility.CreateEmptyPrefab("Assets/dummy.prefab");
    5. PrefabUtility.ReplacePrefab(disconnectingObj, prefab, ReplacePrefabOptions.ConnectToPrefab);
    6. PrefabUtility.DisconnectPrefabInstance(disconnectingObj);
    7. AssetDatabase.DeleteAsset("Assets/dummy.prefab");
    8.  
    The one idiosyncracy is that if the GameObject in question is selected in the editor, a "SELECT" button will remain at the top of the inspector. It goes away if you deselect and reselect the object, and if you click it, it just deslects the object. Doesn't seem to cause any problems.

    Hope this helps!
     
    VivienS likes this.
  15. azpt

    azpt

    Joined:
    Feb 12, 2013
    Posts:
    3
    First, thanks AaronBiddlecom !

    This code resolves your minor issue

    Code (csharp):
    1.  
    2. GameObject disconnectingObj = Selection.activeGameObject;
    3. Selection.activeGameObject = null;
    4. PrefabUtility.DisconnectPrefabInstance(disconnectingObj);
    5. Object prefab = PrefabUtility.CreateEmptyPrefab("Assets/dummy.prefab");
    6. PrefabUtility.ReplacePrefab(disconnectingObj, prefab, ReplacePrefabOptions.ConnectToPrefab);
    7. PrefabUtility.DisconnectPrefabInstance(disconnectingObj);
    8. AssetDatabase.DeleteAsset("Assets/dummy.prefab");
    9. Selection.activeObject = disconnectingObj;
    10.  
     
    VivienS and Victor_Kallai like this.
  16. FernandoRCosta

    FernandoRCosta

    Joined:
    Aug 29, 2014
    Posts:
    5
    Thanks a lot ddvgames! That's what I looking for.
     
  17. flashframe

    flashframe

    Joined:
    Feb 10, 2015
    Posts:
    797
    I managed to break a prefab connection without deleting any existing prefabs by :

    1. Select object in hierarchy. Goto GameObject break prefab instance
    2. Drag object into project panel to create new prefab
    3. Delete the new prefab
    4. Select object in hierarchy. Goto GameObject break prefab instance
     
  18. lgarczynski

    lgarczynski

    Joined:
    Aug 17, 2015
    Posts:
    9
    I made it into a scriptable wizard!

    Simply place this in an appropriately named class in the editor folder.

    Code (CSharp):
    1.  
    2. using UnityEditor;
    3. using UnityEngine;
    4.  
    5. public class BreakPrefabWizard : ScriptableWizard
    6. {
    7.     [MenuItem("GameObject/Break Prefab Instance Definitive")]
    8.     static void CreateWizard()
    9.     {
    10.         GameObject disconnectingObj = Selection.activeGameObject;
    11.         Selection.activeGameObject = null;
    12.         PrefabUtility.DisconnectPrefabInstance(disconnectingObj);
    13.         Object prefab = PrefabUtility.CreateEmptyPrefab("Assets/dummy.prefab");
    14.         PrefabUtility.ReplacePrefab(disconnectingObj, prefab, ReplacePrefabOptions.ConnectToPrefab);
    15.         PrefabUtility.DisconnectPrefabInstance(disconnectingObj);
    16.         AssetDatabase.DeleteAsset("Assets/dummy.prefab");
    17.         Selection.activeObject = disconnectingObj;
    18.     }
    19. }
    20.  
     
  19. lgarczynski

    lgarczynski

    Joined:
    Aug 17, 2015
    Posts:
    9
    I decided to actually spend some time making it better, so here's a full editor suite.

    It feature undo, context menu items on components and in the hierarchy tab, as well as items in the GameObject menu. All those items disable themselves if no prefabs are selected.

    Code (CSharp):
    1.  
    2. using UnityEditor;
    3. using UnityEngine;
    4. using System.Linq;
    5.  
    6. public static class PrefabBreakMenuItems
    7. {
    8.   #region MENU_ITEMS
    9.  
    10.   /// <summary>
    11.   /// Breaks the prefab connection of every selected object and delete it permanently.
    12.   /// </summary>
    13.   [MenuItem("GameObject/Break Prefab Instance Definitive %&b", false, 29)]
    14.   [MenuItem("CONTEXT/Object/Break Prefab Instance Definitive", false, 301)]
    15.   static void MenuBreakInstanceDefinitive()
    16.   {
    17.   GameObject[] breakTargets = Selection.gameObjects;
    18.   Selection.activeGameObject = null;
    19.   BreakInstancesDefinitive(breakTargets);
    20.   Selection.objects = breakTargets;
    21.   }
    22.  
    23.   /// <summary>
    24.   /// Breaks the prefab connection of every selected object, but leaves the "Select - Revert - Apply" buttons.
    25.   /// </summary>
    26.   [MenuItem("GameObject/Break Prefab Instance", false, 28)]
    27.   [MenuItem("CONTEXT/Object/Break Prefab Instance", false, 300)]
    28.   static void ContextBreakInstance(MenuCommand command)
    29.   {
    30.   GameObject[] breakTargets = Selection.gameObjects;
    31.   Selection.activeGameObject = null;
    32.   BreakInstances(breakTargets);
    33.   Selection.objects = breakTargets;
    34.   }
    35.  
    36.   /// <summary>
    37.   /// Checks if any elements of the selection contain prefabs.
    38.   /// </summary>
    39.   [MenuItem("CONTEXT/Object/Break Prefab Instance", true)]
    40.   [MenuItem("CONTEXT/Object/Break Prefab Instance Definitive", true)]
    41.   [MenuItem("GameObject/Break Prefab Instance", true)]
    42.   [MenuItem("GameObject/Break Prefab Instance Definitive %&b", true)]
    43.   static bool PrefabCheck()
    44.   {
    45.   GameObject[] goSelection = Selection.gameObjects;
    46.  
    47.   return (goSelection.Any(x => PrefabUtility.GetPrefabParent(x)));
    48.   }
    49.  
    50.   #endregion
    51.  
    52.   #region LOGIC
    53.  
    54.   /// <summary>
    55.   /// Breaks the prefab connections of a list of GameObject and delete them permanently.
    56.   /// Records an undo.
    57.   /// </summary>
    58.   public static void BreakInstancesDefinitive(GameObject[] targets)
    59.   {
    60.   Undo.RegisterCompleteObjectUndo(targets, "Breaking multiple prefab instances definitively");
    61.  
    62.   Object prefab = PrefabUtility.CreateEmptyPrefab("Assets/dummy.prefab");
    63.   foreach (var target in targets)
    64.   {
    65.   PrefabUtility.ReplacePrefab(target, prefab, ReplacePrefabOptions.ConnectToPrefab);
    66.   PrefabUtility.DisconnectPrefabInstance(target);
    67.   }
    68.   AssetDatabase.DeleteAsset("Assets/dummy.prefab");
    69.  
    70.   Undo.RecordObjects(targets, "Breaking multiple prefab instances definitively");
    71.   }
    72.  
    73.  
    74.   /// <summary>
    75.   /// Breaks the prefab connection of a single GameObject and delete it permanently.
    76.   /// Records an undo.
    77.   /// </summary>
    78.   public static void BreakInstanceDefinitive(GameObject target)
    79.   {
    80.   Undo.RegisterCompleteObjectUndo(target, "Breaking single prefab instance definitively");
    81.  
    82.   Object prefab = PrefabUtility.CreateEmptyPrefab("Assets/dummy.prefab");
    83.    
    84.   PrefabUtility.ReplacePrefab(target, prefab, ReplacePrefabOptions.ConnectToPrefab);
    85.   PrefabUtility.DisconnectPrefabInstance(target);
    86.  
    87.   AssetDatabase.DeleteAsset("Assets/dummy.prefab");
    88.   }
    89.  
    90.   /// <summary>
    91.   /// Breaks the prefab connections of a list of GameObject, but leaves the "Select - Revert - Apply" buttons.
    92.   /// Records an undo.
    93.   /// </summary>
    94.   public static void BreakInstances(GameObject[] targets)
    95.   {
    96.   Undo.RegisterCompleteObjectUndo(targets, "Breaking multiple prefab instances");
    97.    
    98.   foreach (var target in targets)
    99.   {
    100.   PrefabUtility.DisconnectPrefabInstance(target);
    101.   }
    102.   }
    103.  
    104.   /// <summary>
    105.   /// Breaks the prefab connection of a single GameObject, but leaves the "Select - Revert - Apply" buttons.
    106.   /// Records an undo.
    107.   /// </summary>
    108.   public static void BreakInstance(GameObject target)
    109.   {
    110.   Undo.RegisterCompleteObjectUndo(target, "Breaking single prefab instance");
    111.   PrefabUtility.DisconnectPrefabInstance(target);
    112.   }
    113.  
    114.   #endregion
    115. }
    116.  
     

    Attached Files:

    Last edited: Jan 22, 2016
    Nick62, iprogrammer, fadden and 2 others like this.
  20. flowerMaster

    flowerMaster

    Joined:
    Apr 27, 2013
    Posts:
    33
    I found an easy way to deal with this stupid problem. Drag the gameobject into the assets folder to turn it into a prefab, thus forgetting about the old broken prefab connection. Then delete the new prefab, leaving the gameobject with a 'missing' prefab. Finally, select that gameobject and click 'GameObject' on the top menu and select 'Break Prefab Instance'.
     
  21. Bas-Smit

    Bas-Smit

    Joined:
    Dec 23, 2012
    Posts:
    274
    Edit: bugfix

    Code (CSharp):
    1. public static void RemoveDisconnectedReferences(string scenePath)
    2. {
    3.    var lines = File.ReadAllLines(scenePath);
    4.    var sb = new StringBuilder();
    5.    var inPrefab = false;
    6.    var removingDisconnectedPrefab = false;
    7.  
    8.    for (int i = 0; i < lines.Length; i++)
    9.    {
    10.      var line = lines[i];
    11.  
    12.      if (line.StartsWith("---"))
    13.        inPrefab = lines[i + 1] == "Prefab:";
    14.  
    15.      if (inPrefab)
    16.        sb.Append(line + "\n");
    17.      else
    18.      {
    19.        if (line.StartsWith("  m_PrefabParentObject:"))
    20.        {
    21.          sb.Append("  m_PrefabParentObject: {fileID: 0}\n");
    22.          removingDisconnectedPrefab = true;
    23.        }
    24.        else
    25.        {
    26.          if (!(removingDisconnectedPrefab && line.StartsWith("  type:")))
    27.            sb.Append(line + "\n");
    28.  
    29.          removingDisconnectedPrefab = false;
    30.        }
    31.      }
    32.    }
    33.  
    34.    File.WriteAllText(scenePath, sb.ToString());
    35. }
     
    Last edited: Mar 18, 2016
  22. josessito

    josessito

    Joined:
    Feb 14, 2014
    Posts:
    57


    Thank you so much for this!!!
     
  23. DraftedVisions

    DraftedVisions

    Joined:
    May 21, 2014
    Posts:
    1
    Thank you! This works. Still annoying, but at least it's a simple solution.
     
  24. JBLZR

    JBLZR

    Joined:
    Mar 6, 2017
    Posts:
    2
    This is not working for me at all, I can't bare Unity sometimes.

    Literally the other day i Duplicated the Prefab, Dragged it to Hierarchy, duplicated it, renamed it, disconnected the prefab instance and made a new Prefab.

    Worked for a dozen objects, I come back the next day and it just does not work.

    Program is bothering me now.