using System;
using UnityEngine;
using UnityObject = UnityEngine.Object;
namespace Chronos.Reflection
{
[Serializable]
public abstract class UnityMember
{
[SerializeField]
private UnityObject _target;
///
/// The object containing the member.
///
public UnityObject target
{
get { return _target; }
set { _target = value; isTargeted = false; }
}
[SerializeField]
private string _component;
///
/// The name of the component containing the member, if the target is a GameObject.
///
public string component
{
get { return _component; }
set { _component = value; isTargeted = false; isReflected = false; }
}
[SerializeField]
private string _name;
///
/// The name of the member.
///
public string name
{
get { return _name; }
set { _name = value; isReflected = false; }
}
///
/// Indicates whether the reflection target has been found and cached.
///
protected bool isTargeted { get; private set; }
///
/// Indicates whether the reflection data has been found and cached.
///
public bool isReflected { get; protected set; }
///
/// Indicates whether the member has been properly assigned.
///
public bool isAssigned
{
get
{
return target != null && !string.IsNullOrEmpty(name);
}
}
///
/// The object on which to perform reflection.
/// For GameObjects and Component targets, this is the component of type or the object itself if null.
/// For ScriptableObjects targets, this is the object itself.
/// Other Unity Objects are not supported.
///
protected UnityObject reflectionTarget { get; private set; }
#region Constructors
public UnityMember() { }
public UnityMember(string name)
{
this.name = name;
}
public UnityMember(string name, UnityObject target)
{
this.name = name;
this.target = target;
Reflect();
}
public UnityMember(string component, string name)
{
this.component = component;
this.name = name;
}
public UnityMember(string component, string name, UnityObject target)
{
this.component = component;
this.name = name;
this.target = target;
Reflect();
}
#endregion
///
/// Gathers and caches the reflection target for the member.
///
protected void Target()
{
if (target == null)
{
throw new NullReferenceException("Target has not been specified.");
}
GameObject targetAsGameObject = target as GameObject;
Component targetAsComponent = target as Component;
if (targetAsGameObject != null || targetAsComponent != null)
{
// The target is a GameObject or a Component.
if (!string.IsNullOrEmpty(component))
{
// If a component is specified, look for it on the target.
Component componentObject;
if (targetAsGameObject != null)
{
componentObject = targetAsGameObject.GetComponent(component);
}
else // if (targetAsComponent != null)
{
componentObject = targetAsComponent.GetComponent(component);
}
if (componentObject == null)
{
throw new UnityReflectionException(string.Format("Target object does not contain a component of type '{0}'.", component));
}
reflectionTarget = componentObject;
return;
}
else
{
// Otherwise, return the GameObject itself.
if (targetAsGameObject != null)
{
reflectionTarget = targetAsGameObject;
}
else // if (targetAsComponent != null)
{
reflectionTarget = targetAsComponent.gameObject;
}
return;
}
}
ScriptableObject scriptableObject = target as ScriptableObject;
if (scriptableObject != null)
{
// The real target is directly the ScriptableObject target.
reflectionTarget = scriptableObject;
return;
}
throw new UnityReflectionException("Target should be a GameObject, a Component or a ScriptableObject.");
}
///
/// Gathers and caches the reflection data for the member.
///
public abstract void Reflect();
///
/// Gathers the reflection data if it is not alreadypresent.
///
public void EnsureReflected()
{
if (!isReflected)
{
Reflect();
}
}
///
/// Gathers the reflection target if it is not already present.
///
public void EnsureTargeted()
{
if (!isTargeted)
{
Target();
}
}
///
/// Asserts that the member has been properly assigned.
///
public void EnsureAssigned()
{
if (!isAssigned)
{
throw new UnityReflectionException("Member hasn't been properly assigned.");
}
}
public virtual bool Corresponds(UnityMember other)
{
return
(other != null || !this.isAssigned) &&
this.target == other.target &&
this.component == other.component &&
this.name == other.name;
}
}
}