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 a specific amount of prefab instances are created.
///
public class PrefabInstanceCountCriterion : Criterion
{
///
/// Different comparison modes.
///
public enum InstanceCountComparison
{
///
/// At least X amount of instances required.
///
AtLeast,
///
/// Exactly X amount of instances required.
///
Exactly,
///
/// No more than X amount of instances required.
///
NoMoreThan,
}
///
/// The prefab of instances we want to count.
///
[FormerlySerializedAs("prefabParent")]
public GameObject PrefabParent;
///
/// The wanted comparison mode.
///
[FormerlySerializedAs("comparisonMode")]
public InstanceCountComparison ComparisonMode = InstanceCountComparison.AtLeast;
///
/// The desired amount of instances.
///
[Range(0, 100)]
[FormerlySerializedAs("instanceCount")]
public int InstanceCount = 1;
[SerializeField, HideInInspector]
FutureObjectReference m_FutureReference;
///
/// Starts testing of the criterion.
///
public override void StartTesting()
{
UpdateCompletion();
Selection.selectionChanged += UpdateCompletion;
}
///
/// Stops testing of the criterion.
///
public override void StopTesting()
{
Selection.selectionChanged -= UpdateCompletion;
}
///
/// Evaluates if the criterion is completed.
///
///
protected override bool EvaluateCompletion()
{
if (PrefabParent == null)
return false;
var matches = FindObjectsOfType().Where(go => PrefabUtilityShim.GetCorrespondingObjectFromSource(go) == PrefabParent);
var count = matches.Count();
switch (ComparisonMode)
{
case InstanceCountComparison.AtLeast:
return count >= InstanceCount;
case InstanceCountComparison.Exactly:
var complete = count == InstanceCount;
if (complete && InstanceCount == 1 && m_FutureReference != null)
m_FutureReference.SceneObjectReference.Update(matches.First());
return complete;
case InstanceCountComparison.NoMoreThan:
return count <= InstanceCount;
default:
return false;
}
}
///
/// Returns FutureObjectReference for this Criterion.
///
///
protected override IEnumerable GetFutureObjectReferences()
{
if (m_FutureReference == null)
yield break;
yield return m_FutureReference;
}
///
/// Destroys unused future reference assets and updates future references.
///
protected override void OnValidate()
{
// Destroy unreferenced future reference assets
base.OnValidate();
// Update future reference
var needsUpdate = false;
if (ComparisonMode == InstanceCountComparison.Exactly && InstanceCount == 1)
{
if (m_FutureReference == null)
{
m_FutureReference = CreateFutureObjectReference();
m_FutureReference.ReferenceName = "Prefab Instance";
needsUpdate = true;
}
}
else
DestroyImmediate(m_FutureReference, true);
if (needsUpdate)
UpdateFutureObjectReferenceNames();
}
///
/// Auto-completes the criterion.
///
/// True if the auto-completion succeeded.
public override bool AutoComplete()
{
var prefabInstances = FindObjectsOfType().Where(go => PrefabUtilityShim.GetCorrespondingObjectFromSource(go) == PrefabParent);
var actualInstanceCount = prefabInstances.Count();
var difference = actualInstanceCount - InstanceCount;
if (difference == 0)
return true;
switch (ComparisonMode)
{
case InstanceCountComparison.AtLeast:
difference = Math.Min(0, difference);
break;
case InstanceCountComparison.NoMoreThan:
difference = Math.Max(0, difference);
break;
}
if (difference < 0)
{
for (var i = 0; i < -difference; i++)
PrefabUtility.InstantiatePrefab(PrefabParent);
}
else
{
foreach (var prefabInstance in prefabInstances.Take(difference))
DestroyImmediate(prefabInstance);
}
return true;
}
}
}