Editor Wizard: Copy Existing Components to Another GameObject

Since the editor does not have a way to copy the child components of a game object and apply that copy to another game object, I am trying to make a Editor Wizard that will do this.

My wizard is able to copy the components presently, but cannot copy the values of the source.

Any ideas?

Here's what I have so far (below). The commented-out code doesn't work (so, for example, I know that CloneComponent will just make clones in the source - makes a mess so don't use - it will duplicate your transform components, for example - not good!). I left the comments in so folks realize that I've tried the obvious code from the reference and so we don't "reinvent the broken wheel" so to speak.

using UnityEngine;
using UnityEditor;
using System.Collections;
// CopyComponents - by Michael L. Croswell for Colorado Game Coders, LLC
// March 2010

public class CopyComponents : ScriptableWizard
{   
    public bool copyValues = true;  
    public GameObject fromObject;
    public GameObject toObject;
    
    [MenuItem ("Custom/Copy Components")]
    static void CreateWizard ()
    {
        ScriptableWizard.DisplayWizard("Copy Components", typeof(CopyComponents), "Copy");  
    }
    
    void OnWizardCreate ()
    {
        //foreach (GameObject go in fromObject.GetFiltered(typeof(GameObject), SelectionMode.TopLevel))
        Component[] fromComps = fromObject.GetComponents(typeof(Component));
        Component[] toComps = toObject.GetComponents(typeof(Component));
        string msg = "";
        msg += "FromObject total components count is " + fromComps.Length;
        msg += "

ToObject total components count is " + toComps.Length;
/// Blows up Unity iPhone: EditorUtility.CopySerialized(fromObject, toObject); // Source to Destination
/// return;
int i = 0;
for (i=0; i < fromComps.Length; i++)
{
string t1 = fromComps*.GetType().Name;*
string t2 = “”;
msg += "
#" + i + " is type " + t1;

if (i < toComps.Length)
t2 = toComps*.GetType().Name;*
if (t2 != t1)
{
//if (copyValues)
// toObject.AddComponent(EditorUtility.CloneComponent(fromComps*));*
//else
toObject.AddComponent(fromComps*.GetType());*
toComps = toObject.GetComponents(typeof(Component));
if (i < toComps.Length)
{
Debug.Log("toComps.Length is " + toComps.Length + " i is " + i);
// Not good at all: EditorUtility.CopySerialized(fromComps_, toComps*); // Source to Destination*
toComps = fromComps*; // Does nothing apparently.*
// This doesn’t work it just duplicates inside fromObject: EditorUtility.CloneComponent(fromComps*);
msg += " Add To: Increasing toObject component count to " + toComps.Length;
}
else
{
msg += " Problem: i is " + i + " but toComps is only " + toComps.Length;
}
}
else
{
if (copyValues)
{
// Doesn’t make a difference: Destroy(toComps);
//Duplicates in Source (not good either): toObject.AddComponent(EditorUtility.CloneComponent(fromComps));
// Not good: EditorUtility.CopySerialized(fromComps, toComps); // Source to Destination*

toComps = fromComps*; //Does nothing.*
// Trouble here also: EditorUtility.CloneComponent(fromComps*);
msg += " Cloned values.";
}
}
}
EditorUtility.DisplayDialog(“Game Object Facts”, msg , “OK”, “”);
}
}

Thanks in advance!

*_

Use reflection.

Component new_component = gameObject.AddComponent(old_component.GetType());
foreach (FieldInfo f in old_component.GetType().GetFields())
{
  f.SetValue(new_component, f.GetValue(old_component));
}

A better approach would be to use UnityEditorInternal namespace:

UnityEditorInternal.ComponentUtility.CopyComponent(componentToCopy);
UnityEditorInternal.ComponentUtility.PasteComponentAsNew(targetGameObject);

You can also use PasteComponentValues instead of PasteComponentAsNew.

To add to that Reflection suggestion, if you are using private serialized variables, like me, you may want something more like this…

foreach (FieldInfo info in comp.GetType().GetFields(BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.NonPublic))
	if(info.IsPublic || info.GetCustomAttributes(typeof(SerializeField),true).Length != 0);
		info.SetValue(newComponent, info.GetValue(comp));