Search Unity

Question Changing Prefab Hierarchy from Script

Discussion in 'Prefabs' started by Moritz5thPlanet, Aug 17, 2021.

  1. Moritz5thPlanet

    Moritz5thPlanet

    Joined:
    Feb 5, 2019
    Posts:
    73
    Trying to do even small changes to a hierarchy to a prefab on disk yields this error:
    Setting the parent of a transform which resides in a Prefab Asset is disabled to prevent data corruption

    What an absurd error in the age of nested prefabs... (also, it's my disk, my script, my prefab, ahem...)
    What is the correct way to execute such hierarchy changes, then? Load and unpack the prefab and then overwrite on disk?

    I also haven't found a way on all of the internet and documentation to open the prefab stage from script, which I find terrifying a whole 3 years in from Unity 2018 with the new prefab workflow :D

    PrefabUtility.LoadPrefabContents(string assetPath); gives me the above error, it seems. And AssetDatabase.OpenAsset(...) strikes me as just one tenuous step away from using AutoIt to click the button for my script...
     
    Last edited: Aug 17, 2021
  2. SteenLund

    SteenLund

    Unity Technologies

    Joined:
    Jan 20, 2011
    Posts:
    639
    There are some older example here https://github.com/Unity-Technologi...e2/Assets/Editor/Scripts/CreateNesting.cs#L23

    Though today I would use PrefabUitlity.EditPrefabContentsScope instead:

    Code (CSharp):
    1.     [MenuItem("Prefabs/Nesting/NestBInA Via Content")]
    2.     static public void NestBInAViaContent()
    3.     {
    4.         string path = "Assets/Prefabs/A.prefab";
    5.  
    6.         var goB = (GameObject)AssetDatabase.LoadMainAssetAtPath("Assets/Prefabs/B.prefab");
    7.         var instanceB = (GameObject)PrefabUtility.InstantiatePrefab(goB);
    8.  
    9.         using (var editingScope = new [URL='https://docs.unity3d.com/ScriptReference/PrefabUtility.EditPrefabContentsScope.html']PrefabUtility.EditPrefabContentsScope[/URL](path))
    10.         {
    11.             var root = editingScope.prefabContentsRoot;
    12.  
    13.             instanceB.GetComponent<Transform>().parent = root.GetComponent<Transform>();
    14.             PrefabUtility.RecordPrefabInstancePropertyModifications(instanceB.GetComponent<Transform>());
    15.         }
    16.     }
     
  3. Moritz5thPlanet

    Moritz5thPlanet

    Joined:
    Feb 5, 2019
    Posts:
    73
    Thank you for the reply - in the example here https://docs.unity3d.com/2020.1/Doc...ce/PrefabUtility.EditPrefabContentsScope.html after the line
    PrefabUtility.SaveAsPrefabAsset(source, assetPath);

    Wouldn't the developer be expected to call DestroyImmediate(source), lest the gameobject that was saved (but not connected) as the prefab still remain in whatever scene is active?

    I usually set hideflags on these objects but I need to reset the flags if I want to save the prefab.

    Asking for a friend. :)
     
  4. SteenLund

    SteenLund

    Unity Technologies

    Joined:
    Jan 20, 2011
    Posts:
    639
    True, the example code does not clean up properly