using System.Globalization; using System.Reflection; using UnityEngine; using X10D.Reflection; using Object = UnityEngine.Object; namespace X10D.Unity; /// /// Extension methods for . /// public static class ComponentExtensions { /// /// Copies the component to another game object. /// /// The component to copy. /// The game object to which the component will be copied. /// The type of the component to copy. /// /// is . /// -or- /// is . /// /// /// already has a component of type . /// /// /// This method will destroy the component on the source game object, creating a new instance on the target. Use with /// caution. /// public static void CopyTo(this T component, GameObject target) where T : Component { if (component == null) { throw new ArgumentNullException(nameof(component)); } if (target == null) { throw new ArgumentNullException(nameof(target)); } if (target.TryGetComponent(out T targetComponent)) { string message = ExceptionMessages.ComponentAlreadyExists; message = string.Format(CultureInfo.CurrentCulture, message, target.name, typeof(T).Name); throw new InvalidOperationException(message); } targetComponent = target.AddComponent(); var typeInfo = typeof(T).GetTypeInfo(); CopyFields(typeInfo, component, targetComponent); } /// /// Copies the component to another game object. /// /// The component to copy. /// The game object to which the component will be copied. /// /// is . /// -or- /// is . /// /// /// already has a component of the same type. /// /// /// This method will destroy the component on the source game object, creating a new instance on the target. Use with /// caution. /// public static void CopyTo(this Component component, GameObject target) { if (component == null) { throw new ArgumentNullException(nameof(component)); } if (target == null) { throw new ArgumentNullException(nameof(target)); } var componentType = component.GetType(); if (target.TryGetComponent(componentType, out Component targetComponent)) { string message = ExceptionMessages.ComponentAlreadyExists; message = string.Format(CultureInfo.CurrentCulture, message, target.name, componentType.Name); throw new InvalidOperationException(message); } targetComponent = target.AddComponent(componentType); var typeInfo = componentType.GetTypeInfo(); CopyFields(typeInfo, component, targetComponent); } /// /// Returns an array of components of the specified type, excluding components that live on the object to which this /// component is attached. /// /// The component whose child components to retrieve. /// The type of the components to retrieve. /// An array representing the child components. public static T[] GetComponentsInChildrenOnly(this Component component) { return component.gameObject.GetComponentsInChildrenOnly(); } /// /// Moves the component to another game object. /// /// The component to move. /// The game object to which the component will be moved. /// The type of the component to move. /// /// is . /// -or- /// is . /// /// /// already has a component of type . /// /// /// This method will destroy the component on the source game object, creating a new instance on the target. Use with /// caution. /// public static void MoveTo(this T component, GameObject target) where T : Component { if (component == null) { throw new ArgumentNullException(nameof(component)); } if (target == null) { throw new ArgumentNullException(nameof(target)); } component.CopyTo(target); Object.Destroy(component); } /// /// Moves the component to another game object. /// /// The component to move. /// The game object to which the component will be moved. /// /// is . /// -or- /// is . /// /// /// already has a component of the same type. /// /// /// This method will destroy the component on the source game object, creating a new instance on the target. Use with /// caution. /// public static void MoveTo(this Component component, GameObject target) { if (component == null) { throw new ArgumentNullException(nameof(component)); } if (target == null) { throw new ArgumentNullException(nameof(target)); } component.CopyTo(target); Object.Destroy(component); } private static void CopyFields(TypeInfo typeInfo, T component, T targetComponent) where T : Component { foreach (FieldInfo field in typeInfo.DeclaredFields) { if (field.IsStatic || !field.IsPublic && !field.HasCustomAttribute()) { continue; } if (field.HasCustomAttribute()) { continue; } object fieldValue = GetNewReferences(component, targetComponent, field.GetValue(component)); field.SetValue(targetComponent, fieldValue); } } private static object GetNewReferences(T component, T targetComponent, object value) where T : Component { if (ReferenceEquals(value, component)) { value = targetComponent; } else if (ReferenceEquals(value, component.gameObject)) { value = targetComponent.gameObject; } return value; } }