You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

287 lines
9.3 KiB

using System;
using System.Collections.Generic;
using UnityEngine;
namespace BansheeGz.BGSpline.Curve
{
/// <summary>
/// Abstract superclass for components.
///
/// Current Requirements:
/// 1) editor should be extended from BGCcEditor
/// 2) Should have a descriptor.
/// 3) Only one RequireComponent of type BGCc (parent). Parent is another Cc component, this component is totally depends on and can not operate without it.
///
/// Cc stands for "Curve's component"
/// </summary>
[RequireComponent(typeof (BGCurve))]
public abstract class BGCc : MonoBehaviour
{
/// <summary>if component's parameters changed </summary>
public event EventHandler ChangedParams;
/// <summary>Any information Cc wants to provide (for editor)</summary>
public virtual string Info
{
get { return null; }
}
/// <summary>Warning (for editor)</summary>
public virtual string Warning
{
get { return null; }
}
/// <summary>Error if something is wrong (for editor)</summary>
public virtual string Error
{
get { return null; }
}
#if UNITY_EDITOR
// ============================================== !!! This is editor only field
#pragma warning disable 0414
//should CC's handles be shown in SceneView
[SerializeField] private bool showHandles = true;
#pragma warning restore 0414
#endif
/// <summary>Does this Cc supports handles in SceneView?</summary>
public virtual bool SupportHandles
{
get { return false; }
}
/// <summary>Does this Cc supports some adjustable settings for handles in SceneView?</summary>
public virtual bool SupportHandlesSettings
{
get { return false; }
}
//=============================================== Curve
private BGCurve curve;
public BGCurve Curve
{
get
{
//do not replace with ??
if (curve == null) curve = GetComponent<BGCurve>();
return curve;
}
}
//=============================================== Parent
//parent is another Cc component, this component is totally depends on and can not operate without it
[SerializeField] private BGCc parent;
public void SetParent(BGCc parent)
{
this.parent = parent;
}
public T GetParent<T>() where T : BGCc
{
return (T) GetParent(typeof (T));
}
public BGCc GetParent(Type type)
{
if (parent != null) return parent;
parent = (BGCc) GetComponent(type);
return parent;
}
//=============================================== Name
//you can name your Cc
[SerializeField] private string ccName;
public string CcName
{
get { return string.IsNullOrEmpty(ccName) ? "" + GetInstanceID() : ccName; }
set { ccName = value; }
}
//=============================================== Transaction
//transaction is for events grouping only
private int transactionLevel;
//=============================================== Descriptor
//descriptor is used to add icon, name and description to Cc
private CcDescriptor descriptor;
public CcDescriptor Descriptor
{
get
{
//do not replace with ??
if (descriptor == null) descriptor = GetDescriptor(GetType());
return descriptor;
}
}
// www page, containing help info
public virtual string HelpURL
{
get
{
var helpUrl = GetHelpUrl(GetType());
return helpUrl == null ? null : helpUrl.URL;
}
}
//=================================================== Unity Methods
public virtual void Start()
{
}
public virtual void OnDestroy()
{
}
//=================================================== Methods
//in case any param changed
protected bool ParamChanged<T>(ref T oldValue, T newValue)
{
var oldValueNull = oldValue == null;
var newValueNull = newValue == null;
if (oldValueNull && newValueNull) return false;
if (oldValueNull == newValueNull && oldValue.Equals(newValue)) return false;
oldValue = newValue;
FireChangedParams();
return true;
}
/// <summary> if component has an error</summary>
public bool HasError()
{
return !string.IsNullOrEmpty(Error);
}
/// <summary> if component has a warning</summary>
public bool HasWarning()
{
return !string.IsNullOrEmpty(Warning);
}
//utility method for chosing error message
protected string ChoseMessage(string baseError, Func<string> childError)
{
return !string.IsNullOrEmpty(baseError) ? baseError : childError();
}
/// <summary> if any parameter changed</summary>
public void FireChangedParams()
{
if (ChangedParams != null && transactionLevel == 0) ChangedParams(this, null);
}
/// <summary> component was added via editor menu</summary>
public virtual void AddedInEditor()
{
}
/// <summary> get parent Cc class</summary>
public Type GetParentClass()
{
return GetParentClass(GetType());
}
/// <summary> get parent Cc class</summary>
public static Type GetParentClass(Type ccType)
{
//gather required
var requiredList = BGReflectionAdapter.GetCustomAttributes(ccType, typeof (RequireComponent), true);
if (requiredList.Length == 0) return null;
var result = new List<Type>();
foreach (var item in requiredList)
{
var requiredComponent = (RequireComponent) item;
CheckRequired(requiredComponent.m_Type0, result);
CheckRequired(requiredComponent.m_Type1, result);
CheckRequired(requiredComponent.m_Type2, result);
}
if (result.Count == 0) return null;
if (result.Count > 1) throw new CcException(ccType + " has more than one parent (extended from BGCc class), calculated by RequireComponent attribute");
return result[0];
}
//add class if it's not abstract and a child of BGCc
private static void CheckRequired(Type type, List<Type> result)
{
if (type == null || BGReflectionAdapter.IsAbstract(type) || !BGReflectionAdapter.IsClass(type) || !BGReflectionAdapter.IsSubclassOf(type,typeof (BGCc)))return;
result.Add(type);
}
/// <summary> Check standard Unity's DisallowMultipleComponent attribute </summary>
public static bool IsSingle(Type ccType)
{
return BGReflectionAdapter.GetCustomAttributes(ccType, typeof(DisallowMultipleComponent), true).Length > 0;
}
/// <summary> This is used to group events. Use it to change several params and fire one single event</summary>
public void Transaction(Action action)
{
transactionLevel++;
try
{
action();
}
finally
{
transactionLevel--;
if (transactionLevel == 0)
{
if (ChangedParams != null) ChangedParams(this, null);
}
}
}
//======================== descriptor for Editor
/// <summary>this descriptor is used by editor</summary>
[AttributeUsage(AttributeTargets.Class)]
public class CcDescriptor : Attribute
{
/// <summary>Component's name</summary>
public string Name { get; set; }
/// <summary>Component's desciption</summary>
public string Description { get; set; }
/// <summary>Component's icon</summary>
public string Image { get; set; }
}
/// <summary>Retrieves the descriptor from "type"</summary>
public static CcDescriptor GetDescriptor(Type type)
{
var propertyInfos = BGReflectionAdapter.GetCustomAttributes(type, typeof(CcDescriptor), false);
if (propertyInfos.Length > 0) return (CcDescriptor) propertyInfos[0];
return null;
}
// get Unity's HelpURLAttribute attrubute
private static HelpURLAttribute GetHelpUrl(Type type)
{
var propertyInfos = BGReflectionAdapter.GetCustomAttributes(type,typeof (HelpURLAttribute), false);
if (propertyInfos.Length > 0) return (HelpURLAttribute) propertyInfos[0];
return null;
}
//======================== Exception
/// <summary>Exception if something is wrong with Cc related stuff</summary>
public class CcException :Exception
{
public CcException(string message) : base(message)
{
}
}
}
}