using System;
using System.Collections.Generic;
using System.Linq;
using UnityEditor;
using UnityEngine;
using UnityEngine.Serialization;
namespace Unity.Tutorials.Core.Editor
{
///
/// Criterion for checking that specific Components are added to a GameObject.
///
public class ComponentAddedCriterion : Criterion
{
[SerializeField, FormerlySerializedAs("targetGameObject")]
ObjectReference m_TargetGameObject;
[SerializeField, FormerlySerializedAs("requiredComponents")]
SerializedTypeCollection m_RequiredComponents = new SerializedTypeCollection();
///
/// Returns the target GameObject.
///
public GameObject TargetGameObject
{
get
{
if (m_TargetGameObject == null)
return null;
return m_TargetGameObject.SceneObjectReference.ReferencedObjectAsGameObject;
}
set
{
if (m_TargetGameObject == null)
m_TargetGameObject = new ObjectReference();
m_TargetGameObject.SceneObjectReference.Update(value);
}
}
///
/// Returns the required Components.
///
public IList RequiredComponents
{
get
{
return m_RequiredComponents.Select(typeAndFutureReference => typeAndFutureReference.SerializedType.Type)
.ToList();
}
set
{
var items = value.Select(type => new TypeAndFutureReference(new SerializedType(type))).ToList();
m_RequiredComponents.SetItems(items);
OnValidate();
}
}
///
/// Starts testing of the criterion.
///
public override void StartTesting()
{
UpdateCompletion();
EditorApplication.update += UpdateCompletion;
}
///
/// Stops testing of the criterion.
///
public override void StopTesting()
{
EditorApplication.update -= UpdateCompletion;
}
///
/// Destroys unused future reference assets and updates future references.
///
protected override void OnValidate()
{
// Destroy unused future reference assets
base.OnValidate();
// Update future references
var requiredComponentsIndex = 0;
foreach (var typeAndFutureReference in m_RequiredComponents)
{
requiredComponentsIndex++;
var type = typeAndFutureReference.SerializedType.Type;
if (type == null)
continue;
if (typeAndFutureReference.FutureReference == null)
typeAndFutureReference.FutureReference = CreateFutureObjectReference();
typeAndFutureReference.FutureReference.ReferenceName = string.Format("{0}: {1}",
requiredComponentsIndex, type.FullName);
}
if (requiredComponentsIndex != 0)
UpdateFutureObjectReferenceNames();
}
///
/// Evaluates if the criterion is completed.
///
///
protected override bool EvaluateCompletion()
{
var gameObject = TargetGameObject;
if (gameObject == null)
return false;
if (RequiredComponents.Count() == 0)
return true;
foreach (var type in RequiredComponents)
{
if (type == null)
{
Debug.LogWarning("Testing for a null component type will always fail.");
return false;
}
if (gameObject.GetComponent(type) == null)
return false;
}
// Update future references
foreach (var requiredType in m_RequiredComponents)
{
var component = gameObject.GetComponent(requiredType.SerializedType.Type);
requiredType.FutureReference.SceneObjectReference.Update(component);
}
return true;
}
///
/// Returns FutureObjectReference for this Criterion.
///
///
protected override IEnumerable GetFutureObjectReferences()
{
return m_RequiredComponents
.Where(c => c.SerializedType.Type != null && c.FutureReference != null)
.Select(c => c.FutureReference);
}
///
/// Auto-completes the criterion.
///
/// True if the auto-completion succeeded.
public override bool AutoComplete()
{
var gameObject = TargetGameObject;
if (gameObject == null)
return false;
foreach (var type in RequiredComponents)
{
var component = gameObject.AddComponent(type);
if (component == null)
return false;
}
return true;
}
///
/// Wrapper class for serialization purposes.
///
[Serializable]
public class SerializedTypeCollection : CollectionWrapper {}
///
/// A SerializedType-FutureObjectReference pair.
///
[Serializable]
public class TypeAndFutureReference : ICloneable
{
///
/// The SerializedType.
///
[SerializedTypeFilter(typeof(Component), false), FormerlySerializedAs("serializedType")]
public SerializedType SerializedType;
///
/// The FutureReference.
///
[FormerlySerializedAs("futureReference")]
public FutureObjectReference FutureReference;
///
/// Constructs from a SerializedType.
///
///
public TypeAndFutureReference(SerializedType serializedType)
{
this.SerializedType = serializedType;
}
///
/// Creates a clone of this instance.
///
///
public object Clone()
{
return new TypeAndFutureReference(SerializedType);
}
}
}
}