- Home /
Unity Duplicate Event
Hi Everyone,
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...
Any help is appreciated.
Answer by Adam-Mechtley · Nov 20, 2016 at 09:00 PM
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");
}
};
}
}
protected static void OnHierarchyWindowItemOnGUI(int n, Rect rt)
{
Debug.Log("OnHierarchyWindowItemOnGUI()");
if ("Duplicate" == Event.current.commandName)
{
Debug.Log("Copy was made... " + UnityEditor.Selection.activeGameObject);
}
}
Prints out: OnHierarchyWindowItemOnGUI()
but then nothing. So, still no duplicate getting invoked. Running 5.4.1f1 Personal
Where does this method exist and how is it being registered?
I tried this function in a $$anonymous$$onoBehaviour that is attached to the object being duplicated as well as a custom EditorWindow
.
Can you provide some example code where you define this method and register it as an event handler? Can you verify that the script is in an Editor compilation pass (i.e. in an Editor folder)?
Sure thing! I'm at a loss....
The class is located in a folder entitled, 'editor' (the 'e' is not capitalized).
[InitializeOnLoad]
public class ExampleEditorWindow : EditorWindow
{
static ExampleEditorWindow()
{
Debug.Log("static ExampleEditorWindow::ctor()");
EditorApplication.hierarchyWindowItemOnGUI += OnHierarchyWindowItemOnGUI;
}
protected static void OnHierarchyWindowItemOnGUI(int n, Rect rt)
{
string sz = Event.current.commandName;
switch (sz)
{
case null: Debug.Log("commandName is null"); break;
case "": Debug.Log("commandName is empty; instanceId is " + n + " which is " + EditorUtility.InstanceIDToObject(n)); break;
default: Debug.Log("Command name: " + sz); break;
}
if ("Duplicate" == Event.current.commandName)
{
Debug.Log("Copy was made... " + Selection.activeGameObject);
}
}
}
Thanks for the help on this!
Output:
The instance id 'n' and the name of every GameObject
in the hierarchy... and something that doesn't have a name, only an instance id.
Interesting topic ^^. I just had a look myself. I used this script:
using UnityEditor;
using UnityEngine;
[InitializeOnLoad]
public class Test
{
static Test
{
EditorApplication.hierarchyWindowItemOnGUI += OnHierarchyWindowItemGUI;
}
static void OnHierarchyWindowItemGUI(int instanceID, Rect selectionRect)
{
// ignore items which are not selected
if (Selection.activeInstanceID != instanceID)
return;
Event e = Event.current;
if (e.type == EventType.ValidateCommand || e.type == EventType.ExecuteCommand)
{
var o = EditorUtility.InstanceIDToObject(instanceID) as GameObject;
if (o != null)
Debug.Log("Event: " + e.type + " command: " + e.commandName + " item: " + o.name);
}
}
}
Here are my results:
executing copy / paste / rename doesn't cause any command to be executed.
only "duplicate" and "delete" are catched.
The commands are only send when you either press
CTRL+D
/del
or by using the corresponding command from the Edit menuNote: strangely the commands are not sent when you use the context menu.
I'm currently using Unity 5.3.6f1 on Windows10 x64. $$anonymous$$aybe it depends on your operating system. I guess the behaviour is different on $$anonymous$$ac or Linux.
@Bunny83 Would you $$anonymous$$d submitting a bug report on this, please?
Answer by Glurth · Nov 25, 2016 at 05:37 PM
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();
}
}
[ExecuteInEdit$$anonymous$$ode] I just put that at the top, and it worked fine in the editor, without hitting play. (ans updated) Or perhaps I misunderstand, is that option not possible in your situation?
Yes, @Glurth, in my previous reply I stated, "unless I execute in edit mode", but that is not an option for me.
@LW, @Glurth I can't test it right now, but you could try to ins$$anonymous$$d reassign your cached instance id inside ISerializationCallbackReceiver.OnAfterDeserialize (), ins$$anonymous$$d of inside of inside Awake (), and it shouldn't require ExecuteInEdit$$anonymous$$ode.
(That said, this callback will also fire whenever an instance of a prefab is inserted in a scene, whether you use ExecuteInEdit$$anonymous$$ode/Awake or ISerializationCallbackReceiver, so it may not work without some additional smarts)
To add onto this answer, when you restart unity the id's change and awake is executed. It's a smart move to disable this code when quiting unity so it does not change things you do not want it to change. In my case i cleared a list on duplicate, which was fired hundreds of times when restarting unity so it cleared all items from a list i actually wanted to keep.
Answer by BubbaRichard · Nov 24, 2016 at 04:24 AM
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(); } 1) only check the execute command 2) calling Event.current.Use(); 3) 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
No, it's not. Please take a look at the site navigation guide that is mentioned in the side panel on the right. About half way down you can find a "tutorial" how to format code properly.
There's even a live-preview below the editing area where you can see it's not formatted. In short a code block need to be indented 4 spaces on each line and needs an empty line before and after the code block. This can be achieved by simply selecting the whole code and pressing the "101/010" button which will ensure those properties.
Answer by LW · Nov 24, 2016 at 07:16 PM
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.
I managed to reproduce your issue in a Editor/$$anonymous$$onoBehaviour. I believed I fixed it by adding [@ExecuteInEdit$$anonymous$$ode()] to both. (Tried a number of things) All other code was as I mentioned above.
Regards, Freddie Richard
@BubbaRichard thank you for the heads-up! Unfortunately, that workaround has other 'costs' that I'm not certain are good for the project. The fix isn't available to us I believe it has to be fixed internally. But I appreciate the insight!
Thanks@LW! I can see 854480 in the bug tracker, which looks like it's probably your case
Answer by Ng0ns · Jan 02, 2020 at 10:24 PM
I needed to generate new GUID when object was duplicated (it already does so if dragged in as new). So in the GUID component I did this.
void OnValidate()
{
Event e = Event.current;
if (e != null)
{
if (e.type == EventType.ExecuteCommand && e.commandName == "Duplicate")
{
GenerateGUID();
}
}
}
I need this for the same reason as you. The solution still seems very hacky (not your fault). There should be a OnDuplicate event exposed.
Also, I had to swap EventType.ExecuteCommand for EventType.Used for it to work from the Edit menu and CTRL-D. Unity 2020.2.7f1.
void OnValidate()
{
Event e = Event.current;
if (e?.type == EventType.Used && e.commandName == "Duplicate")
{
id = Guid.NewGuid();
}
}