Search Unity

Replacing a prefab in script woes

Discussion in 'Scripting' started by SuppleTeets, May 30, 2017.

  1. SuppleTeets

    SuppleTeets

    Joined:
    Aug 22, 2014
    Posts:
    30
    In an attempt to get around the issue of skinned mesh renderers breaking in prefabs when their FBX files are updated with a character rig change, I've created a different workflow that goes like this. I keep the character setup in its own scene file(the rig doesn't break with updates this way) and I wrote this script that creates a duplicate, saves it as a prefab, then deletes the duplicate. This has been working wonderfully except for one small thing.

    Code (CSharp):
    1.  
    2. static void CreatePrefab()
    3. {
    4.     GameObject[] selObjs = Selection.gameObjects;
    5.     foreach (GameObject selObj in selObjs)
    6.     {
    7.         string charName = selObj.name;
    8.  
    9.         // duplicate
    10.         GameObject newInstance = Instantiate(selObj);
    11.         newInstance.name = charName;
    12.  
    13.         // now replace the prefab
    14.         UnityEngine.Object newPrefab = PrefabUtility.CreateEmptyPrefab("Assets/Resources/" + charName + ".prefab");
    15.         PrefabUtility.ReplacePrefab(newInstance, newPrefab, ReplacePrefabOptions.ConnectToPrefab);
    16.  
    17.         // delete dupe
    18.         DestroyImmediate(newInstance);
    19.  
    20.         Debug.Log("Prefab'd " + charName + "!");
    21.     }
    22. }
    23.  
    The problem I'm running into is if I do these steps by manually in the editor by hand all is well, but when I run this script (with ANY of the ReplacePrefabOptions set) changes to the prefab instance in other scenes are lost, as if I hit the revert button in the inspector. If I do it by hand those changes remain in the scenes, but when I do it with this script they do not.

    Can anyone shed some light on this for me? What exactly is the drag and drop functionality in the editor doing differently?

    Thanks
     
    Last edited: May 30, 2017
  2. jschieck

    jschieck

    Joined:
    Nov 10, 2010
    Posts:
    429
    Is there a reason you are calling CreateEmptyPrefab everytime? I'd recommend checking for the existing prefab and loading and replacing that. That should maintain the connection.

    Code (CSharp):
    1. string prefabPath = "Assets/Resources/" + charName + ".prefab";
    2. var existingPrefab = AssetDatabase.LoadAssetAtPath(prefabPath, typeof(GameObject));
    3. if (existingPrefab != null)
    4. {
    5.     PrefabUtility.ReplacePrefab(newInstance, existingPrefab);
    6. }
    7. else
    8. {
    9.     PrefabUtility.CreatePrefab(prefabPath, newInstance);
    10. }
     
    SuppleTeets likes this.
  3. SuppleTeets

    SuppleTeets

    Joined:
    Aug 22, 2014
    Posts:
    30
    Thanks for responding! Sorry for the months of delay but I had to table it and get back to it.

    Your proposed solution works! Only with ReplacePrefabOptions.ReplaceNameBased set.

    Here's the updated function for any other lovely people that have this exact need.

    Code (CSharp):
    1.  
    2. static void CreatePrefab()
    3. {
    4.     GameObject[] selObjs = Selection.gameObjects;
    5.     foreach (GameObject selObj in selObjs)
    6.     {
    7.         string charName = selObj.name;
    8.  
    9.         // duplicate
    10.         GameObject newInstance = Instantiate(selObj);
    11.         newInstance.name = charName;
    12.  
    13.         // now replace the prefab
    14.         string prefabPath = "Assets/Prefabs/" + charName + ".prefab";
    15.         var existingPrefab = AssetDatabase.LoadAssetAtPath(prefabPath, typeof(GameObject));
    16.         if (existingPrefab != null)
    17.         {
    18.             PrefabUtility.ReplacePrefab(newInstance, existingPrefab, ReplacePrefabOptions.ReplaceNameBased);
    19.         }
    20.         else
    21.         {
    22.             PrefabUtility.CreatePrefab(prefabPath, newInstance);
    23.         }
    24.  
    25.         // delete dupe
    26.         DestroyImmediate(newInstance);
    27.  
    28.         Debug.Log("Prefab'd " + charName + "! \"" + prefabPath + "\"");
    29.     }
    30. }
    Thanks again!