How to call a method when a GameObject has been duplicated?

I need to do some stuff on a Component when it’s GameObject got duplicated.
Did anyone find out how to?
This has especially to work in the Editor - with CMD + D or Copy Paste… but is not restricted to it.
I’d favor something generic - but an explicit approach would be a nice start.

Sure, — it would be possible to hook onto the Unity command events like…

if( (e.type == EventType.ValidateCommand)
    &&((e.commandName == "Duplicate") || (e.commandName == "Paste")) )
{
    	PostDuplicateMethod();
}

… but I don’t want to do that - because only one component class would need that special treatment - and I’d really prefer not to go through all GameObjects to check if they have a Component of my Type.

If someone could show me how to hook direct onto the duplication process - that would be awesome!!!

I presume it’s something in UnityEngine.Object Instantiate but - how can I find out if this was called for instances having my component…

At this point I have to go through all instances of my Component on Awake()!!! and check quite expensive if they have been copied… (they hold a wrong reference - nothing anyone else could use)

I would really appreciate any hint

Probably I should explain what I try to achieve -

The Component holds a List of Properties which derive from ScriptableObject. And these have to be cloned too when the Component gets duplicated.

[ExecuteInEditMode]
public class DuplicateCatcher : MonoBehaviour {
[SerializeField] int instanceID = 0;
void Awake(){
if (instanceID != GetInstanceID()){
if (instanceID == 0){
instanceID = GetInstanceID();
}
else {
instanceID = GetInstanceID();
if (instanceID < 0){
Debug.Log(“DUPLICATE/COPY”);
}
}
}
}
}

Bit of an ancient thread but I stumbled across it and thought I’d add my findings. Awake sounded strange to me since it requires processing during game time rather than in the editor so this is what I ended up doing. First give your script the ExecuteInEditMode tag then for your update function and before your other code:

    void Update()
    {
#if(UNITY_EDITOR)
        if(!Application.isPlaying)//if in the editor
        {
            if(instanceID != gameObject.GetInstanceID())//if the instance ID doesnt match then this was copied!
                Debug.Log("Called: " + gameObject + ", " + transform.parent);
            else if(instanceID == 0)
                instanceID = gameObject.GetInstanceID();//this object wasnt copied but set its ID to check for further copies

            return;//prevent any actual code from running
        }
#endif
    }

This currently just prints when the object is copied but this is where you could place your logic to update the references.

Sounds like you could use an EditorWindow. You can duplicate your stuff, then call whatever needs to be called afterwards, even based on type or name if you feel like coding that much.

Here’s a little something to get you started:

using UnityEngine;
using UnityEditor;
using System.Collections;

public class DuplicatorWindow : EditorWindow {

	[MenuItem ("Custom/Duplicator")]
	public static void Init(){
		DuplicatorWindow window = EditorWindow.GetWindow<DuplicatorWindow >();
		window.Show();
	}
	
	GameObject selectedObject = null;
	
	void OnGUI(){
		selectedObject = Selection.gameObjects[0];
		
		if(selectedObject == null)
			EditorGUILayout.LabelField("No Objects selected.");
		else{
			EditorGUILayout.LabelField(selectedObject.name);
			if(GUILayout.Button("Duplicate")){
				DuplicateGameObject();
				PostDuplicateMethod();
			}
			
		}
		Repaint();
	}
	
	private void DuplicateGameObject(){
		/*Do all duplication here.*/ 
	}
	
	private void PostDuplicateMethod(){
		/*Whatever needs to be done after duplication*/
	}
}

N.B. This code needs to be placed inside the Assets/Editor folder. To access it, there will be a new menu item, Custom, in your menubar ( the one with File, Edit etc).

Edit:
While I think the EditorWindow approach is better, because there is one button that does whatever needs be done, what you’re asking can also be done in a custom inspector:

[CustomEditor(typeof(MyComponent))]
public class Duplicator : Editor {
	
	void OnSceneGUI(){
		Event e = Event.current;
		
		if(e != null && e.type == EventType.ValidateCommand && (e.commandName =="Paste" || e.commandName =="Duplicate" )){
			PostDuplicateMethod();
		}		
	}
private void PostDuplicateMethod(){
	Debug.Log("Post Duplication");
	/*Whatever needs to be done after duplication*/
}
}

That requires the Scene view to have keyboard control, so extra care must be taken in that regard. (E.g. right.clicking on the scene view with an asset selected, or selecting a GameObject from the scene view.) If you need to hook into the event from where ever, you’ll need to code your own Keyboard hook, much like this one Google Code Archive - Long-term storage for Google Code Project Hosting. .

You’ll need a scripted solution to react to any Object.Instantiate, I recommend using Awake(). Unity Editor can’t help you there… unless you plan to have the game played from the Editor.

My simple to implement solution was to check if the filename contains " 1" and then perform some action.

[CustomEditor(typeof(Some_Data))]
		public class Some_Data_Editor : Editor
		{
			private void Awake()
			{
				Some_Data data = this.target as Some_Data;
				var assetPath = AssetDatabase.GetAssetPath(data.GetInstanceID());
				var fileName = System.IO.Path.GetFileNameWithoutExtension(assetPath);

				if (fileName.Contains(" 1"))
				{
					AssetDatabase.RenameAsset(assetPath, "New Data");
					data.Uid = System.Guid.NewGuid().ToString();
				}
			}
//Rest of editor code here