Search Unity

  1. If you have experience with import & exporting custom (.unitypackage) packages, please help complete a survey (open until May 15, 2024).
    Dismiss Notice
  2. Unity 6 Preview is now available. To find out what's new, have a look at our Unity 6 Preview blog post.
    Dismiss Notice

Fixing the Duplicate command that duplicates at bottom of hierarchy

Discussion in 'Editor & General Support' started by Tortuap, Sep 26, 2016.

  1. Tortuap

    Tortuap

    Joined:
    Dec 4, 2013
    Posts:
    137
    Hi fellow creators.

    As you probably know, when duplicating a game object, duplicated objects goes to bottom of hierarchy.
    Which is so counter intuitive and counter productive.

    Here is a small replacement of Ctrl+D, (with a custom Shift+D) that does exactly the same but in addition place the duplicated objects below it's source, in hierarchy.

    Copy and paste this code in a new file in your project :

    Code (CSharp):
    1.  
    2. public static class EditorDuplicateCommand
    3. {
    4.     [MenuItem ( "Edit/Duplicate #d", false, 0 )]
    5.     static void DuplicateSelection ()
    6.     {
    7.         List<GameObject> newSelection = new List<GameObject> ();
    8.         for ( int ui = 0; ui < Selection.gameObjects.Length; ui++ )
    9.         {
    10.             GameObject go = Selection.gameObjects[ui];
    11.             int siblingIndex = go.transform.GetSiblingIndex ();
    12.             GameObject newGo = GameObject.Instantiate ( go );
    13.             newGo.transform.parent = go.transform.parent;
    14.             newGo.transform.position = go.transform.position;
    15.             newGo.transform.SetSiblingIndex ( siblingIndex + 1 );
    16.             Undo.RegisterCreatedObjectUndo ( newGo, "Duplicate" );
    17.             newSelection.Add ( newGo );
    18.         }
    19.         Selection.objects = newSelection.ToArray ();
    20.     }
    21. }
    22.  

    Note that you can also vote to make this "feature" goes into Unity : https://feedback.unity3d.com/suggestions/create-goes-to-top-duplicate-goes-to-bottom-of-hierarchy
     
    DavidLe360 likes this.
  2. Beef-Tooth

    Beef-Tooth

    Joined:
    Nov 27, 2012
    Posts:
    23
    This would be so amazing. Has boggled my mind for years how counter productive it is currently. I tried the script but I get a bunch of errors? For example, can't find MenuItem.
     
  3. haywirephoenix

    haywirephoenix

    Joined:
    May 17, 2017
    Posts:
    109
    Below is the full working script. You have to import the namespaces for the errors.
    I've also added a new line:

    Code (CSharp):
    1. newGo.name = go.name;
    This is my personal preference of removing the " (Clone)" addition to the name.

    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4. using UnityEditor;
    5.  
    6. public static class EditorDuplicateCommand
    7. {
    8.     [MenuItem ( "Edit/Duplicate #d", false, 0 )]
    9.     static void DuplicateSelection ()
    10.     {
    11.         List<GameObject> newSelection = new List<GameObject> ();
    12.         for ( int ui = 0; ui < Selection.gameObjects.Length; ui++ )
    13.         {
    14.             GameObject go = Selection.gameObjects[ui];
    15.             int siblingIndex = go.transform.GetSiblingIndex ();
    16.             GameObject newGo = GameObject.Instantiate ( go );
    17.             newGo.transform.parent = go.transform.parent;
    18.             newGo.transform.position = go.transform.position;
    19.             newGo.transform.SetSiblingIndex ( siblingIndex + 1 );
    20.             Undo.RegisterCreatedObjectUndo ( newGo, "Duplicate" );
    21.             newGo.name = go.name;
    22.             newSelection.Add ( newGo );
    23.         }
    24.         Selection.objects = newSelection.ToArray ();
    25.     }
    26. }
    27.  
     
    jniac likes this.
  4. r_chevallier

    r_chevallier

    Joined:
    Apr 20, 2014
    Posts:
    31
    Hello,

    This is a almost a solution to a very annoying problem in Unity. The only issue I have with it is that it breaks instances of prefabs and turns them into singular game objects.

    Can you make it so it duplicates instances without breaking the prefab connection.

    Thanks,
    Raymond
     
  5. snoopbaron

    snoopbaron

    Joined:
    Mar 21, 2009
    Posts:
    88
    I modified the code so that it no longer breaks prefab connections.

    It will now properly duplicate objects, prefab instances, and prefabs.

    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4. using UnityEditor;
    5.  
    6. public static class EditorDuplicateCommand {
    7.   // Using &d (alt+d) instead of #d (ctrl+d) because typing capital D was triggering this
    8.   [MenuItem("Edit/Duplicate &d", false, 0)]
    9.   static void DuplicateSelection () {
    10.     var newSelection = new List<GameObject>();
    11.     for (int ui = 0; ui < Selection.gameObjects.Length; ui++) {
    12.         var go = Selection.gameObjects[ui];
    13.         int siblingIndex = go.transform.GetSiblingIndex();
    14.         var newGo = SmartInstantiate(go);
    15.         newGo.transform.parent = go.transform.parent;
    16.         newGo.transform.position = go.transform.position;
    17.         newGo.transform.SetSiblingIndex(siblingIndex + 1);
    18.         Undo.RegisterCreatedObjectUndo(newGo, "Duplicate");
    19.         newGo.name = go.name;
    20.         newSelection.Add(newGo);
    21.       }
    22.     Selection.objects = newSelection.ToArray();
    23.   }
    24.  
    25.   private static GameObject SmartInstantiate(GameObject go) {
    26.     var prefabType = PrefabUtility.GetPrefabType(go);
    27.  
    28.     if (prefabType == PrefabType.PrefabInstance) {
    29.       var prefab = PrefabUtility.GetPrefabParent(go) as GameObject;
    30.       var newGo = (GameObject) PrefabUtility.InstantiatePrefab(prefab);
    31.       var mods = PrefabUtility.GetPropertyModifications(go);
    32.       PrefabUtility.SetPropertyModifications(newGo, mods);
    33.       return newGo;
    34.     }
    35.  
    36.     if (prefabType == PrefabType.Prefab) {
    37.       return (GameObject)PrefabUtility.InstantiatePrefab(go);
    38.     }
    39.  
    40.     return GameObject.Instantiate(go) as GameObject;
    41.   }
    42. }
     
    Last edited: Mar 19, 2019
    cdu051, jniac, frogskin and 1 other person like this.
  6. Rodolfo-Rubens

    Rodolfo-Rubens

    Joined:
    Nov 17, 2012
    Posts:
    1,197
    Oh man, please fix this, I'm currently working on a project that has a lot of objects, like a lot, and I need to duplicate some and keep them below the original but they get added at the end. It is very, very annoying!

    Sorry for the necro.
     
  7. frogskin

    frogskin

    Joined:
    Sep 27, 2017
    Posts:
    2
    Hey, this is really good and saved my life
    I rewrite legacy functions and make some optimization on Asset Duplicate so it duplicated with increasing ID

    Note: I use Unity Shortcut Manager to solve conflict
    And I write a tutorial in my blog, hope it helps

    Code (CSharp):
    1.  
    2. using System.Collections;
    3. using System.Collections.Generic;
    4. using UnityEngine;
    5. using UnityEditor;
    6.  
    7. public static class EditorDuplicateCommand
    8. {
    9.     [MenuItem("Edit/Smart Duplicate %d", false, 0)]
    10.     private static void DuplicateSelection()
    11.     {
    12.         var newSelection = new List<Object>();
    13.         if (Selection.gameObjects.Length > 0)
    14.         {
    15.             for (int ui = 0; ui < Selection.gameObjects.Length; ui++)
    16.             {
    17.                 var go = Selection.gameObjects[ui];
    18.                 int siblingIndex = go.transform.GetSiblingIndex();
    19.                 var newGo = SmartInstantiate(go);
    20.                 newGo.transform.parent = go.transform.parent;
    21.                 newGo.transform.position = go.transform.position;
    22.                 newGo.transform.SetSiblingIndex(siblingIndex + 1);
    23.                 newGo.name = go.name;
    24.                 newSelection.Add(newGo);
    25.             }
    26.         }
    27.         else
    28.         {
    29.             for (int ui = 0; ui < Selection.objects.Length; ui++)
    30.             {
    31.                 var go = Selection.objects[ui];
    32.                 var newGo = DuplicateAsset(go);
    33.                 newSelection.Add(newGo);
    34.             }
    35.         }
    36.         Selection.objects = newSelection.ToArray();
    37.     }
    38.  
    39.     private static GameObject SmartInstantiate(GameObject go)
    40.     {
    41.         if (PrefabUtility.GetPrefabInstanceStatus(go) == PrefabInstanceStatus.Connected)
    42.         {
    43.             var prefab = PrefabUtility.GetCorrespondingObjectFromSource(go) as GameObject;
    44.             var newGo = (GameObject)PrefabUtility.InstantiatePrefab(prefab);
    45.             var mods = PrefabUtility.GetPropertyModifications(go);
    46.             PrefabUtility.SetPropertyModifications(newGo, mods);
    47.             return newGo;
    48.         }
    49.  
    50.         if (PrefabUtility.GetPrefabAssetType(go) != PrefabAssetType.NotAPrefab)
    51.         {
    52.             return DuplicateAsset(go) as GameObject;
    53.         }
    54.  
    55.         return GameObject.Instantiate(go) as GameObject;
    56.     }
    57.  
    58.     private static Object DuplicateAsset(Object targetAsset)
    59.     {
    60.         int index = 1;
    61.         while (AssetDatabase.LoadAssetAtPath<Object>(AssetDatabase.GetAssetPath(targetAsset).Replace(".", " " + index + ".")) != null)
    62.         {
    63.             index++;
    64.             if (index > 100)
    65.             {
    66.                 Debug.LogError("Massive Asset Duplicate Detect");
    67.             }
    68.         }
    69.         AssetDatabase.CopyAsset(AssetDatabase.GetAssetPath(targetAsset), AssetDatabase.GetAssetPath(targetAsset).Replace(".", " " + index + "."));
    70.         return AssetDatabase.LoadAssetAtPath<Object>(AssetDatabase.GetAssetPath(targetAsset).Replace(".", " " + index + "."));
    71.     }
    72. }
    73.  
     
    Last edited: Apr 13, 2021
    _geo__ likes this.
  8. _geo__

    _geo__

    Joined:
    Feb 26, 2014
    Posts:
    1,360
    I have added some small fixes for duplicating RectTransforms (scaling and parenting):
    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4. using UnityEditor;
    5. public static class EditorDuplicateCommand
    6. {
    7.     [MenuItem("Edit/Smart Duplicate &d", false, 0)]
    8.     private static void DuplicateSelection()
    9.     {
    10.         var newSelection = new List<Object>();
    11.         if (Selection.gameObjects.Length > 0)
    12.         {
    13.             for (int ui = 0; ui < Selection.gameObjects.Length; ui++)
    14.             {
    15.                 var go = Selection.gameObjects[ui];
    16.                 int siblingIndex = go.transform.GetSiblingIndex();
    17.                 var newGo = SmartInstantiate(go);
    18.                 if(newGo.transform is RectTransform)
    19.                 {
    20.                     newGo.transform.SetParent(go.transform.parent);
    21.                 }
    22.                 else
    23.                 {
    24.                     newGo.transform.parent = go.transform.parent;
    25.                 }
    26.                 newGo.transform.position = go.transform.position;
    27.                 newGo.transform.SetSiblingIndex(siblingIndex + 1);
    28.                 newGo.transform.localScale = go.transform.localScale;
    29.                 newGo.name = go.name;
    30.                 newSelection.Add(newGo);
    31.             }
    32.         }
    33.         else
    34.         {
    35.             for (int ui = 0; ui < Selection.objects.Length; ui++)
    36.             {
    37.                 var go = Selection.objects[ui];
    38.                 var newGo = DuplicateAsset(go);
    39.                 newSelection.Add(newGo);
    40.             }
    41.         }
    42.         Selection.objects = newSelection.ToArray();
    43.     }
    44.     private static GameObject SmartInstantiate(GameObject go)
    45.     {
    46.         if (PrefabUtility.GetPrefabInstanceStatus(go) == PrefabInstanceStatus.Connected)
    47.         {
    48.             var prefab = PrefabUtility.GetCorrespondingObjectFromSource(go) as GameObject;
    49.             var newGo = (GameObject)PrefabUtility.InstantiatePrefab(prefab);
    50.             var mods = PrefabUtility.GetPropertyModifications(go);
    51.             PrefabUtility.SetPropertyModifications(newGo, mods);
    52.             return newGo;
    53.         }
    54.         if (PrefabUtility.GetPrefabAssetType(go) != PrefabAssetType.NotAPrefab)
    55.         {
    56.             return DuplicateAsset(go) as GameObject;
    57.         }
    58.         return GameObject.Instantiate(go) as GameObject;
    59.     }
    60.     private static Object DuplicateAsset(Object targetAsset)
    61.     {
    62.         int index = 1;
    63.         while (AssetDatabase.LoadAssetAtPath<Object>(AssetDatabase.GetAssetPath(targetAsset).Replace(".", " " + index + ".")) != null)
    64.         {
    65.             index++;
    66.             if (index > 100)
    67.             {
    68.                 Debug.LogError("Massive Asset Duplicate Detect");
    69.             }
    70.         }
    71.         AssetDatabase.CopyAsset(AssetDatabase.GetAssetPath(targetAsset), AssetDatabase.GetAssetPath(targetAsset).Replace(".", " " + index + "."));
    72.         return AssetDatabase.LoadAssetAtPath<Object>(AssetDatabase.GetAssetPath(targetAsset).Replace(".", " " + index + "."));
    73.     }
    74. }
     
    jniac likes this.
  9. SnaiperoG

    SnaiperoG

    Joined:
    Apr 6, 2015
    Posts:
    66
    Added Undo operation for Ctrl+Z working and changed shortcut to Ctrl + Shift + D, to available both options
    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4. using UnityEditor;
    5. public static class EditorDuplicateCommand
    6. {
    7.     [MenuItem("Edit/Smart Duplicate %#d", false, 0)]
    8.     private static void DuplicateSelection()
    9.     {
    10.         var newSelection = new List<Object>();
    11.         if (Selection.gameObjects.Length > 0)
    12.         {
    13.             for (int ui = 0; ui < Selection.gameObjects.Length; ui++)
    14.             {
    15.                 var go = Selection.gameObjects[ui];
    16.                 int siblingIndex = go.transform.GetSiblingIndex();
    17.                 var newGo = SmartInstantiate(go);
    18.                 if (newGo.transform is RectTransform)
    19.                 {
    20.                     newGo.transform.SetParent(go.transform.parent);
    21.                 }
    22.                 else
    23.                 {
    24.                     newGo.transform.parent = go.transform.parent;
    25.                 }
    26.                 newGo.transform.position = go.transform.position;
    27.                 newGo.transform.SetSiblingIndex(siblingIndex + 1);
    28.                 newGo.transform.localScale = go.transform.localScale;
    29.                 newGo.name = go.name;
    30.                 newSelection.Add(newGo);
    31.                 Undo.RegisterCreatedObjectUndo(newGo, $"Undo instantiate {newGo.name}");
    32.             }
    33.         }
    34.         else
    35.         {
    36.             for (int ui = 0; ui < Selection.objects.Length; ui++)
    37.             {
    38.                 var go = Selection.objects[ui];
    39.                 var newGo = DuplicateAsset(go);
    40.                 newSelection.Add(newGo);
    41.                 Undo.RegisterCreatedObjectUndo(newGo, $"Undo instantiate {newGo.name}");
    42.             }
    43.         }
    44.         Selection.objects = newSelection.ToArray();
    45.     }
    46.     private static GameObject SmartInstantiate(GameObject go)
    47.     {
    48.         if (PrefabUtility.GetPrefabInstanceStatus(go) == PrefabInstanceStatus.Connected)
    49.         {
    50.             var prefab = PrefabUtility.GetCorrespondingObjectFromSource(go) as GameObject;
    51.             var newGo = (GameObject)PrefabUtility.InstantiatePrefab(prefab);
    52.             var mods = PrefabUtility.GetPropertyModifications(go);
    53.             PrefabUtility.SetPropertyModifications(newGo, mods);
    54.             return newGo;
    55.         }
    56.         if (PrefabUtility.GetPrefabAssetType(go) != PrefabAssetType.NotAPrefab)
    57.         {
    58.             return DuplicateAsset(go) as GameObject;
    59.         }
    60.         return GameObject.Instantiate(go) as GameObject;
    61.     }
    62.     private static Object DuplicateAsset(Object targetAsset)
    63.     {
    64.         int index = 1;
    65.         while (AssetDatabase.LoadAssetAtPath<Object>(AssetDatabase.GetAssetPath(targetAsset).Replace(".", " " + index + ".")) != null)
    66.         {
    67.             index++;
    68.             if (index > 100)
    69.             {
    70.                 Debug.LogError("Massive Asset Duplicate Detect");
    71.             }
    72.         }
    73.         AssetDatabase.CopyAsset(AssetDatabase.GetAssetPath(targetAsset), AssetDatabase.GetAssetPath(targetAsset).Replace(".", " " + index + "."));
    74.         return AssetDatabase.LoadAssetAtPath<Object>(AssetDatabase.GetAssetPath(targetAsset).Replace(".", " " + index + "."));
    75.     }
    76. }
     
    Yany likes this.
  10. daiki-eviltwo

    daiki-eviltwo

    Joined:
    Dec 17, 2013
    Posts:
    1