I add an empty GameObject then my custom component. In the component several instances of other custom classes can be stored, created, deleted. Everything is serialized, properly saved and loaded with the scene.
However when I duplicate the Game Object manually in the editor there is a problem: the GO is new but the component inside is referencing to stuff from the original GO. What I’d like to have is unique instances of everything inside the GO.
What is the proper way of handling this?
The actual system is somewhat complicated but can be boiled down to the following example:
I have GameObject “Pot” and I add component “Plant” to it. That component can create and store instances of the custom class “Berry” (public, serialized, extends C#'s root class). Berry creation is not possible through the inspector.
If I duplicate “Pot” using the editor context menu then I end up with “Pot(2)” containing “Plant(2)” while “Berry” is shared between the two plants. My goal is to have “Berry(2)”, a unique copy of the original.
EDIT: Added example.
EDIT2: Made it more apparent that duplication is done by the Unity Editor, not from script.
My example was wrong above, here is how things seem to be working:
If ‘Berry’ extends c#'s root class (i.e. extends nothing) then it does get duplicated properly.
If ‘Berry’ extends ScriptableObject then the instance is shared. In other words the references are duplicated not the instance they are pointing to. This behavior is actually a feature as explained in this excellent post. (Although I’m still somewhat confused how serialization and ctrl+d relate exactly.)
For other reasons I needed ‘Berry’ to be a ScriptableObject so I had to detect when a GO got duplicated from the editor UI and do deep copies and reference fixes throughout the cloned component:
The component in question has [ExecuteInEditMode] so it’s Update() is executed every time the scene changes, such as on duplication.
I store the result of GetInstanceID() in a separate variable, initialized on creation of the component and on Awake() to handle scene loads. In Update() the cached value is compared to the current GetInstanceID() and if they differ then we are a duplicate.
The UNITY_EDITOR define ensures that this comparison is only done while in the editor.
While performing the deep copies on the contents of the component I build a remapping dictionary containing oldInstance - newInstance pairs. I use that to restore inter-component referencing. (So nothing keeps pointing to the original component’s contents but rather to the similar part of the newly created component with the now unique instances.)