Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. Dismiss Notice

A script replacing one prefab with another

Discussion in 'Scripting' started by bigpunn71, May 21, 2019.

  1. bigpunn71

    bigpunn71

    Joined:
    Apr 10, 2019
    Posts:
    4
    Is there a updated script for 2019.1.3f1 that can replace one prefab with another in the editor view? Really need a script that can do this to make world building a whole lot easier. I was trying to use this one, but it isn't working. I'll paste the code at the bottom.

    Code (CSharp):
    1. using UnityEngine;
    2. using UnityEditor;
    3. public class ReplaceWithPrefab : EditorWindow
    4. {
    5. [SerializeField] private GameObject prefab;
    6. [MenuItem("Tools/Replace With Prefab")]
    7. static void CreateReplaceWithPrefab()
    8. {
    9. EditorWindow.GetWindow<ReplaceWithPrefab>();
    10. }
    11. private void OnGUI()
    12. {
    13. prefab = (GameObject)EditorGUILayout.ObjectField("Prefab", prefab, typeof(GameObject), false);
    14. if (GUILayout.Button("Replace"))
    15. {
    16. var selection = Selection.gameObjects;
    17. for (var i = selection.Length - 1; i >= 0; --i)
    18. {
    19. var selected = selection;
    20. var prefabType = PrefabUtility.GetPrefabType(prefab);
    21. GameObject newObject;
    22. if (prefabType == PrefabType.Prefab)
    23. {
    24. newObject = (GameObject)PrefabUtility.InstantiatePrefab(prefab);
    25. }
    26. else
    27. {
    28. newObject = Instantiate(prefab);
    29. newObject.name = prefab.name;
    30. }
    31. if (newObject == null)
    32. {
    33. Debug.LogError("Error instantiating prefab");
    34. break;
    35. }
    36. Undo.RegisterCreatedObjectUndo(newObject, "Replace With Prefabs");
    37. newObject.transform.parent = selected.transform.parent;
    38. newObject.transform.localPosition = selected.transform.localPosition;
    39. newObject.transform.localRotation = selected.transform.localRotation;
    40. newObject.transform.localScale = selected.transform.localScale;
    41. newObject.transform.SetSiblingIndex(selected.transform.GetSiblingIndex());
    42. Undo.DestroyObjectImmediate(selected);
    43. }
    44. }
    45. GUI.enabled = false;
    46. EditorGUILayout.LabelField("Selection count: " + Selection.objects.Length);
    47. }
    48. }
     
    Last edited: May 22, 2019
  2. halley

    halley

    Joined:
    Aug 26, 2013
    Posts:
    1,863
    Wrap the code above in code tags to preserve the formatting, please.

    What error(s) are you getting in the console? What behavior are you getting?

    Also, you should be able to find the key change to instantiating prefabs with 2018.3+ with a quick googling around. What have you found?
     
    angrypenguin likes this.
  3. bigpunn71

    bigpunn71

    Joined:
    Apr 10, 2019
    Posts:
    4
    I recently updated my build to the newest one, which resulted in this script not working. I posted an image below with the errors I am getting. Here is the youtube video where I got the code from. The guy in the video demos the script.

    .

    I know nothing about C# or how to go about solving the issue.


    Fantasy Village (Running) - Microsoft Visual Studio .jpg
     
  4. bigpunn71

    bigpunn71

    Joined:
    Apr 10, 2019
    Posts:
    4
    Talked to some of my Engineer buddies, but they aren't familiar with Unity. I have no errors or warnings, but I just can't get it to work like the video above.


    Code (CSharp):
    1. using UnityEngine;
    2. using UnityEditor;
    3. public class ReplaceWithPrefab : EditorWindow
    4. {
    5.     [SerializeField] private GameObject prefab;
    6.     [MenuItem("Tools/Replace With Prefab")]
    7.     static void CreateReplaceWithPrefab()
    8.     {
    9.         EditorWindow.GetWindow<ReplaceWithPrefab>();
    10.     }
    11.     private void OnGUI()
    12.     {
    13.         prefab = (GameObject)EditorGUILayout.ObjectField("Prefab", prefab, typeof(GameObject), false);
    14.         if (GUILayout.Button("Replace"))
    15.         {
    16.             var selection = Selection.gameObjects;
    17.             for (var i = selection.Length - 1; i >= 0; --i)
    18.             {
    19.                 var selected = selection[i];
    20.                 var prefabType = PrefabUtility.GetPrefabAssetType(prefab);
    21.                 GameObject newObject;
    22.                 if (prefabType == PrefabAssetType.Model)
    23.                 {
    24.                     newObject = (GameObject)PrefabUtility.InstantiatePrefab(prefab);
    25.                 }
    26.                 else
    27.                 {
    28.                     newObject = Instantiate(prefab);
    29.                     newObject.name = prefab.name;
    30.                 }
    31.                 if (newObject == null)
    32.                 {
    33.                     Debug.LogError("Error instantiating prefab");
    34.                     break;
    35.                 }
    36.                 Undo.RegisterCreatedObjectUndo(newObject, "Replace With Prefabs");
    37.                 newObject.transform.parent = selected.transform.parent;
    38.                 newObject.transform.localPosition = selected.transform.localPosition;
    39.                 newObject.transform.localRotation = selected.transform.localRotation;
    40.                 newObject.transform.localScale = selected.transform.localScale;
    41.                 newObject.transform.SetSiblingIndex(selected.transform.GetSiblingIndex());
    42.                 Undo.DestroyObjectImmediate(selected);
    43.             }
    44.         }
    45.         GUI.enabled = false;
    46.         EditorGUILayout.LabelField("Selection count: " + Selection.objects.Length);
    47.     }
    48. }
     
  5. thundercat71

    thundercat71

    Joined:
    Sep 13, 2018
    Posts:
    10
    It works fine in 2019, I think it may be the way you are implementing it.

    Here is how to do this.

    Within the unity editor:
    Create a new folder in the Assets folder called Editor
    Now Create a new C# script in that folder and rename it to match the code (class), in this case ReplaceWithPrefab <---- this is your error me thinks
    Next open the script you just made and erase every thing in it.
    Now copy the script from his web page into the empty c# script you made
    Save the script.
    Go back to Unity and look under the Tools menu to run the script.

    Hope that helps.
     
  6. spaz_1

    spaz_1

    Joined:
    Apr 29, 2013
    Posts:
    3
    I've updated his code to work with later versions since some of those functions are obsolete. Also commented so you know what's going on. Hope this helps.

    Code (CSharp):
    1. using UnityEngine;
    2. using UnityEditor;
    3.  
    4. public class ReplaceWithPrefab : EditorWindow
    5. {
    6.     // -- this is the box in the window where you drag your "new" prefab
    7.     [SerializeField] private GameObject prefab;
    8.  
    9.     // -- this creates the menu to open the "Replace With Prefab" window
    10.     [MenuItem("Tools/Replace With Prefab")]
    11.     static void CreateReplaceWithPrefab()
    12.     {
    13.         EditorWindow.GetWindow<ReplaceWithPrefab>();
    14.     }
    15.  
    16.     private void OnGUI()
    17.     {
    18.         // -- get a handle to the prefab you want to replace everything with
    19.         prefab = (GameObject)EditorGUILayout.ObjectField("Prefab", prefab, typeof(GameObject), false);
    20.  
    21.         // -- if you've pressed the "Replace" button...
    22.         if (GUILayout.Button("Replace"))
    23.         {
    24.             // -- get the list of objects you have selected
    25.             var selection = Selection.gameObjects;
    26.  
    27.             // -- get the prefab type (I moved this out of the loop because it makes
    28.             // -- no sense to check it every time)
    29.             var prefabType = PrefabUtility.GetPrefabAssetType(prefab);
    30.  
    31.             // -- loop over all of the selected objects
    32.             for (var i = selection.Length - 1; i >= 0; --i)
    33.             {
    34.                 // -- get the next selected object
    35.                 var selected = selection[i];
    36.                 GameObject newObject;
    37.  
    38.                 // -- if your "prefab" really is a prefab . . .
    39.                 if (prefabType != PrefabAssetType.NotAPrefab)
    40.                 {
    41.                     // -- . . . then this part should always run.
    42.                     // -- If you update the original prefab, the replaced items will
    43.                     // -- update as well.
    44.                     newObject = (GameObject)PrefabUtility.InstantiatePrefab(prefab);
    45.                 }
    46.                 else
    47.                 {
    48.                     // -- if this code is running, you didn't drag a prefab to your window.
    49.                     // -- it will just Instantiate whatever you did drag over.
    50.                     newObject = Instantiate(prefab);
    51.                     newObject.name = prefab.name;
    52.                 }
    53.  
    54.                 // -- if for some reason Unity couldn't perform your request, print an error
    55.                 if (newObject == null)
    56.                 {
    57.                     Debug.LogError("Error instantiating prefab");
    58.                     break;
    59.                 }
    60.  
    61.                 // -- set up "undo" features for the new prefab, like setting up the old transform
    62.                 Undo.RegisterCreatedObjectUndo(newObject, "Replace With Prefabs");
    63.                 newObject.transform.parent = selected.transform.parent;
    64.                 newObject.transform.localPosition = selected.transform.localPosition;
    65.                 newObject.transform.localRotation = selected.transform.localRotation;
    66.                 newObject.transform.localScale = selected.transform.localScale;
    67.                 newObject.transform.SetSiblingIndex(selected.transform.GetSiblingIndex());
    68.                 // -- now delete the old prefab
    69.                 Undo.DestroyObjectImmediate(selected);
    70.             }
    71.         }
    72.  
    73.         // -- prevent the user from editing the window
    74.         GUI.enabled = false;
    75.  
    76.         // -- update how many items you have selected (Note, it only updates when the mouse cursor is above the Replace window)
    77.         EditorGUILayout.LabelField("Selection count: " + Selection.objects.Length);
    78.     }
    79. }
     
  7. spaz_1

    spaz_1

    Joined:
    Apr 29, 2013
    Posts:
    3
    If it's still not working with the suggestions above, let us know specifically what it does or doesn't do.
     
  8. bigpunn71

    bigpunn71

    Joined:
    Apr 10, 2019
    Posts:
    4
    Spaz_1 - Awesome that works and thank you for writing that code out!

    thundercat71 - Thank you for breaking it down on how to set up the script.
     
  9. fherbst

    fherbst

    Joined:
    Jun 24, 2012
    Posts:
    801
    Just a tiny change so this also works for replacing objects that are already inside other prefabs (e.g. inside imported meshes):

    Change
    Code (CSharp):
    1. Undo.DestroyObjectImmediate(selected);
    to
    Code (CSharp):
    1. try {
    2.   Undo.DestroyObjectImmediate(selected);
    3. }
    4. catch {
    5.   selected.SetActive(false);
    6. }
     
    binoman, sivrikaya and thundercat71 like this.
  10. Shadowing

    Shadowing

    Joined:
    Jan 29, 2015
    Posts:
    1,627
  11. Armegalo

    Armegalo

    Joined:
    May 14, 2018
    Posts:
    24
    The update wasn't working

    My 2020 build gave me this warning...

    "Parent of RectTransform is being set with parent property. Consider using the SetParent method instead, with the worldPositionStays argument set to false. This will retain local orientation and scale rather than world orientation and scale, which can prevent common UI scaling issues."

    So I did

    newObject.transform.parent = selected.transform.parent;
    becomes
    newObject.transform.SetParent(selected.transform.parent,false);


    and it worked :D :D
     
  12. Ziplock9000

    Ziplock9000

    Joined:
    Jan 26, 2016
    Posts:
    360
    Can someone link a completed version rather than having to track tiny updates on each post please?
     
    Evayo likes this.
  13. HoweToGaming

    HoweToGaming

    Joined:
    Feb 22, 2021
    Posts:
    1
    Code Update of obsolete code
    var prefabType = PrefabUtility.GetPrefabType(prefab);
    to
    var prefabType = PrefabUtility.GetPrefabAssetType(prefab);
    and
    prefabType == PrefabType.Prefab
    to
    prefabType == PrefabAssetType.Regular

    Code (CSharp):
    1.  
    2. using UnityEngine;
    3. using UnityEditor;
    4.  
    5. public class ReplaceWithPrefab : EditorWindow
    6. {
    7.     [SerializeField] private GameObject prefab;
    8.  
    9.     [MenuItem("Tools/Replace With Prefab")]
    10.     static void CreateReplaceWithPrefab()
    11.     {
    12.         EditorWindow.GetWindow<ReplaceWithPrefab>();
    13.     }
    14.  
    15.     private void OnGUI()
    16.     {
    17.         prefab = (GameObject)EditorGUILayout.ObjectField("Prefab", prefab, typeof(GameObject), false);
    18.  
    19.         if (GUILayout.Button("Replace"))
    20.         {
    21.             var selection = Selection.gameObjects;
    22.  
    23.             for (var i = selection.Length - 1; i >= 0; --i)
    24.             {
    25.                 var selected = selection[i];
    26.                 var prefabType = PrefabUtility.GetPrefabAssetType(prefab);
    27.                 GameObject newObject;
    28.  
    29.                 if (prefabType == PrefabAssetType.Regular)
    30.                 {
    31.                     newObject = (GameObject)PrefabUtility.InstantiatePrefab(prefab);
    32.                 }
    33.                 else
    34.                 {
    35.                     newObject = Instantiate(prefab);
    36.                     newObject.name = prefab.name;
    37.                 }
    38.  
    39.                 if (newObject == null)
    40.                 {
    41.                     Debug.LogError("Error instantiating prefab");
    42.                     break;
    43.                 }
    44.  
    45.                 Undo.RegisterCreatedObjectUndo(newObject, "Replace With Prefabs");
    46.                 newObject.transform.parent = selected.transform.parent;
    47.                 newObject.transform.localPosition = selected.transform.localPosition;
    48.                 newObject.transform.localRotation = selected.transform.localRotation;
    49.                 newObject.transform.localScale = selected.transform.localScale;
    50.                 newObject.transform.SetSiblingIndex(selected.transform.GetSiblingIndex());
    51.                 Undo.DestroyObjectImmediate(selected);
    52.             }
    53.         }
    54.  
    55.         GUI.enabled = false;
    56.         EditorGUILayout.LabelField("Selection count: " + Selection.objects.Length);
    57.     }
    58. }
     
    imitationkrab and shmulik_v like this.
  14. Leniaal

    Leniaal

    Joined:
    Nov 7, 2012
    Posts:
    119
    Edited to support prefab variants:

    Code (CSharp):
    1. using UnityEngine;
    2. using UnityEditor;
    3. public class ReplaceWithPrefab : EditorWindow
    4. {
    5.     [SerializeField] private GameObject prefab;
    6.     [MenuItem("Tools/Replace With Prefab")]
    7.     static void CreateReplaceWithPrefab()
    8.     {
    9.         EditorWindow.GetWindow<ReplaceWithPrefab>();
    10.     }
    11.     private void OnGUI()
    12.     {
    13.         prefab = (GameObject)EditorGUILayout.ObjectField("Prefab", prefab, typeof(GameObject), false);
    14.         if (GUILayout.Button("Replace"))
    15.         {
    16.             var selection = Selection.gameObjects;
    17.             for (var i = selection.Length - 1; i >= 0; --i)
    18.             {
    19.                 var selected = selection[i];
    20.                 var prefabType = PrefabUtility.GetPrefabAssetType(prefab);
    21.                 GameObject newObject;
    22.                 if (prefabType == PrefabAssetType.Regular || prefabType == PrefabAssetType.Variant)
    23.                 {
    24.                     newObject = (GameObject)PrefabUtility.InstantiatePrefab(prefab);
    25.                 }
    26.                 else
    27.                 {
    28.                     newObject = Instantiate(prefab);
    29.                     newObject.name = prefab.name;
    30.                 }
    31.                 if (newObject == null)
    32.                 {
    33.                     Debug.LogError("Error instantiating prefab");
    34.                     break;
    35.                 }
    36.                 Undo.RegisterCreatedObjectUndo(newObject, "Replace With Prefabs");
    37.                 newObject.transform.parent = selected.transform.parent;
    38.                 newObject.transform.localPosition = selected.transform.localPosition;
    39.                 newObject.transform.localRotation = selected.transform.localRotation;
    40.                 newObject.transform.localScale = selected.transform.localScale;
    41.                 newObject.transform.SetSiblingIndex(selected.transform.GetSiblingIndex());
    42.                 Undo.DestroyObjectImmediate(selected);
    43.             }
    44.         }
    45.         GUI.enabled = false;
    46.         EditorGUILayout.LabelField("Selection count: " + Selection.objects.Length);
    47.     }
    48. }
     
    AidenDruid and wedgiebee like this.
  15. brkrzero

    brkrzero

    Joined:
    Jul 25, 2021
    Posts:
    5
    I know this is over a year old, but in the most recent LTS (as of this comment) destroying game objects is apparently deprecated as it throws an error saying that the functionality is not allowed to be used in order to prevent data loss. Furthermore, the PrefabUtility.ReplacePrefab approach is also deprecated (and in this case has also been removed completely) so that's not an option either. Why such basic functionality would be completely removed or disallowed is beyond me, but it's not my decision to make this kind of thing so difficult to do.
     
    Last edited: Sep 6, 2023
  16. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    36,713
    That only means you're destroying the wrong thing. You have written a bug.

    That's beyond you because no functionality has been removed.

    Instead of necro-jacking a thread from 2019, if you have a new question, please make a new post. It's FREE!!

    How to report your problem productively in the Unity3D forums:

    http://plbm.com/?p=220

    This is the bare minimum of information to report:

    - what you want
    - what you tried
    - what you expected to happen
    - what actually happened, log output, variable values, and especially any errors you see
    - links to documentation you used to cross-check your work (CRITICAL!!!)

    The purpose of YOU providing links is to make our job easier, while simultaneously showing us that you actually put effort into the process. If you haven't put effort into finding the documentation, why should we bother putting effort into replying?

    If you post a code snippet, ALWAYS USE CODE TAGS:

    How to use code tags: https://forum.unity.com/threads/using-code-tags-properly.143875/

    - Do not TALK about code without posting it.
    - Do NOT post unformatted code.
    - Do NOT retype code. Use copy/paste properly using code tags.
    - Do NOT post screenshots of code.
    - Do NOT post photographs of code.
    - ONLY post the relevant code, and then refer to it in your discussion.
     
  17. MelvMay

    MelvMay

    Unity Technologies

    Joined:
    May 24, 2013
    Posts:
    10,512
  18. brkrzero

    brkrzero

    Joined:
    Jul 25, 2021
    Posts:
    5
    Well, it sure didn't seem that way considering that I was trying to destroy the intended object when I ran into the problem. But thanks for the heads up.

    I can explain further in a separate discussion if necessary, so I'll update accordingly if I don't find a solution to this. Although as a side note, I'm considering swapping the prefab's animation controllers as an alternative.