Search Unity

  1. Unity 2019.2 is now released.
    Dismiss Notice

Destroying a GameObject inside a Prefab instance is not allowed

Discussion in 'Prefabs' started by stephero, Sep 15, 2018.

  1. stephero

    stephero

    Joined:
    Feb 8, 2016
    Posts:
    83
    Hi guys,

    I encounter a very annoying issue with the new prefab workflow.

    I have a "master" GameObject which procedurally generates a sub GameObject as child.
    The child GameObject is not serialized since it's procedurally recomputed from the "Start" callback (both in editor and runtime).
    Note that the child GameObject is flagged as NotEditable AND DontSave via the HideFlags.

    When I duplicate my master GameObject in the editor, or when I instantiate a prefab storing my master GameObject, the sub GameObject is also duplicated. To fix this issue, I used to destroy the "old" sub GameObject. Basically, from the sub GameObject, I store a reference on its master. If this reference is broken, I know that this sub GameObject is duplicated or instantiated, so I could safely destroy it using DestroyImmediate.

    This trick used to work very very well... until the new prefab workflow introduced in 2018.3.0b1.
    In the beta, when I drop a prefab storing a "master" GameObject, I got this very annoying error message:
    InvalidOperationException: Destroying a GameObject inside a Prefab instance is not allowed.
    and my "old" sub GameObject is not properly destroyed.

    Why is this not allowed anymore? How are we supposed to deal with procedurally objects inside prefabs?

    Thanks
     
    Thaina likes this.
  2. TooManySugar

    TooManySugar

    Joined:
    Aug 2, 2015
    Posts:
    864
    I've not tested this yet cause my prefabs are broken but this sounds
    "Destroying a GameObject inside a Prefab instance is not allowed."
    This is an operation I do constantly in my tank editor hope this is adressed soon.
     
  3. Mads-Nyholm

    Mads-Nyholm

    Unity Technologies

    Joined:
    Aug 19, 2013
    Posts:
    92
    Hi stephero,
    Please create a bug report with a small repro project, then we will take a look at your use case. Thanks
     
  4. stephero

    stephero

    Joined:
    Feb 8, 2016
    Posts:
    83
    Hi,
    I filled a bug report (1084109), but I discovered something really interesting. This problem only occurs if the prefab has been created with older Unity version! Mine was created in Unity 5.2.0f3.
    I tried to create the prefab with many different Unity versions, but was able to reproduce the bug only when created with 5.2.
    Here is a repro project. Open it in Unity 2018.3.0b1 (or b2) and drag and drop the prefab in a scene. Alternatively you can run the test runner (I made a unit-test which highlights the problem).
    Thanks
     

    Attached Files:

    Last edited by a moderator: Sep 24, 2018
  5. james7132

    james7132

    Joined:
    Mar 6, 2015
    Posts:
    110
    Does reimporting fix the issue? I seem to be running into the same issue when building asset bundles.
     
  6. stephero

    stephero

    Joined:
    Feb 8, 2016
    Posts:
    83
    No reimporting the prefab doesn't fix the issue.
     
  7. konsic

    konsic

    Joined:
    Oct 19, 2015
    Posts:
    632
    I'm importing asset bundles from Blende. I have to unlink them to drag them in Prefab folder first.
    When I parent some prefab, it seems that it looses location information.

    I'm confused with new prefabs and how it works with parenting.


    When imporiting form 2018.2.8 HDRP in 2018.3 HDRP, Unity deletes all folders and scripts. It only leaves sample scene.
     
  8. LeonhardP

    LeonhardP

    Unity Technologies

    Joined:
    Jul 4, 2016
    Posts:
    1,487
    Could you please submit a bug report with a reproduction project? That would be very helpful.
     
  9. MatthieuPr

    MatthieuPr

    Joined:
    May 4, 2017
    Posts:
    56
    I tried to make a small repo to reproduce the bug, sadly the editor keeps going into infinite loop before able to reproduce in separate project. I did submit the infinite loop bug and got reply it was sent do the DEVS, so that is one that will be killed at least...

    On a different note: I was able to solve that error in editor. The cause was editor script dynamically adding and removing nested prefabs and if the prefab was saved with already nested prefabs present in it trying to remove them with an editor script gives that error.

    On a separate note, I am now able to generate that error at RUNTIME in our project, which is very strange cause runtime should not have any prefabs at all. I have not been able to reproduce this part in a separate project, this will most likely be work for today, trying to break nested prefabs some more ;)
     
  10. LeonhardP

    LeonhardP

    Unity Technologies

    Joined:
    Jul 4, 2016
    Posts:
    1,487
    Thanks a lot Matthieu, this is all incredibly helpful!
     
  11. MatthieuPr

    MatthieuPr

    Joined:
    May 4, 2017
    Posts:
    56
    no problem, I spent about 2 days on the new nested prefab system and reported 3 different issues related to our current project. One of them is this specific issue. The next few days will try to do same to the ECS.
     
    LeonhardP likes this.
  12. LeonhardP

    LeonhardP

    Unity Technologies

    Joined:
    Jul 4, 2016
    Posts:
    1,487
  13. konsic

    konsic

    Joined:
    Oct 19, 2015
    Posts:
    632
  14. LeonhardP

    LeonhardP

    Unity Technologies

    Joined:
    Jul 4, 2016
    Posts:
    1,487
    No it's still being worked on. You can follow the resolution status through the issue tracker link I posted above.
     
  15. konsic

    konsic

    Joined:
    Oct 19, 2015
    Posts:
    632
    @LeonhardP it says now
    What does this mean improved prefabs ?

    How can I make sure prefabs are not improved ?
     
  16. LeonhardP

    LeonhardP

    Unity Technologies

    Joined:
    Jul 4, 2016
    Posts:
    1,487
  17. konsic

    konsic

    Joined:
    Oct 19, 2015
    Posts:
    632
    Ok, please fix this in next beta.
     
  18. MatthieuPr

    MatthieuPr

    Joined:
    May 4, 2017
    Posts:
    56
    This is related to the infinite loop bug I reported in here:

    We have fixed this problem and it should not appear in the 2019.1.0a9 version.
    If you are still able to reproduce it on the latest version of Unity, please respond to this email.

    https://issuetracker.unity3d.com/is...hild-prefab-which-has-been-previously-deleted

    Related to the bug for those wandering, I have found the reason and so far I know that is actually works as intended.
    When you are adding GameObject to a prefab in prefab mode, you will get this error when you try to delete that gameObject in editor mode. GameObjects (and I assume nested prefabs as well) can only be added/removed in the sceneMode where they were added and from what I understood, you should only do this in PrefabMode as that is where you edit a prefab, in editor you are working with an INSTANCE of the prefab and not the actual prefab (so can't apply changes etc.)

    In short, old workflows can be throws out of the window cause 80% of them no longer apply in the new nested prefab system. Based on all the tools we have for generating UI dynamically in editor, we can throw all of that away + redo entire UI from scratch to be able to upgrade to Unity 2018.3...
     
    JBR-games and konsic like this.
  19. mkgame

    mkgame

    Joined:
    Feb 24, 2014
    Posts:
    582
    I'm trying to destroy a GameObject inside of a prefab in editor script for 3DMesh synchronization purposes (Asset: PrefabUpdater): "GameObject.DestroyImmediate (filter.gameObject);". Are there another possibilities in editor script to remove a GameObject in an instantiated prefab. PrefabUtility is able to remove a component, but not a GameObject.

    Should this work in the future releases, in 2019.1.0a9?
     
    Last edited: Dec 31, 2018
  20. NibbleByte3

    NibbleByte3

    Joined:
    Aug 9, 2017
    Posts:
    8
    I believe that you're supposed to use PrefabUtility.LoadPrefabContents() + PrefabUtility.SaveAsPrefabAsset() + PrefabUtility.UnloadPrefabContents() to load prefab instance into memory, modify it and then save it back.
    Read carefully the description of these methods. It seems to work with my tools.

    In the previous workflow you again had to instantiate prefab into your current scene, modify it and apply it back, so I guess this won't change much things. It is now even better, because it doesn't actually instantiate the prefab into your current working scene, which was weird. PrefabUtility.LoadPrefabContents() seems to load the prefab in a scene somewhere in the background and doesn't pop up in the Hierarchy, so be careful not to leak stuff.
     
    Last edited: Jan 9, 2019
    mkgame likes this.
  21. mkgame

    mkgame

    Joined:
    Feb 24, 2014
    Posts:
    582
    I missed this method PrefabUtility.LoadPrefabContents(), could have a better name. I used instead unpack, then I replaced the original prefab. You may right, if this works fine, then it is a more cleaner workflow. Thanks!
     
  22. TooManySugar

    TooManySugar

    Joined:
    Aug 2, 2015
    Posts:
    864
    this is driving me mad. Seriously add the option for this to be possible without entering prefab mode. This prefab system feels designed by a double agent from Unreal engine or something like that to ****up Unity's user base.
     
    jrumps likes this.
  23. TooManySugar

    TooManySugar

    Joined:
    Aug 2, 2015
    Posts:
    864
    also, when deleting, it forces you to prefab mode, and if your prefab is very complex with a long tree, like a complex UI it LAAAGS, when deleting objects. Plus any change you make is pretty much permanent... WT*************
     
    jrumps likes this.
  24. Lewnatic

    Lewnatic

    Joined:
    Sep 29, 2012
    Posts:
    191
    How is Unity so terrible lately? Lots of issues ... starting with unity 2017 and its getting worse with every new version. Unity 5.6 was very stable and i am actively thinking about switching the game engine for my next project.
     
  25. TooManySugar

    TooManySugar

    Joined:
    Aug 2, 2015
    Posts:
    864
    I know its crazy right?, I've also started to think about it for my next project.
    But all the time spent in this engine, that is no joke. But the prefab move was an stupid one, with quite despotic too.
     
    jrumps likes this.
  26. TooManySugar

    TooManySugar

    Joined:
    Aug 2, 2015
    Posts:
    864
    TBH, I never thought I was gonna do this, but I've installed U.E.
    I'm obviously not switching but I'm going to start to mess with it and may be do an small new project I had planned for Unity in there.

    I'm atm about to deliver a several years of work project on Steam and XbOne so losing all that bkg on an engine is a tough decision but I recall when Autocad started to do stupid things and I swapped to Microstation, it was tough, but I'll never regret. MS has a MUCH more serious/professional way of doing the things and that is what I need, seeing my workflows damaged or destroyed by no reason is simply too much. The new prefab system has been poorly integrated bye new features being added AT A COST of too much. New features I may or may not use? fine!! at the cost of my AND MANY others workflow? NO.
    I can´t switch back because there are other enhancementes that I trully need like the new physics being stable enough so I can have same physic performance like u.4.7 with joints as since it has been performing extremely poorly.
    Doint this in the MIDDLE of a product cycle is a thing I can´t pardon.
    If they release LTS with former prefab system I may stay for some years otherwise they're paving the way to the exit.

    One thing that *ucks form U.E is the marketplace, is way less populated than Unity's.
     
  27. Lewnatic

    Lewnatic

    Joined:
    Sep 29, 2012
    Posts:
    191
    The terrible thing is that i also cannot move back to 5.6 because it crashes every time. Also Unity collab is not really working. This is something you only experience for yourselve when you try to revert to a very old version and switch back to 5.6 and yes people are paying for that service. I am currently storing my projects once per month on multiple hard-drives.

    So i am basically trapped now at 2018.3 with all the errors. I tried 2019 but it seems to have even more errors. I can only run my game. But i cannot build it because i am getting stuff like this:


    On top of that it seems like the "standalone" version is not really standalone anymore and requires the right .NET installed. So i need to figure out what the right .NET is to tell my customers what they have to install.

    On top of that it seems like builds are not working anymore for my russian customers because when building with mono as a scripting backend it only uses latin and not cyrill. So people running it on russian OS installs simply get a crash because the data path cannot be read.

    For everyone new. Do NEVER upgrade your projects. Do not move to Unity 2018. Lessons learned.

    This is also a good reason why we need more open source engines. Blender and krita are good example for open source and free projects that are blowing paid services out of the water. Lets hope https://godotengine.org/ will be that big in the future.
     
    Last edited: Jan 24, 2019
    JBR-games likes this.
  28. Thaina

    Thaina

    Joined:
    Jul 13, 2012
    Posts:
    240
    Bug report should be created internal by YOU from the forum because the forum is where we could collectively discuss the problem. Bug report have no collective sense that people are having problem on something and should it be fixed. It privately report system make us never know how it progress and and better solution and how many people stuck on the same thing

    If the bug report system is like github issue it would be better. But it not so we use forum to report problem
     
    jrumps likes this.
  29. TooManySugar

    TooManySugar

    Joined:
    Aug 2, 2015
    Posts:
    864
    This is not a bug, this is a side effect of a poorly implemented system.
     
  30. dmitryzenevich

    dmitryzenevich

    Joined:
    Jun 9, 2017
    Posts:
    2
    If Prefab instance, i do following things
    Code (CSharp):
    1. if (UnityEditor.PrefabUtility.IsPartOfPrefabInstance(transform))
    2.                             UnityEditor.PrefabUtility.UnpackPrefabInstance(gameObject, UnityEditor.PrefabUnpackMode.Completely, UnityEditor.InteractionMode.AutomatedAction);
    Then I do DestroyImmediate();
    Sorry for my English.
     
    Dom1nus likes this.
  31. hungrybelome

    hungrybelome

    Joined:
    Dec 31, 2014
    Posts:
    245
    I would think that the lesson is to use version control, so that if you have problems after upgrading to a new version, you can just roll back the changes to your serialized assets, and delete your Library/ to force generation of a new one in your old version.
     
    JBR-games likes this.
  32. Lewnatic

    Lewnatic

    Joined:
    Sep 29, 2012
    Posts:
    191
    Yeah i thought that as well ... until i used Unity collab. Oooh.. how wrong i was.There are sadly multiple things that are terribly wrong with collab, especially when you have a slow internet connection like I have.

    1. Commit sometimes does not work. And it generates a random message that does not really explain what is wrong. So you have to dig deep to find a solution for this. The solution in my case was to delete some local data. After couple of commits i had the same problem again so I canceled my subscription.
    2. After Unity 2018.3 when you have upgrade a prefab to a nested prefab. It seems like you cannot go back to Unity 5.6 with collab.
    3. Nearly lost my project because of collab doing silly things. So no thanks. Had to put my assets together from multiple projects instances. And yeah I gladly also have saved my work on my HD. So gladly for me not much was lost.
     
    Last edited: Jan 29, 2019
  33. Baste

    Baste

    Joined:
    Jan 24, 2013
    Posts:
    4,096
    Yeah don't use Collab. I don't know why Unity thinks Collab is a good idea, and I don't know why anyone would look at it and think it's a good idea.

    One of the main features of a VC system when working with Unity is that it allows you to revert from making file changes that break Unity. If the VC system requires Unity to be open to work, then it's already useless by design.
     
    jrumps likes this.
  34. Dom1nus

    Dom1nus

    Joined:
    Sep 4, 2017
    Posts:
    1
    Wonderful! Thanks! Привет из Харькова :)
     
  35. tenderclawsJK

    tenderclawsJK

    Joined:
    Jan 12, 2019
    Posts:
    12
    I was trying to get around this issue by first calling UnpackPrefabInstance, then deleting the objects (and doing other things) then SaveAsPrefabAssetAndConnect. Unfortunately, this breaks other references to the prefab object that weren't broken before by calling ReplacePrefab. ARGH!
     
  36. SteenLund

    SteenLund

    Unity Technologies

    Joined:
    Jan 20, 2011
    Posts:
    439
    @tenderclawsJK

    If you want to do edits like that from script you should use LoadPrefabContents.


    Code (CSharp):
    1. var rootGO = PrefabUtility.LoadPrefabContents(pathToMyPrefab);
    2. // Destroy child objects or components on rootGO
    3. PrefabUtility.SaveAsPrefabAsset(rootGO, pathToMyPrefab);
    4. prefabUtility.UnloadPrefabContents(rootGO);
     
    han_xu and JBR-games like this.
  37. Ev-Roll7

    Ev-Roll7

    Joined:
    Mar 6, 2019
    Posts:
    2
    Hello

    I've been running into this issue as well.
    Is the above reply really the best way of doing that? Not being able to delete game objects in a prefab is a pretty big deal, especially for procedurally generated content.
    If the above trick does indeed work - why not wrap it up in a PrefabUtility.DestroyChild method or some such?

    Say I have a very basic "spawn random meshes" method inside a prefab, and I want to clear the children before - this becomes convoluted and pretty messy.
     
  38. ALI3D69

    ALI3D69

    Joined:
    Apr 20, 2014
    Posts:
    10

    Hi. I try this. but i still get this error:
    "InvalidOperationException: Destroying a GameObject inside a Prefab instance is not allowed."

    here is my code:
    Code (CSharp):
    1. public void DeletePeople()
    2.     {
    3.         if (UnityEditor.PrefabUtility.IsPartOfPrefabInstance(this.gameObject))
    4.         {
    5.             var prefabPath = UnityEditor.PrefabUtility.GetPrefabAssetPathOfNearestInstanceRoot(this.gameObject);
    6.             var prefabRoot = UnityEditor.PrefabUtility.LoadPrefabContents(prefabPath);
    7.  
    8.             int c = myTrans.childCount;
    9.             for (int i = 0; i < c; i++)
    10.             {
    11.                 DestroyImmediate(myTrans.GetChild(0).gameObject, true);
    12.             }
    13.  
    14.             UnityEditor.PrefabUtility.SaveAsPrefabAsset(prefabRoot, prefabPath);
    15.             UnityEditor.PrefabUtility.UnloadPrefabContents(prefabRoot);
    16.         }
    17.     }

    I want to have a crowd prefab. and each instance of the prefab have different number of people. I have button on the prefab to change the number of people. first i want to delete all the child of prefab object and then instantiate new ones but i cant delete the old ones!
     
    Last edited: May 5, 2019
  39. trappist-1

    trappist-1

    Joined:
    Mar 26, 2017
    Posts:
    462
    Piecing together a function from some templates I had laying around; here's one solution I managed to get working:
    Code (csharp):
    1. using UnityEngine;
    2.  
    3. #if UNITY_EDITOR
    4. using UnityEditor;
    5.  
    6. public static class MyExtensionMethods
    7. {
    8.     static Component GetComponentMethod<T> (this GameObject go)  where T : Component
    9.     {
    10.         return go.GetComponentInChildren<T> (); //modifying this line can change how components are located in the main object
    11.         //return go.GetComponent<T> (); //Alternate search option 1
    12.         //return go.GetComponentInParent<T> (); //Alternate search option 2
    13.  
    14.     }
    15.  
    16.     public static void DestroyComponentInPrefab<T>(this GameObject go) where T : Component
    17.     {
    18.         var component = go.GetComponentMethod<T> ();
    19.         if (component == null)
    20.         {
    21.             return;
    22.         }
    23.         bool isPrefabInstance = PrefabUtility.GetPrefabParent(component) != null && PrefabUtility.GetPrefabObject(component.transform) != null;
    24.         if (isPrefabInstance)
    25.         {
    26.             GameObject clone = GameObject.Instantiate(go) as GameObject;
    27.             Object.DestroyImmediate (clone.GetComponentMethod<T> ().gameObject);
    28.             try
    29.             {
    30.                 PrefabUtility.ReplacePrefab (clone, PrefabUtility.GetPrefabParent (go));
    31.             }
    32.             finally
    33.             {
    34.                 GameObject.DestroyImmediate (clone);
    35.             }
    36.         }
    37.         else
    38.         {
    39.             Object.DestroyImmediate (component.gameObject);
    40.         }
    41.     }
    42. }
    43.  
    44. //Usage example:
    45. [CustomEditor(typeof(MyBaseScript))]
    46. class MyBaseScriptEditor : Editor
    47. {
    48.     public override void OnInspectorGUI()
    49.     {
    50.         MyBaseScript myScript = (MyBaseScript)target;
    51.         var go = myScript.gameObject;
    52.         if (GUILayout.Button ("Remove Unused Components"))
    53.         {
    54.             go.DestroyComponentInPrefab<MyComponent> (); //Removes the "MyComponent" component from the "go" object or prefab
    55.         }
    56.         DrawDefaultInspector ();
    57.         serializedObject.ApplyModifiedProperties();
    58.     }
    59. }
    60. #endif
    It basically creates a clone gameobject, modifies it, then replaces the original prefab.
    Also, if the object supplied is not a prefab, 'isPrefabInstance' will be false and the component will be destroyed normally.

    Also with small modification you can change it to destroy just the component instead of the entire GO.
    Just remove the ".gameobejct" part from inside the two DestroyImmediate() functions and you're set.


    Hope it is helpful :)
     
    Last edited: May 10, 2019
    JBR-games and Subliminum like this.