Skip to content

Instantly share code, notes, and snippets.

@mattatz
Last active July 26, 2023 20:44
Show Gist options
  • Star 17 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save mattatz/1c039dce5ef251dcef7b628c878bea32 to your computer and use it in GitHub Desktop.
Save mattatz/1c039dce5ef251dcef7b628c878bea32 to your computer and use it in GitHub Desktop.
CopyComponent by Script for Unity
using System;
using System.Linq;
using System.Collections;
using System.Collections.Generic;
using System.Reflection;
using UnityEngine;
namespace Utils
{
// http://answers.unity3d.com/questions/458207/copy-a-component-at-runtime.html
// http://stackoverflow.com/questions/10261824/how-can-i-get-all-constants-of-a-type-by-reflection
public class ComponentUtil
{
public static T CopyComponent<T>(T original, GameObject destination) where T : Component
{
System.Type type = original.GetType();
var dst = destination.GetComponent(type) as T;
if (!dst) dst = destination.AddComponent(type) as T;
var fields = GetAllFields(type);
foreach (var field in fields)
{
if (field.IsStatic) continue;
field.SetValue(dst, field.GetValue(original));
}
var props = type.GetProperties();
foreach (var prop in props)
{
if (!prop.CanWrite || !prop.CanWrite || prop.Name == "name") continue;
prop.SetValue(dst, prop.GetValue(original, null), null);
}
return dst as T;
}
public static IEnumerable<FieldInfo> GetAllFields(System.Type t)
{
if (t == null)
{
return Enumerable.Empty<FieldInfo>();
}
BindingFlags flags = BindingFlags.Public | BindingFlags.NonPublic |
BindingFlags.Static | BindingFlags.Instance |
BindingFlags.DeclaredOnly;
return t.GetFields(flags).Concat(GetAllFields(t.BaseType));
}
}
}
@dmitry1100
Copy link

dmitry1100 commented Jan 11, 2020

I guess !prop.CanWrite || !prop.CanWrite is typo and second check should be !prop.CanRead?

@thygrrr
Copy link

thygrrr commented Jan 22, 2021

The field copy part clobbers most internal components of Unity, e.g. when copying an AudioSource.

This doesn't immediately show because the code disallows for multiple components; if it allowed multiple components to be added, you will see the problem.

Repro: Remove line 21 and try to clone a component (eg AudioSource) 20 times. It will show up erratically in the Inspector, and if you change one of its serialized properties (e.g. AudioClip), it will change in the copies as well.

@wp498930275
Copy link

when copy MeshRenderer, original and destination material will instante; this changed original`s property.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment