mirror of
https://github.com/oliverbooth/X10D
synced 2024-11-25 13:38:49 +00:00
feat: add Component move/copy
As usual, experimental API - subject to change.
This commit is contained in:
parent
75ac9e2d8f
commit
420ec2433a
@ -20,6 +20,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
- X10D: Added `TextWriter.WriteLineNoAlloc(uint[, ReadOnlySpan<char>[, IFormatProvider]])`.
|
||||
- X10D: Added `TextWriter.WriteLineNoAlloc(long[, ReadOnlySpan<char>[, IFormatProvider]])`.
|
||||
- X10D: Added `TextWriter.WriteLineNoAlloc(ulong[, ReadOnlySpan<char>[, IFormatProvider]])`.
|
||||
- X10D.Unity: Added `Component.CopyTo(GameObject)` and `Component.MoveTo(GameObject)`.
|
||||
- X10D.Unity: Added `GameObject.CopyComponent<T>(GameObject)` and `GameObject.MoveComponent<T>(GameObject)`.
|
||||
|
||||
### Changed
|
||||
- X10D: `DateTime.Age(DateTime)` and `DateTimeOffset.Age(DateTimeOffset)` parameter renamed from `asOf` to `referenceDate`.
|
||||
|
@ -1,14 +1,77 @@
|
||||
#nullable enable
|
||||
|
||||
using System;
|
||||
using System.Collections;
|
||||
using NUnit.Framework;
|
||||
using UnityEngine;
|
||||
using UnityEngine.TestTools;
|
||||
using Object = UnityEngine.Object;
|
||||
|
||||
namespace X10D.Unity.Tests
|
||||
{
|
||||
public class ComponentTests
|
||||
{
|
||||
[UnityTest]
|
||||
public IEnumerator CopyTo_ShouldCopyComponent_GivenComponent()
|
||||
{
|
||||
var source = new GameObject();
|
||||
var sourceComponent = source.AddComponent<Rigidbody>();
|
||||
sourceComponent.mass = 10.0f;
|
||||
sourceComponent.useGravity = false;
|
||||
|
||||
var target = new GameObject();
|
||||
sourceComponent.CopyTo(target);
|
||||
|
||||
Assert.That(target.TryGetComponent(out Rigidbody targetComponent));
|
||||
Assert.That(targetComponent.mass, Is.EqualTo(10.0f));
|
||||
Assert.That(targetComponent.useGravity, Is.False);
|
||||
|
||||
Object.Destroy(source);
|
||||
Object.Destroy(target);
|
||||
yield break;
|
||||
}
|
||||
|
||||
[UnityTest]
|
||||
public IEnumerator CopyTo_ShouldThrowArgumentNullException_GivenNullComponent()
|
||||
{
|
||||
var target = new GameObject();
|
||||
Rigidbody rigidbody = null!;
|
||||
|
||||
Assert.Throws<ArgumentNullException>(() => rigidbody.CopyTo(target));
|
||||
|
||||
Object.Destroy(target);
|
||||
yield break;
|
||||
}
|
||||
|
||||
[UnityTest]
|
||||
public IEnumerator CopyTo_ShouldThrowArgumentNullException_GivenNullTarget()
|
||||
{
|
||||
var source = new GameObject();
|
||||
var rigidbody = source.AddComponent<Rigidbody>();
|
||||
GameObject target = null!;
|
||||
|
||||
Assert.Throws<ArgumentNullException>(() => rigidbody.CopyTo(target));
|
||||
|
||||
Object.Destroy(source);
|
||||
yield break;
|
||||
}
|
||||
|
||||
[UnityTest]
|
||||
public IEnumerator CopyTo_ShouldThrowInvalidOperationException_GivenDuplicate()
|
||||
{
|
||||
var source = new GameObject();
|
||||
var rigidbody = source.AddComponent<Rigidbody>();
|
||||
|
||||
var target = new GameObject();
|
||||
target.AddComponent<Rigidbody>();
|
||||
|
||||
Assert.Throws<InvalidOperationException>(() => rigidbody.CopyTo(target));
|
||||
|
||||
Object.Destroy(source);
|
||||
Object.Destroy(target);
|
||||
yield break;
|
||||
}
|
||||
|
||||
[UnityTest]
|
||||
public IEnumerator GetComponentsInChildrenOnly_ShouldIgnoreParent()
|
||||
{
|
||||
@ -16,13 +79,80 @@ namespace X10D.Unity.Tests
|
||||
var rigidbody = parent.AddComponent<Rigidbody>();
|
||||
|
||||
var child = new GameObject();
|
||||
child.transform.SetParent(parent.transform);
|
||||
child.AddComponent<Rigidbody>();
|
||||
|
||||
yield return null;
|
||||
|
||||
Rigidbody[] components = rigidbody.GetComponentsInChildrenOnly<Rigidbody>();
|
||||
Assert.That(components.Length, Is.EqualTo(1));
|
||||
Assert.That(child, Is.EqualTo(components[0].gameObject));
|
||||
|
||||
Object.Destroy(parent);
|
||||
Object.Destroy(child);
|
||||
}
|
||||
|
||||
[UnityTest]
|
||||
public IEnumerator MoveTo_ShouldCopyComponent_GivenComponent()
|
||||
{
|
||||
var source = new GameObject();
|
||||
var sourceComponent = source.AddComponent<Rigidbody>();
|
||||
sourceComponent.mass = 10f;
|
||||
sourceComponent.useGravity = false;
|
||||
|
||||
var target = new GameObject();
|
||||
sourceComponent.MoveTo(target);
|
||||
|
||||
// effects of Destroy only take place at end of frame
|
||||
yield return null;
|
||||
|
||||
Assert.That(sourceComponent == null);
|
||||
Assert.That(source.TryGetComponent(out Rigidbody _), Is.False);
|
||||
Assert.That(target.TryGetComponent(out Rigidbody targetComponent));
|
||||
Assert.That(targetComponent.mass, Is.EqualTo(10.0f));
|
||||
Assert.That(targetComponent.useGravity, Is.False);
|
||||
|
||||
Object.Destroy(source);
|
||||
Object.Destroy(target);
|
||||
}
|
||||
|
||||
[UnityTest]
|
||||
public IEnumerator MoveTo_ShouldThrowArgumentNullException_GivenNullComponent()
|
||||
{
|
||||
var target = new GameObject();
|
||||
Rigidbody rigidbody = null!;
|
||||
|
||||
Assert.Throws<ArgumentNullException>(() => rigidbody.MoveTo(target));
|
||||
|
||||
Object.Destroy(target);
|
||||
yield break;
|
||||
}
|
||||
|
||||
[UnityTest]
|
||||
public IEnumerator MoveTo_ShouldThrowArgumentNullException_GivenNullTarget()
|
||||
{
|
||||
var source = new GameObject();
|
||||
var rigidbody = source.AddComponent<Rigidbody>();
|
||||
GameObject target = null!;
|
||||
|
||||
Assert.Throws<ArgumentNullException>(() => rigidbody.MoveTo(target));
|
||||
|
||||
Object.Destroy(source);
|
||||
yield break;
|
||||
}
|
||||
|
||||
[UnityTest]
|
||||
public IEnumerator MoveTo_ShouldThrowInvalidOperationException_GivenDuplicate()
|
||||
{
|
||||
var source = new GameObject();
|
||||
var rigidbody = source.AddComponent<Rigidbody>();
|
||||
|
||||
var target = new GameObject();
|
||||
target.AddComponent<Rigidbody>();
|
||||
|
||||
Assert.Throws<InvalidOperationException>(() => rigidbody.MoveTo(target));
|
||||
|
||||
Object.Destroy(source);
|
||||
Object.Destroy(target);
|
||||
yield break;
|
||||
}
|
||||
}
|
||||
|
@ -1,14 +1,107 @@
|
||||
#nullable enable
|
||||
|
||||
using System;
|
||||
using System.Collections;
|
||||
using NUnit.Framework;
|
||||
using UnityEngine;
|
||||
using UnityEngine.TestTools;
|
||||
using Object = UnityEngine.Object;
|
||||
|
||||
namespace X10D.Unity.Tests
|
||||
{
|
||||
public class GameObjectTests
|
||||
{
|
||||
[UnityTest]
|
||||
public IEnumerator CopyComponent_ShouldCopyComponent_GivenComponent()
|
||||
{
|
||||
var source = new GameObject();
|
||||
var sourceComponent = source.AddComponent<Rigidbody>();
|
||||
sourceComponent.mass = 10.0f;
|
||||
sourceComponent.useGravity = false;
|
||||
|
||||
var target = new GameObject();
|
||||
source.CopyComponent<Rigidbody>(target);
|
||||
|
||||
Assert.That(target.TryGetComponent(out Rigidbody targetComponent));
|
||||
Assert.That(targetComponent.mass, Is.EqualTo(10.0f));
|
||||
Assert.That(targetComponent.useGravity, Is.False);
|
||||
|
||||
Object.Destroy(source);
|
||||
Object.Destroy(target);
|
||||
yield break;
|
||||
}
|
||||
|
||||
[UnityTest]
|
||||
public IEnumerator CopyComponent_ShouldThrowArgumentNullException_GivenNullComponentType()
|
||||
{
|
||||
var source = new GameObject();
|
||||
var target = new GameObject();
|
||||
Type componentType = null!;
|
||||
|
||||
Assert.Throws<ArgumentNullException>(() => source.CopyComponent(componentType, target));
|
||||
|
||||
Object.Destroy(source);
|
||||
Object.Destroy(target);
|
||||
yield break;
|
||||
}
|
||||
|
||||
[UnityTest]
|
||||
public IEnumerator CopyComponent_ShouldThrowArgumentNullException_GivenNullGameObject()
|
||||
{
|
||||
var target = new GameObject();
|
||||
GameObject source = null!;
|
||||
|
||||
Assert.Throws<ArgumentNullException>(() => source.CopyComponent<Rigidbody>(target));
|
||||
Assert.Throws<ArgumentNullException>(() => source.CopyComponent(typeof(Rigidbody), target));
|
||||
|
||||
Object.Destroy(target);
|
||||
yield break;
|
||||
}
|
||||
|
||||
[UnityTest]
|
||||
public IEnumerator CopyComponent_ShouldThrowArgumentNullException_GivenNullTarget()
|
||||
{
|
||||
var source = new GameObject();
|
||||
GameObject target = null!;
|
||||
|
||||
Assert.Throws<ArgumentNullException>(() => source.CopyComponent<Rigidbody>(target));
|
||||
Assert.Throws<ArgumentNullException>(() => source.CopyComponent(typeof(Rigidbody), target));
|
||||
|
||||
Object.Destroy(source);
|
||||
yield break;
|
||||
}
|
||||
|
||||
[UnityTest]
|
||||
public IEnumerator CopyComponent_ShouldThrowInvalidOperationException_GivenInvalidComponent()
|
||||
{
|
||||
var source = new GameObject();
|
||||
var target = new GameObject();
|
||||
|
||||
Assert.Throws<InvalidOperationException>(() => source.CopyComponent<Rigidbody>(target));
|
||||
Assert.Throws<InvalidOperationException>(() => source.CopyComponent(typeof(Rigidbody), target));
|
||||
|
||||
Object.Destroy(source);
|
||||
Object.Destroy(target);
|
||||
yield break;
|
||||
}
|
||||
|
||||
[UnityTest]
|
||||
public IEnumerator CopyComponent_ShouldThrowInvalidOperationException_GivenDuplicate()
|
||||
{
|
||||
var source = new GameObject();
|
||||
source.AddComponent<Rigidbody>();
|
||||
|
||||
var target = new GameObject();
|
||||
target.AddComponent<Rigidbody>();
|
||||
|
||||
Assert.Throws<InvalidOperationException>(() => source.CopyComponent<Rigidbody>(target));
|
||||
Assert.Throws<InvalidOperationException>(() => source.CopyComponent(typeof(Rigidbody), target));
|
||||
|
||||
Object.Destroy(source);
|
||||
Object.Destroy(target);
|
||||
yield break;
|
||||
}
|
||||
|
||||
[UnityTest]
|
||||
public IEnumerator GetComponentsInChildrenOnly_ShouldIgnoreParent()
|
||||
{
|
||||
@ -23,6 +116,8 @@ namespace X10D.Unity.Tests
|
||||
Assert.That(components.Length, Is.EqualTo(1));
|
||||
Assert.That(child, Is.EqualTo(components[0].gameObject));
|
||||
|
||||
Object.Destroy(parent);
|
||||
Object.Destroy(child);
|
||||
yield break;
|
||||
}
|
||||
|
||||
@ -58,6 +153,103 @@ namespace X10D.Unity.Tests
|
||||
first.LookAt(Vector3.right);
|
||||
Assert.That(firstTransform.rotation, Is.EqualTo(expected));
|
||||
|
||||
Object.Destroy(first);
|
||||
Object.Destroy(second);
|
||||
yield break;
|
||||
}
|
||||
|
||||
[UnityTest]
|
||||
public IEnumerator MoveComponent_ShouldCopyComponent_GivenComponent()
|
||||
{
|
||||
var source = new GameObject();
|
||||
var sourceComponent = source.AddComponent<Rigidbody>();
|
||||
sourceComponent.mass = 10.0f;
|
||||
sourceComponent.useGravity = false;
|
||||
|
||||
var target = new GameObject();
|
||||
source.MoveComponent<Rigidbody>(target);
|
||||
|
||||
// effects of Destroy only take place at end of frame
|
||||
yield return null;
|
||||
|
||||
Assert.That(sourceComponent == null);
|
||||
Assert.That(source.TryGetComponent(out Rigidbody _), Is.False);
|
||||
Assert.That(target.TryGetComponent(out Rigidbody targetComponent));
|
||||
Assert.That(targetComponent.mass, Is.EqualTo(10.0f));
|
||||
Assert.That(targetComponent.useGravity, Is.False);
|
||||
|
||||
Object.Destroy(source);
|
||||
Object.Destroy(target);
|
||||
}
|
||||
|
||||
[UnityTest]
|
||||
public IEnumerator MoveComponent_ShouldThrowArgumentNullException_GivenNullComponentType()
|
||||
{
|
||||
var source = new GameObject();
|
||||
var target = new GameObject();
|
||||
Type componentType = null!;
|
||||
|
||||
Assert.Throws<ArgumentNullException>(() => source.MoveComponent(componentType, target));
|
||||
|
||||
Object.Destroy(source);
|
||||
Object.Destroy(target);
|
||||
yield break;
|
||||
}
|
||||
|
||||
[UnityTest]
|
||||
public IEnumerator MoveComponent_ShouldThrowArgumentNullException_GivenNullGameObject()
|
||||
{
|
||||
var target = new GameObject();
|
||||
GameObject source = null!;
|
||||
|
||||
Assert.Throws<ArgumentNullException>(() => source.MoveComponent<Rigidbody>(target));
|
||||
Assert.Throws<ArgumentNullException>(() => source.MoveComponent(typeof(Rigidbody), target));
|
||||
|
||||
Object.Destroy(target);
|
||||
yield break;
|
||||
}
|
||||
|
||||
[UnityTest]
|
||||
public IEnumerator MoveComponent_ShouldThrowArgumentNullException_GivenNullTarget()
|
||||
{
|
||||
var source = new GameObject();
|
||||
GameObject target = null!;
|
||||
|
||||
Assert.Throws<ArgumentNullException>(() => source.MoveComponent<Rigidbody>(target));
|
||||
Assert.Throws<ArgumentNullException>(() => source.MoveComponent(typeof(Rigidbody), target));
|
||||
|
||||
Object.Destroy(source);
|
||||
yield break;
|
||||
}
|
||||
|
||||
[UnityTest]
|
||||
public IEnumerator MoveComponent_ShouldThrowInvalidOperationException_GivenInvalidComponent()
|
||||
{
|
||||
var source = new GameObject();
|
||||
var target = new GameObject();
|
||||
|
||||
Assert.Throws<InvalidOperationException>(() => source.MoveComponent<Rigidbody>(target));
|
||||
Assert.Throws<InvalidOperationException>(() => source.MoveComponent(typeof(Rigidbody), target));
|
||||
|
||||
Object.Destroy(source);
|
||||
Object.Destroy(target);
|
||||
yield break;
|
||||
}
|
||||
|
||||
[UnityTest]
|
||||
public IEnumerator MoveComponent_ShouldThrowInvalidOperationException_GivenDuplicate()
|
||||
{
|
||||
var source = new GameObject();
|
||||
source.AddComponent<Rigidbody>();
|
||||
|
||||
var target = new GameObject();
|
||||
target.AddComponent<Rigidbody>();
|
||||
|
||||
Assert.Throws<InvalidOperationException>(() => source.MoveComponent<Rigidbody>(target));
|
||||
Assert.Throws<InvalidOperationException>(() => source.MoveComponent(typeof(Rigidbody), target));
|
||||
|
||||
Object.Destroy(source);
|
||||
Object.Destroy(target);
|
||||
yield break;
|
||||
}
|
||||
|
||||
@ -82,6 +274,9 @@ namespace X10D.Unity.Tests
|
||||
Assert.That(child.layer, Is.EqualTo(layer));
|
||||
Assert.That(grandChild.layer, Is.EqualTo(layer));
|
||||
|
||||
Object.Destroy(parent);
|
||||
Object.Destroy(child);
|
||||
Object.Destroy(grandChild);
|
||||
yield break;
|
||||
}
|
||||
|
||||
@ -103,6 +298,8 @@ namespace X10D.Unity.Tests
|
||||
second.SetParent(first);
|
||||
Assert.That(second.transform.parent, Is.EqualTo(first.transform));
|
||||
|
||||
Object.Destroy(first);
|
||||
Object.Destroy(second);
|
||||
yield break;
|
||||
}
|
||||
}
|
||||
|
@ -70,4 +70,19 @@
|
||||
</None>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<EmbeddedResource Update="src\ExceptionMessages.resx">
|
||||
<Generator>ResXFileCodeGenerator</Generator>
|
||||
<LastGenOutput>ExceptionMessages.Designer.cs</LastGenOutput>
|
||||
</EmbeddedResource>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Compile Update="src\ExceptionMessages.Designer.cs">
|
||||
<DesignTime>True</DesignTime>
|
||||
<AutoGen>True</AutoGen>
|
||||
<DependentUpon>ExceptionMessages.resx</DependentUpon>
|
||||
</Compile>
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
@ -1,4 +1,7 @@
|
||||
using UnityEngine;
|
||||
using System.Globalization;
|
||||
using System.Reflection;
|
||||
using UnityEngine;
|
||||
using Object = UnityEngine.Object;
|
||||
|
||||
namespace X10D.Unity;
|
||||
|
||||
@ -7,6 +10,95 @@ namespace X10D.Unity;
|
||||
/// </summary>
|
||||
public static class ComponentExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Copies the component to another game object.
|
||||
/// </summary>
|
||||
/// <param name="component">The component to copy.</param>
|
||||
/// <param name="target">The game object to which the component will be copied.</param>
|
||||
/// <typeparam name="T">The type of the component to copy.</typeparam>
|
||||
/// <exception cref="ArgumentNullException">
|
||||
/// <para><paramref name="component" /> is <see langword="null" />.</para>
|
||||
/// -or-
|
||||
/// <para><paramref name="target" /> is <see langword="null" />.</para>
|
||||
/// </exception>
|
||||
/// <exception cref="InvalidOperationException">
|
||||
/// <paramref name="target" /> already has a component of type <typeparamref name="T" />.
|
||||
/// </exception>
|
||||
/// <remarks>
|
||||
/// This method will destroy the component on the source game object, creating a new instance on the target. Use with
|
||||
/// caution.
|
||||
/// </remarks>
|
||||
public static void CopyTo<T>(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<T>();
|
||||
|
||||
var typeInfo = typeof(T).GetTypeInfo();
|
||||
CopyFields(typeInfo, component, targetComponent);
|
||||
CopyProperties(typeInfo, component, targetComponent);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Copies the component to another game object.
|
||||
/// </summary>
|
||||
/// <param name="component">The component to copy.</param>
|
||||
/// <param name="target">The game object to which the component will be copied.</param>
|
||||
/// <exception cref="ArgumentNullException">
|
||||
/// <para><paramref name="component" /> is <see langword="null" />.</para>
|
||||
/// -or-
|
||||
/// <para><paramref name="target" /> is <see langword="null" />.</para>
|
||||
/// </exception>
|
||||
/// <exception cref="InvalidOperationException">
|
||||
/// <paramref name="target" /> already has a component of the same type.
|
||||
/// </exception>
|
||||
/// <remarks>
|
||||
/// This method will destroy the component on the source game object, creating a new instance on the target. Use with
|
||||
/// caution.
|
||||
/// </remarks>
|
||||
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);
|
||||
CopyProperties(typeInfo, component, targetComponent);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns an array of components of the specified type, excluding components that live on the object to which this
|
||||
/// component is attached.
|
||||
@ -18,4 +110,124 @@ public static class ComponentExtensions
|
||||
{
|
||||
return component.gameObject.GetComponentsInChildrenOnly<T>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Moves the component to another game object.
|
||||
/// </summary>
|
||||
/// <param name="component">The component to move.</param>
|
||||
/// <param name="target">The game object to which the component will be moved.</param>
|
||||
/// <typeparam name="T">The type of the component to move.</typeparam>
|
||||
/// <exception cref="ArgumentNullException">
|
||||
/// <para><paramref name="component" /> is <see langword="null" />.</para>
|
||||
/// -or-
|
||||
/// <para><paramref name="target" /> is <see langword="null" />.</para>
|
||||
/// </exception>
|
||||
/// <exception cref="InvalidOperationException">
|
||||
/// <paramref name="target" /> already has a component of type <typeparamref name="T" />.
|
||||
/// </exception>
|
||||
/// <remarks>
|
||||
/// This method will destroy the component on the source game object, creating a new instance on the target. Use with
|
||||
/// caution.
|
||||
/// </remarks>
|
||||
public static void MoveTo<T>(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);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Moves the component to another game object.
|
||||
/// </summary>
|
||||
/// <param name="component">The component to move.</param>
|
||||
/// <param name="target">The game object to which the component will be moved.</param>
|
||||
/// <exception cref="ArgumentNullException">
|
||||
/// <para><paramref name="component" /> is <see langword="null" />.</para>
|
||||
/// -or-
|
||||
/// <para><paramref name="target" /> is <see langword="null" />.</para>
|
||||
/// </exception>
|
||||
/// <exception cref="InvalidOperationException">
|
||||
/// <paramref name="target" /> already has a component of the same type.
|
||||
/// </exception>
|
||||
/// <remarks>
|
||||
/// This method will destroy the component on the source game object, creating a new instance on the target. Use with
|
||||
/// caution.
|
||||
/// </remarks>
|
||||
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<T>(TypeInfo typeInfo, T component, T targetComponent)
|
||||
where T : Component
|
||||
{
|
||||
foreach (FieldInfo field in typeInfo.DeclaredFields)
|
||||
{
|
||||
if (field.IsStatic)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
object fieldValue = GetNewReferences(component, targetComponent, field.GetValue(component));
|
||||
field.SetValue(targetComponent, fieldValue);
|
||||
}
|
||||
}
|
||||
|
||||
private static void CopyProperties<T>(TypeInfo typeInfo, T component, T targetComponent)
|
||||
where T : Component
|
||||
{
|
||||
foreach (PropertyInfo property in typeInfo.DeclaredProperties)
|
||||
{
|
||||
if (!property.CanRead || !property.CanWrite)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
MethodInfo getMethod = property.GetMethod;
|
||||
MethodInfo setMethod = property.SetMethod;
|
||||
if (getMethod.IsStatic || setMethod.IsStatic)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
object propertyValue = GetNewReferences(component, targetComponent, property.GetValue(component));
|
||||
property.SetValue(targetComponent, propertyValue);
|
||||
}
|
||||
}
|
||||
|
||||
private static object GetNewReferences<T>(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;
|
||||
}
|
||||
}
|
||||
|
80
X10D.Unity/src/ExceptionMessages.Designer.cs
generated
Normal file
80
X10D.Unity/src/ExceptionMessages.Designer.cs
generated
Normal file
@ -0,0 +1,80 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// <auto-generated>
|
||||
// This code was generated by a tool.
|
||||
//
|
||||
// Changes to this file may cause incorrect behavior and will be lost if
|
||||
// the code is regenerated.
|
||||
// </auto-generated>
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
namespace X10D.Unity {
|
||||
using System;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// A strongly-typed resource class, for looking up localized strings, etc.
|
||||
/// </summary>
|
||||
// This class was auto-generated by the StronglyTypedResourceBuilder
|
||||
// class via a tool like ResGen or Visual Studio.
|
||||
// To add or remove a member, edit your .ResX file then rerun ResGen
|
||||
// with the /str option, or rebuild your VS project.
|
||||
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
|
||||
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
|
||||
internal class ExceptionMessages {
|
||||
|
||||
private static global::System.Resources.ResourceManager resourceMan;
|
||||
|
||||
private static global::System.Globalization.CultureInfo resourceCulture;
|
||||
|
||||
[global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
|
||||
internal ExceptionMessages() {
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the cached ResourceManager instance used by this class.
|
||||
/// </summary>
|
||||
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
|
||||
internal static global::System.Resources.ResourceManager ResourceManager {
|
||||
get {
|
||||
if (object.ReferenceEquals(resourceMan, null)) {
|
||||
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("X10D.Unity.src.ExceptionMessages", typeof(ExceptionMessages).Assembly);
|
||||
resourceMan = temp;
|
||||
}
|
||||
return resourceMan;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Overrides the current thread's CurrentUICulture property for all
|
||||
/// resource lookups using this strongly typed resource class.
|
||||
/// </summary>
|
||||
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
|
||||
internal static global::System.Globalization.CultureInfo Culture {
|
||||
get {
|
||||
return resourceCulture;
|
||||
}
|
||||
set {
|
||||
resourceCulture = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to The game object {0} already has a component of type {1}..
|
||||
/// </summary>
|
||||
internal static string ComponentAlreadyExists {
|
||||
get {
|
||||
return ResourceManager.GetString("ComponentAlreadyExists", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to The game object {0} does not have a component of type {1}..
|
||||
/// </summary>
|
||||
internal static string ComponentDoesNotExist {
|
||||
get {
|
||||
return ResourceManager.GetString("ComponentDoesNotExist", resourceCulture);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
34
X10D.Unity/src/ExceptionMessages.resx
Normal file
34
X10D.Unity/src/ExceptionMessages.resx
Normal file
@ -0,0 +1,34 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
|
||||
<root>
|
||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema"
|
||||
xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||
<xsd:element name="root" msdata:IsDataSet="true">
|
||||
|
||||
</xsd:element>
|
||||
</xsd:schema>
|
||||
<resheader name="resmimetype">
|
||||
<value>text/microsoft-resx</value>
|
||||
</resheader>
|
||||
<resheader name="version">
|
||||
<value>1.3</value>
|
||||
</resheader>
|
||||
<resheader name="reader">
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral,
|
||||
PublicKeyToken=b77a5c561934e089
|
||||
</value>
|
||||
</resheader>
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral,
|
||||
PublicKeyToken=b77a5c561934e089
|
||||
</value>
|
||||
</resheader>
|
||||
|
||||
<data name="ComponentDoesNotExist" xml:space="preserve">
|
||||
<value>The game object {0} does not have a component of type {1}.</value>
|
||||
</data>
|
||||
|
||||
<data name="ComponentAlreadyExists" xml:space="preserve">
|
||||
<value>The game object {0} already has a component of type {1}.</value>
|
||||
</data>
|
||||
</root>
|
@ -1,4 +1,6 @@
|
||||
using System.Globalization;
|
||||
using UnityEngine;
|
||||
using Object = UnityEngine.Object;
|
||||
|
||||
namespace X10D.Unity;
|
||||
|
||||
@ -7,6 +9,90 @@ namespace X10D.Unity;
|
||||
/// </summary>
|
||||
public static class GameObjectExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Copies the component of the specified type from one game object to another.
|
||||
/// </summary>
|
||||
/// <param name="gameObject">The game object from which to copy the component.</param>
|
||||
/// <param name="target">The game object to which the component will be copied.</param>
|
||||
/// <typeparam name="T">The type of the component to copy.</typeparam>
|
||||
/// <exception cref="ArgumentNullException">
|
||||
/// <para><paramref name="gameObject" /> is <see langword="null" />.</para>
|
||||
/// -or-
|
||||
/// <para><paramref name="target" /> is <see langword="null" />.</para>
|
||||
/// </exception>
|
||||
/// <exception cref="InvalidOperationException">
|
||||
/// <para><paramref name="gameObject" /> does not have a component of type <typeparamref name="T" />.</para>
|
||||
/// -or-
|
||||
/// <para><paramref name="target" /> already has a component of type <typeparamref name="T" />.</para>
|
||||
/// </exception>
|
||||
public static void CopyComponent<T>(this GameObject gameObject, GameObject target)
|
||||
where T : Component
|
||||
{
|
||||
if (gameObject == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(gameObject));
|
||||
}
|
||||
|
||||
if (target == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(target));
|
||||
}
|
||||
|
||||
if (!gameObject.TryGetComponent(out T sourceComponent))
|
||||
{
|
||||
string message = ExceptionMessages.ComponentDoesNotExist;
|
||||
message = string.Format(CultureInfo.CurrentCulture, message, gameObject.name, typeof(T).Name);
|
||||
throw new InvalidOperationException(message);
|
||||
}
|
||||
|
||||
sourceComponent.CopyTo(target);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Copies the component of the specified type from one game object to another.
|
||||
/// </summary>
|
||||
/// <param name="gameObject">The game object from which to copy the component.</param>
|
||||
/// <param name="componentType">The type of the component to copy.</param>
|
||||
/// <param name="target">The game object to which the component will be copied.</param>
|
||||
/// <exception cref="ArgumentNullException">
|
||||
/// <para><paramref name="gameObject" /> is <see langword="null" />.</para>
|
||||
/// -or-
|
||||
/// <para><paramref name="target" /> is <see langword="null" />.</para>
|
||||
/// -or-
|
||||
/// <para><paramref name="target" /> is <see langword="null" />.</para>
|
||||
/// </exception>
|
||||
/// <exception cref="InvalidOperationException">
|
||||
/// <para><paramref name="gameObject" /> does not have a component of type <paramref name="componentType" />.</para>
|
||||
/// -or-
|
||||
/// <para><paramref name="target" /> already has a component of type <paramref name="componentType" />.</para>
|
||||
/// </exception>
|
||||
public static void CopyComponent(this GameObject gameObject, Type componentType, GameObject target)
|
||||
{
|
||||
if (gameObject == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(gameObject));
|
||||
}
|
||||
|
||||
if (componentType is null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(componentType));
|
||||
}
|
||||
|
||||
if (target == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(target));
|
||||
}
|
||||
|
||||
if (!gameObject.TryGetComponent(componentType, out Component sourceComponent))
|
||||
{
|
||||
string message = ExceptionMessages.ComponentDoesNotExist;
|
||||
message = string.Format(CultureInfo.CurrentCulture, message, gameObject.name, componentType.Name);
|
||||
throw new InvalidOperationException(message);
|
||||
}
|
||||
|
||||
sourceComponent.CopyTo(target);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns an array of components of the specified type, excluding components that live on this game object.
|
||||
/// </summary>
|
||||
@ -171,6 +257,100 @@ public static class GameObjectExtensions
|
||||
gameObject.transform.LookAt(target, worldUp);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Moves the component of the specified type from one game object to another.
|
||||
/// </summary>
|
||||
/// <param name="gameObject">The game object from which to move the component.</param>
|
||||
/// <param name="target">The game object to which the component will be moved.</param>
|
||||
/// <typeparam name="T">The type of the component to copy.</typeparam>
|
||||
/// <exception cref="ArgumentNullException">
|
||||
/// <para><paramref name="gameObject" /> is <see langword="null" />.</para>
|
||||
/// -or-
|
||||
/// <para><paramref name="target" /> is <see langword="null" />.</para>
|
||||
/// </exception>
|
||||
/// <exception cref="InvalidOperationException">
|
||||
/// <para><paramref name="gameObject" /> does not have a component of type <typeparamref name="T" />.</para>
|
||||
/// -or-
|
||||
/// <para><paramref name="target" /> already has a component of type <typeparamref name="T" />.</para>
|
||||
/// </exception>
|
||||
/// <remarks>
|
||||
/// This method will destroy the component on the source game object, creating a new instance on the target. Use with
|
||||
/// caution.
|
||||
/// </remarks>
|
||||
public static void MoveComponent<T>(this GameObject gameObject, GameObject target)
|
||||
where T : Component
|
||||
{
|
||||
if (gameObject == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(gameObject));
|
||||
}
|
||||
|
||||
if (target == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(target));
|
||||
}
|
||||
|
||||
if (!gameObject.TryGetComponent(out T sourceComponent))
|
||||
{
|
||||
string message = ExceptionMessages.ComponentDoesNotExist;
|
||||
message = string.Format(CultureInfo.CurrentCulture, message, gameObject.name, typeof(T).Name);
|
||||
throw new InvalidOperationException(message);
|
||||
}
|
||||
|
||||
sourceComponent.MoveTo(target);
|
||||
Object.Destroy(sourceComponent);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Moves the component of the specified type from one game object to another.
|
||||
/// </summary>
|
||||
/// <param name="gameObject">The game object from which to move the component.</param>
|
||||
/// <param name="componentType">The type of the component to copy.</param>
|
||||
/// <param name="target">The game object to which the component will be moved.</param>
|
||||
/// <exception cref="ArgumentNullException">
|
||||
/// <para><paramref name="gameObject" /> is <see langword="null" />.</para>
|
||||
/// -or-
|
||||
/// <para><paramref name="componentType" /> is <see langword="null" />.</para>
|
||||
/// -or-
|
||||
/// <para><paramref name="target" /> is <see langword="null" />.</para>
|
||||
/// </exception>
|
||||
/// <exception cref="InvalidOperationException">
|
||||
/// <para><paramref name="gameObject" /> does not have a component of type <paramref name="componentType" />.</para>
|
||||
/// -or-
|
||||
/// <para><paramref name="target" /> already has a component of type <paramref name="componentType" />.</para>
|
||||
/// </exception>
|
||||
/// <remarks>
|
||||
/// This method will destroy the component on the source game object, creating a new instance on the target. Use with
|
||||
/// caution.
|
||||
/// </remarks>
|
||||
public static void MoveComponent(this GameObject gameObject, Type componentType, GameObject target)
|
||||
{
|
||||
if (gameObject == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(gameObject));
|
||||
}
|
||||
|
||||
if (componentType is null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(componentType));
|
||||
}
|
||||
|
||||
if (target == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(target));
|
||||
}
|
||||
|
||||
if (!gameObject.TryGetComponent(componentType, out Component sourceComponent))
|
||||
{
|
||||
string message = ExceptionMessages.ComponentDoesNotExist;
|
||||
message = string.Format(CultureInfo.CurrentCulture, message, gameObject.name, componentType.Name);
|
||||
throw new InvalidOperationException(message);
|
||||
}
|
||||
|
||||
sourceComponent.MoveTo(target);
|
||||
Object.Destroy(sourceComponent);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the new layer of this game object and its children, recursively.
|
||||
/// </summary>
|
||||
|
Loading…
Reference in New Issue
Block a user