Search Unity

Replacing Prefab without changing asset ID

Discussion in 'Prefabs' started by VirtualDestructor, Feb 3, 2019.

  1. VirtualDestructor

    VirtualDestructor

    Joined:
    May 3, 2014
    Posts:
    44
    I'm really liking the new prefab functionality in 2018.3.

    I have an editor script that generates a prefab. I want it to overwrite an existing prefab without changing the asset ID (there are references to the prefab elsewhere in the application). It is my understanding that this would have been done with PrefabUtility.ReplacePrefab(), but this method is now obsolete. I am using PrefabUtility.SaveAsPrefabAssetAndConnect(), it will overwrite the prefab but it seems to generate a new asset ID each time. Is there any way to overwrite the existing prefab without generating a new asset ID?
     
  2. JesOb

    JesOb

    Joined:
    Sep 3, 2012
    Posts:
    1,109
    Try to simply delete prefab file and create new one using System.IO.File
    Or may be create new prefab using Unity methods and rename it into your using System.IO.File
     
  3. SteenLund

    SteenLund

    Unity Technologies

    Joined:
    Jan 20, 2011
    Posts:
    639
    @JakeC

    For now please use ReplacePrefab with the ReplaceNameBased flag. Even thought the method is obsolete it still works. We are working on a replacement inline with the new API.
     
    Last edited: Feb 12, 2019
    joshcamas likes this.
  4. VirtualDestructor

    VirtualDestructor

    Joined:
    May 3, 2014
    Posts:
    44
    Thanks for the feedback. ReplacePrefab writes the prefab but seems to invalidate the existing prefab references somehow. Is there any way to programatically overwrite the prefab and preserve references to the prefab in the inspector?
     
  5. SteenLund

    SteenLund

    Unity Technologies

    Joined:
    Jan 20, 2011
    Posts:
    639
    Can you please share a test project?
     
  6. VirtualDestructor

    VirtualDestructor

    Joined:
    May 3, 2014
    Posts:
    44
    I've attached a unity package that has a simple script that reproduces the issue. Here are the steps to reproduce:

    1) Open "Prefab Issue Scene"
    2) Click on the "Prefab Reference" object in the scene hierarchy. You will see that Prefab is set to "Test Prefab"
    3) Click on "Prefab Issue->Prefab Issue Window" (a custom editor window I made)
    4) The window has only one field, the prefab to overwrite. It should automatically be populated with "Test Prefab"
    5) Click on "Write Prefab." Go back and look at the "Prefab Reference" object in the scene hierarchy. For me it now says the prefab is missing.

    The code to write the prefab is in PrefabIssueWindow.cs:

    Code (CSharp):
    1. // replace the prefab with another object
    2. var emptyGameObject = new GameObject("Empty");
    3. PrefabUtility.ReplacePrefab(emptyGameObject, prefabReference, ReplacePrefabOptions.ConnectToPrefab);
    4. DestroyImmediate(emptyGameObject);
    Note that I am not on the latest version of Unity. I am using 2018.3.1f1.

    Since I am not able to replace the existing prefab, I have been simply overwriting the old prefab at the specified path.
    Using this approach, references in the inspector to the prefab are still broken, but instances of the prefab in the scene are still there but their positions and any overridden fields are reset (maybe this is the expected behavior)

    Sorry about the delay in getting back to you about this. I thought I could work around this bug, but it is giving me trouble again and I would like to see if I can fix it without totally changing my approach.
     

    Attached Files:

  7. tcjkant

    tcjkant

    Joined:
    Jan 12, 2019
    Posts:
    15
    ReplaceNameBased breaks the prefab instance's connection though...and using ReplacePrefabOptions.ConnectToPrefab breaks external references to prefab (didn't use to).
     
  8. tcjkant

    tcjkant

    Joined:
    Jan 12, 2019
    Posts:
    15
    Trying this:

    Code (CSharp):
    1. PrefabUtility.ReplacePrefab(gameObject, prefabObj, ReplacePrefabOptions.ReplaceNameBased);
    2. PrefabUtility.ConnectGameObjectToPrefab(gameObject, prefabObj);
    Appears to work (though both calls are marked as obsolete) but now references to the prefab instance are broken, even though references to the prefab root remain intact.

    Previously, simply calling "PrefabUtility.ReplacePrefab(gameObject, prefabObj, ReplacePrefabOptions.ConnectToPrefab)" did what was intended - it updated the prefab root to match the contents of the modified prefab instance, while preserving references both to the prefab root and the prefab instance.
     
    Last edited: Mar 5, 2019
  9. VirtualDestructor

    VirtualDestructor

    Joined:
    May 3, 2014
    Posts:
    44
    Thanks for looking into this. It seems that calling PrefabUtility.ReplacePrefab() with ReplacePrefabOptions.ReplaceNameBased does what I need it to do. References in the inspector remain intact and the transforms of the instances in the scene are unchanged.
     
  10. SomeLazyDev

    SomeLazyDev

    Joined:
    Sep 15, 2020
    Posts:
    4
    Are there any updates on this topic?
     
  11. paulbettner

    paulbettner

    Joined:
    Jan 13, 2014
    Posts:
    14
    Topic bump.