I could use some help getting the Duplicate event in editor.
I’ve tried catching ‘Paste’ and ‘Duplicate’ but they do not get called when I look for them.
Additionally, I’ve tried to put an event handler in the EditorApplication.hierarchyWindowItemOnGUI to see if the commands are caught inside that but those commands do not appear.
Catching duplicate events in Unity is one of the single most frustrating things I’ve dealt with in Unity. It feels like handling this was an afterthought…
Hi @LW! Can you provide some more information? The following example works for me:
using UnityEditor;
using UnityEngine;
[InitializeOnLoad]
public class Test {
static Test () {
EditorApplication.hierarchyWindowItemOnGUI += delegate(int instanceID, Rect selectionRect)
{
if (Event.current.commandName == "Duplicate")
{
Debug.Log ("Duplicated");
}
};
}
}
Facing the same issue, and not really liking any of the other answers, particularly since the context menu does not work with them. Here is a simple workaround I came up with. I’ve only tested to confirm it detects duplicates, there my be other things that cause a detection I’m not aware of yet.
[ExecuteInEditMode]
public class DuplicatableObject : MonoBehaviour {
public int instanceID=0; //this value is duplicated with the gameobject
void Awake()
{
if (instanceID != 0)
{
Debug.Log("Duplication Detected of " + gameObject.name + " oldID:" + instanceID + " newID: " + gameObject.GetInstanceID());
}
instanceID =gameObject.GetInstanceID();
}
}
I don’t know if this will help but if you try
if (Event.current.commandName == “Duplicate”
&& Event.current.type == EventType.ExecuteCommand)
{
Debug.Log(Selection.activeTransform.name);
Event.current.Use();
}
only check the execute command
calling Event.current.Use();
and checking the Selection.activeTransform instead of the activeGameObject
you will cancel the duplicate and the Selection.activeTransform will give you the selected object.
The major difference I notice is the activeTransform and the Use()
Regards,
Bubba
I have submitted a bug for this. Thank you @Bunny83 and @Adam-Metchley for helping dig around in the editor with me. I can confirm that Event.current.commandName is empty when using the Context menu.
Old topic, but still relevant. Glurth’s solution is on the right track, but I believe there’s a more complete solution.
Duplicate Trap
Exactly like Glurth did. We use the InstanceID to detect cloned instances.
public static class DuplicateTrap
{
public static bool Trigger(GameObject gameObject)
{
var cache = gameObject.GetComponent<CachedInstanceId>();
if (cache != null)
{
if (cache.InstanceId == gameObject.GetInstanceID())
{
// same component reenabled
return false;
}
else
{
// Duplicate!
cache.InstanceId = gameObject.GetInstanceID();
return true;
}
}
else
{
// new object, no duplication
cache = gameObject.AddComponent<CachedInstanceId>();
cache.hideFlags = HideFlags.HideAndDontSave | HideFlags.HideInInspector;
cache.InstanceId = gameObject.GetInstanceID();
return false;
}
}
private class CachedInstanceId : MonoBehaviour
{
public int InstanceId;
}
}
Usage Example
Generating a GUID for a gameobject that stays unique even after duplication.
[ExecuteInEditMode]
public class MyScript : MonoBehaviour
{
public string GUID;
#if UNITY_EDITOR
private void OnEnable()
{
// Optional: Used to ignore duplications on objects that are playing
if (Application.IsPlaying(this))
return;
if (string.IsNullOrEmpty(GUID))
{
// new object, new guid
GUID = Guid.NewGuid().ToString();
}
if (DuplicateTrap.Trigger(gameObject))
{
// Duplicate! Generate new ID
GUID = Guid.NewGuid().ToString();
}
}
#endif
}
Limitations
This use case example will not detect Prefab asset duplication since their OnEnable method is not called. (NB: Opening a prefab and duplicating gameobjects inside is OK, just duplicating the prefab asset root in the Project window). If this limitation is a problem for you, I suggesting saving the asset GUID string on a component using an AssetPostProcessor.
As of writing, there’s a known bug in Unity that makes the DuplicateTrap.CachedInstanceId component visible in the inspector (ignoring the hideflags). This issue is harmless and purely visual, but if you want to avoid it, you can add this to the class