using System.Collections.Generic;
using UnityEngine;
using System.Reflection;
using System.Linq;
#if UNITY_EDITOR
using UnityEditor;
#endif
namespace Lightbug.Utilities
{
public enum Direction
{
Right,
Left,
Up,
Down,
Forward,
Back
}
///
/// This static class contains all kind of useful methods used across the package.
///
public static class CustomUtilities
{
public static Vector3 Add(Vector3 vectorA, Vector3 vectorB)
{
vectorA.x += vectorB.x;
vectorA.y += vectorB.y;
return vectorA;
}
public static Vector3 Substract(Vector3 vectorA, Vector3 vectorB)
{
vectorA.x -= vectorB.x;
vectorA.y -= vectorB.y;
return vectorA;
}
public static Vector3 Multiply(Vector3 vectorValue, float floatValue)
{
vectorValue.x *= floatValue;
vectorValue.y *= floatValue;
vectorValue.z *= floatValue;
return vectorValue;
}
public static Vector3 Multiply(Vector3 vectorValue, float floatValueA, float floatValueB)
{
vectorValue.x *= floatValueA * floatValueB;
vectorValue.y *= floatValueA * floatValueB;
vectorValue.z *= floatValueA * floatValueB;
return vectorValue;
}
public static void AddMagnitude(ref Vector3 vector, float magnitude)
{
if (vector == Vector3.zero)
return;
float vectorMagnitude = Vector3.Magnitude(vector);
Vector3 vectorDirection = vector / vectorMagnitude;
vector += vectorDirection * magnitude;
}
public static void ChangeMagnitude(ref Vector3 vector, float magnitude)
{
if (vector == Vector3.zero)
return;
Vector3 vectorDirection = Vector3.Normalize(vector);
vector = vectorDirection * magnitude;
}
public static void ChangeDirection(ref Vector3 vector, Vector3 direction)
{
if (vector == Vector3.zero)
return;
float vectorMagnitude = Vector3.Magnitude(vector);
vector = direction * vectorMagnitude;
}
public static void ChangeDirectionOntoPlane(ref Vector3 vector, Vector3 planeNormal)
{
if (vector == Vector3.zero)
return;
Vector3 direction = Vector3.Normalize(Vector3.ProjectOnPlane(vector, planeNormal));
float vectorMagnitude = Vector3.Magnitude(vector);
vector = direction * vectorMagnitude;
}
public static void GetMagnitudeAndDirection(this Vector3 vector, out Vector3 direction, out float magnitude)
{
magnitude = Vector3.Magnitude(vector);
direction = Vector3.Normalize(vector);
}
///
/// Projects an input vector onto the tangent of a given plane (defined by its normal).
///
public static Vector3 ProjectOnTangent(Vector3 inputVector, Vector3 planeNormal, Vector3 up)
{
Vector3 inputVectorDirection = Vector3.Normalize(inputVector);
if (inputVectorDirection == -up)
{
inputVector += planeNormal * 0.01f;
}
else if (inputVectorDirection == up)
{
return Vector3.zero;
}
Vector3 rotationAxis = GetPerpendicularDirection(inputVector, up);
Vector3 tangent = GetPerpendicularDirection(planeNormal, rotationAxis);
return Multiply(tangent, Vector3.Magnitude(inputVector));
}
///
/// Projects an input vector onto plane A and plane B orthonormal direction.
///
public static Vector3 DeflectVector(Vector3 inputVector, Vector3 planeA, Vector3 planeB, bool maintainMagnitude = false)
{
Vector3 direction = GetPerpendicularDirection(planeA, planeB);
if (maintainMagnitude)
return direction * inputVector.magnitude;
else
return Vector3.Project(inputVector, direction);
}
public static Vector3 GetPerpendicularDirection(Vector3 vectorA, Vector3 vectorB)
{
return Vector3.Normalize(Vector3.Cross(vectorA, vectorB));
}
public static float GetTriangleValue(float center, float height, float width, float independentVariable, float minIndependentVariableLimit = Mathf.NegativeInfinity, float maxIndependentVariableLimit = Mathf.Infinity)
{
float minValue = center - width / 2f;
float maxValue = center + width / 2f;
if (independentVariable < minValue || independentVariable > maxValue)
{
return 0f;
}
else if (independentVariable < center)
{
return height * (independentVariable - minValue) / (center - minValue);
}
else
{
return -height * (independentVariable - center) / (maxValue - center) + height;
}
}
///
/// Makes a value greater than or equal to zero (default value).
///
public static void SetPositive(ref T value) where T : System.IComparable
{
SetMin(ref value, default(T));
}
///
/// Makes a value less than or equal to zero (default value).
///
public static void SetNegative(ref T value) where T : System.IComparable
{
SetMax(ref value, default(T));
}
///
/// Makes a value greater than or equal to a minimum value.
///
public static void SetMin(ref T value, T minValue) where T : System.IComparable
{
bool isLess = value.CompareTo(minValue) < 0;
if (isLess)
value = minValue;
}
///
/// Makes a value less than or equal to a maximum value.
///
public static void SetMax(ref T value, T maxValue) where T : System.IComparable
{
bool isGreater = value.CompareTo(maxValue) > 0;
if (isGreater)
value = maxValue;
}
///
/// Limits a value range from a minimum value to a maximum value (similar to Mathf.Clamp).
///
public static void SetRange(ref T value, T minValue, T maxValue) where T : System.IComparable
{
SetMin(ref value, minValue);
SetMax(ref value, maxValue);
}
///
/// Returns true if the target value is between a and b ( both exclusive ).
/// To include the limits values set the "inclusive" parameter to true.
///
public static bool isBetween(float target, float a, float b, bool inclusive = false)
{
if (b > a)
return (inclusive ? target >= a : target > a) && (inclusive ? target <= b : target < b);
else
return (inclusive ? target >= b : target > b) && (inclusive ? target <= a : target < a);
}
///
/// Returns true if the target value is between a and b ( both exclusive ).
/// To include the limits values set the "inclusive" parameter to true.
///
public static bool isBetween(int target, int a, int b, bool inclusive = false)
{
if (b > a)
return (inclusive ? target >= a : target > a) && (inclusive ? target <= b : target < b);
else
return (inclusive ? target >= b : target > b) && (inclusive ? target <= a : target < a);
}
public static bool isCloseTo(Vector3 input, Vector3 target, float tolerance)
{
return Vector3.Distance(input, target) <= tolerance;
}
public static bool isCloseTo(float input, float target, float tolerance)
{
return Mathf.Abs(target - input) <= tolerance;
}
public static Vector3 TransformVectorUnscaled(this Transform transform, Vector3 vector)
{
return transform.rotation * vector;
}
public static Vector3 InverseTransformVectorUnscaled(this Transform transform, Vector3 vector)
{
return Quaternion.Inverse(transform.rotation) * vector;
}
public static Vector3 RotatePointAround(Vector3 point, Vector3 center, float angle, Vector3 axis)
{
Quaternion rotation = Quaternion.AngleAxis(angle, axis);
Vector3 pointToCenter = center - point;
Vector3 rotatedPointToCenter = rotation * pointToCenter;
return center - rotatedPointToCenter;
}
public static T GetOrAddComponent(this GameObject targetGameObject, bool includeChildren = false) where T : Component
{
T existingComponent = includeChildren ? targetGameObject.GetComponentInChildren() : targetGameObject.GetComponent();
if (existingComponent != null)
{
return existingComponent;
}
T component = targetGameObject.AddComponent();
return component;
}
///
/// Gets a "target" component within a particular branch (inside the hierarchy). The branch is defined by the "branch root object", which is also defined by the chosen
/// "branch root component". The returned component must come from a child of the "branch root object".
///
///
/// Include inactive objects?
/// Branch root component type.
/// Target component type.
/// The target component.
public static T2 GetComponentInBranch(this Component callerComponent, bool includeInactive = true) where T1 : Component where T2 : Component
{
T1[] rootComponents = callerComponent.transform.root.GetComponentsInChildren(includeInactive);
if (rootComponents.Length == 0)
{
Debug.LogWarning($"Root component: No objects found with {typeof(T1).Name} component");
return null;
}
for (int i = 0; i < rootComponents.Length; i++)
{
T1 rootComponent = rootComponents[i];
// Is the caller a child of this root?
if (!callerComponent.transform.IsChildOf(rootComponent.transform) && !rootComponent.transform.IsChildOf(callerComponent.transform))
continue;
T2 targetComponent = rootComponent.GetComponentInChildren(includeInactive);
if (targetComponent == null)
continue;
return targetComponent;
}
return null;
}
///
/// Gets a "target" component within a particular branch (inside the hierarchy). The branch is defined by the "branch root object", which is also defined by the chosen
/// "branch root component". The returned component must come from a child of the "branch root object".
///
///
/// Include inactive objects?
/// Target component type.
/// The target component.
public static T1 GetComponentInBranch(this Component callerComponent, bool includeInactive = true) where T1 : Component
{
return callerComponent.GetComponentInBranch(includeInactive);
}
public static bool IsNullOrEmpty(this string target)
{
return target == null || target.Length == 0;
}
public static bool IsNullOrWhiteSpace(this string target)
{
if (target == null)
return true;
for (int i = 0; i < target.Length; i++)
{
if (target[i] != ' ')
return false;
}
return true;
}
public static string Between(this string targetString, string firstString, string lastString)
{
int start = targetString.IndexOf(firstString) + firstString.Length;
int end = targetString.IndexOf(lastString);
if (end - start < 0)
return "";
return targetString.Substring(start, end - start);
}
public static bool BelongsToLayerMask(int layer, int layerMask)
{
return (layerMask & (1 << layer)) > 0;
}
public static T1 GetOrAddComponent(this GameObject gameObject) where T1 : Component
{
if (!gameObject.TryGetComponent(out T1 component))
component = gameObject.AddComponent();
return component;
}
public static T1 GetOrAddComponent(this GameObject gameObject) where T1 : Component where T2 : Component
{
if (!gameObject.TryGetComponent(out T1 component))
{
if (gameObject.TryGetComponent(out T2 requiredComponent))
component = gameObject.AddComponent();
}
return component;
}
public static T1 GetOrAddComponent(this Component baseComponent) where T1 : Component
{
if (!baseComponent.TryGetComponent(out T1 component))
component = baseComponent.gameObject.AddComponent();
return component;
}
public static T1 GetOrAddComponent(this Component baseComponent) where T1 : Component where T2 : Component
{
if (!baseComponent.TryGetComponent(out T1 component))
{
if (baseComponent.TryGetComponent(out T2 requiredComponent))
component = baseComponent.gameObject.AddComponent();
}
return component;
}
public static T1 GetOrAddComponent(this Component baseComponent, T2 requiredComponentType) where T1 : Component where T2 : System.Type
{
if (!baseComponent.TryGetComponent(out T1 component))
{
if (baseComponent.TryGetComponent(out T2 requiredComponent))
component = (T1)baseComponent.gameObject.AddComponent(requiredComponentType);
}
return component;
}
///
/// Gets a particular value from this dictionary. If the value isn't there, it gets added.
///
/// Key type.
/// Value type.
/// A dictionary container.
/// The key parameter
/// Indicates if the component should be added if it doesn't exist.
///
public static T2 GetOrRegisterValue(this Dictionary dictionary, T1 key, bool addIfNull = false) where T1 : Component where T2 : Component
{
if (key == null)
return null;
bool found = dictionary.TryGetValue(key, out T2 value);
if (!found)
{
value = addIfNull ? key.gameObject.GetOrAddComponent() : key.GetComponent();
if (value != null)
dictionary.Add(key, value);
}
return value;
}
///
/// Gets a particular value from this dictionary. If the value isn't there, it gets added.
///
/// Key type.
/// Value type.
/// Required component type.
/// A dictionary container.
/// The key parameter
/// Indicates if the component should be added if it doesn't exist and the
/// required component exist.
///
public static T2 GetOrRegisterValue(this Dictionary dictionary, T1 key, bool addIfNull = false) where T1 : Component where T2 : Component where T3 : Component
{
if (key == null)
return null;
bool found = dictionary.TryGetValue(key, out T2 value);
if (!found)
{
value = addIfNull ? key.gameObject.GetOrAddComponent() : key.GetComponent();
if (value != null)
dictionary.Add(key, value);
}
return value;
}
public static float SignedAngle(Vector3 from, Vector3 to, Vector3 axis)
{
float angle = Vector3.Angle(from, to);
Vector3 cross = Vector3.Cross(from, to);
cross.Normalize();
float sign = cross == axis ? 1f : -1f;
return sign * angle;
}
public static void DebugRay(Vector3 point, Vector3 direction = default(Vector3), float duration = 2f, Color color = default(Color))
{
Vector3 drawDirection = direction == default(Vector3) ? Vector3.up : direction;
Color drawColor = color == default(Color) ? Color.blue : color;
Debug.DrawRay(point, drawDirection, drawColor, duration);
}
public static void DrawArrowGizmo(Vector3 start, Vector3 end, Color color, float radius = 0.25f)
{
Gizmos.color = color;
Gizmos.DrawLine(start, end);
Gizmos.DrawRay(
end,
Quaternion.AngleAxis(45, Vector3.forward) * Vector3.Normalize(start - end) * radius
);
Gizmos.DrawRay(
end,
Quaternion.AngleAxis(-45, Vector3.forward) * Vector3.Normalize(start - end) * radius
);
}
public static void DrawGizmoCross(Vector3 point, float radius, Color color)
{
Gizmos.color = color;
Gizmos.DrawRay(
point + Vector3.up * 0.5f * radius,
Vector3.down * radius
);
Gizmos.DrawRay(
point + Vector3.right * 0.5f * radius,
Vector3.left * radius
);
}
public static void DrawDebugCross(Vector3 point, float radius, Color color, float angleOffset = 0f)
{
Debug.DrawRay(
point + Quaternion.Euler(0, 0, angleOffset) * Vector3.up * 0.5f * radius,
Quaternion.Euler(0, 0, angleOffset) * Vector3.down * radius,
color
);
Debug.DrawRay(
point + Quaternion.Euler(0, 0, angleOffset) * Vector3.right * 0.5f * radius,
Quaternion.Euler(0, 0, angleOffset) * Vector3.left * radius,
color
);
}
#region Animator
///
/// Gets the current clip effective length, that is, the original length divided by the playback speed. The length value is always positive, regardless of the speed sign.
/// It returns false if the clip is not valid.
///
public static bool GetCurrentClipLength(this Animator animator, ref float length)
{
if (animator.runtimeAnimatorController == null)
return false;
AnimatorClipInfo[] clipInfo = animator.GetCurrentAnimatorClipInfo(0);
if (clipInfo.Length == 0)
return false;
float clipLength = clipInfo[0].clip.length;
float speed = animator.GetCurrentAnimatorStateInfo(0).speed;
length = Mathf.Abs(clipLength / speed);
return true;
}
public static bool MatchTarget(this Animator animator, Vector3 targetPosition, Quaternion targetRotation, AvatarTarget avatarTarget, float startNormalizedTime, float targetNormalizedTime)
{
if (animator.runtimeAnimatorController == null)
return false;
if (animator.isMatchingTarget)
return false;
if (animator.IsInTransition(0))
return false;
MatchTargetWeightMask weightMask = new MatchTargetWeightMask(Vector3.one, 1f);
animator.MatchTarget(
targetPosition,
targetRotation,
avatarTarget,
weightMask,
startNormalizedTime,
targetNormalizedTime
);
return true;
}
public static bool MatchTarget(this Animator animator, Vector3 targetPosition, AvatarTarget avatarTarget, float startNormalizedTime, float targetNormalizedTime)
{
if (animator.runtimeAnimatorController == null)
return false;
if (animator.isMatchingTarget)
return false;
if (animator.IsInTransition(0))
return false;
MatchTargetWeightMask weightMask = new MatchTargetWeightMask(Vector3.one, 0f);
animator.MatchTarget(
targetPosition,
Quaternion.identity,
avatarTarget,
weightMask,
startNormalizedTime,
targetNormalizedTime
);
return true;
}
public static bool MatchTarget(this Animator animator, Transform target, AvatarTarget avatarTarget, float startNormalizedTime, float targetNormalizedTime)
{
if (animator.runtimeAnimatorController == null)
return false;
if (animator.isMatchingTarget)
return false;
if (animator.IsInTransition(0))
return false;
MatchTargetWeightMask weightMask = new MatchTargetWeightMask(Vector3.one, 1f);
animator.MatchTarget(
target.position,
target.rotation,
avatarTarget,
weightMask,
startNormalizedTime,
targetNormalizedTime
);
return true;
}
public static bool MatchTarget(this Animator animator, Transform target, AvatarTarget avatarTarget, float startNormalizedTime, float targetNormalizedTime, MatchTargetWeightMask weightMask)
{
if (animator.runtimeAnimatorController == null)
return false;
if (animator.isMatchingTarget)
return false;
if (animator.IsInTransition(0))
return false;
animator.MatchTarget(
target.position,
target.rotation,
AvatarTarget.Root,
weightMask,
startNormalizedTime,
targetNormalizedTime
);
return true;
}
#endregion
// ─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
// ─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
// ─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
#if UNITY_EDITOR
public static List FindInterfaces()
{
List interfaces = new List();
GameObject[] rootGameObjects = UnityEngine.SceneManagement.SceneManager.GetActiveScene().GetRootGameObjects();
foreach (var rootGameObject in rootGameObjects)
{
T[] childrenInterfaces = rootGameObject.GetComponentsInChildren();
foreach (T childInterface in childrenInterfaces)
{
interfaces.Add(childInterface);
}
}
return interfaces;
}
public static MethodInfo[] GetMethods(this MonoBehaviour monoBehaviour)
{
MonoScript monoScript = MonoScript.FromMonoBehaviour(monoBehaviour);
MethodInfo[] methods = monoScript.GetClass().GetMethods();
return methods;
}
public static MethodInfo[] GetMethods(this ScriptableObject scriptableObject)
{
MonoScript monoScript = MonoScript.FromScriptableObject(scriptableObject);
MethodInfo[] methods = monoScript.GetClass().GetMethods();
return methods;
}
public static System.Type[] GetAllDerivedObjects(bool allowAbstract = true) where T : Component
{
List result = new List();
var assemblies = System.AppDomain.CurrentDomain.GetAssemblies();
foreach (var assembly in assemblies)
{
var types = assembly.GetTypes();
foreach (var type in types)
{
if (type.IsSubclassOf(typeof(T)))
{
if (type.IsAbstract)
{
if (allowAbstract)
result.Add(type);
}
else
{
result.Add(type);
}
}
}
}
return result.ToArray();
}
public static T GetInterface(this MonoBehaviour monoBehaviour)
{
T[] walkInterfaces = monoBehaviour.GetComponents();
for (int i = 0; i < walkInterfaces.Length; i++)
{
T @interface = walkInterfaces[i];
Object interfaceObject = @interface as object as Object;
if (interfaceObject == monoBehaviour)
return @interface;
}
return default(T);
}
public static System.Type[] GetAllDerivedComponents(System.Type componentType, bool allowAbstract = true)
{
if (!componentType.IsSubclassOf(typeof(Component)))
return null;
List result = new List();
var assemblies = System.AppDomain.CurrentDomain.GetAssemblies();
foreach (var assembly in assemblies)
{
var types = assembly.GetTypes();
foreach (var type in types)
{
if (type.IsSubclassOf(componentType))
{
if (type.IsAbstract)
{
if (allowAbstract)
result.Add(type);
}
else
{
result.Add(type);
}
}
}
}
return result.ToArray();
}
public static System.Type[] GetAllDerivedObjectsClass(bool allowAbstract = true) where T : class
{
List result = new List();
var assemblies = System.AppDomain.CurrentDomain.GetAssemblies();
foreach (var assembly in assemblies)
{
var types = assembly.GetTypes();
foreach (var type in types)
{
if (type.IsSubclassOf(typeof(T)))
{
if (type.IsAbstract)
{
if (allowAbstract)
result.Add(type);
}
else
{
result.Add(type);
}
}
}
}
return result.ToArray();
}
public static void DrawMonoBehaviourField(T target) where T : MonoBehaviour
{
GUI.enabled = false;
EditorGUILayout.ObjectField("Script:", MonoScript.FromMonoBehaviour(target), typeof(T), false);
GUI.enabled = true;
}
public static void DrawScriptableObjectField(T target) where T : ScriptableObject
{
GUI.enabled = false;
EditorGUILayout.ObjectField("Script:", MonoScript.FromScriptableObject(target), typeof(T), false);
GUI.enabled = true;
}
public static void DrawEditorLayoutHorizontalLine(Color color, int thickness = 1, int padding = 10)
{
Rect rect = EditorGUILayout.GetControlRect(GUILayout.Height(padding + thickness));
rect.height = thickness;
rect.y += padding / 2;
//rect.x -= 2;
//rect.width +=6;
EditorGUI.DrawRect(rect, color);
}
public static void DrawEditorHorizontalLine(ref Rect rect, Color color, int thickness = 1, int padding = 10)
{
rect.height = thickness;
rect.y += padding / 2;
//rect.x -= 2;
//rect.width +=6;
EditorGUI.DrawRect(rect, color);
rect.y += padding;
rect.height = EditorGUIUtility.singleLineHeight;
}
public static void DrawWireCapsule(Vector3 position, Quaternion rotation, float radius, float height, Color color = default(Color))
{
if (color != default(Color))
Handles.color = color;
Matrix4x4 angleMatrix = Matrix4x4.TRS(position, rotation, Handles.matrix.lossyScale);
using (new Handles.DrawingScope(angleMatrix))
{
var pointOffset = (height - (radius * 2)) / 2;
//draw sideways
Handles.DrawWireArc(Vector3.up * pointOffset, Vector3.left, Vector3.back, -180, radius);
Handles.DrawLine(new Vector3(0, pointOffset, -radius), new Vector3(0, -pointOffset, -radius));
Handles.DrawLine(new Vector3(0, pointOffset, radius), new Vector3(0, -pointOffset, radius));
Handles.DrawWireArc(Vector3.down * pointOffset, Vector3.left, Vector3.back, 180, radius);
//draw frontways
Handles.DrawWireArc(Vector3.up * pointOffset, Vector3.back, Vector3.left, 180, radius);
Handles.DrawLine(new Vector3(-radius, pointOffset, 0), new Vector3(-radius, -pointOffset, 0));
Handles.DrawLine(new Vector3(radius, pointOffset, 0), new Vector3(radius, -pointOffset, 0));
Handles.DrawWireArc(Vector3.down * pointOffset, Vector3.back, Vector3.left, -180, radius);
//draw center
Handles.DrawWireDisc(Vector3.up * pointOffset, Vector3.up, radius);
Handles.DrawWireDisc(Vector3.down * pointOffset, Vector3.up, radius);
}
}
public static void DrawArray(SerializedProperty rootProperty, string namePropertyString = null, bool showAddElement = true, bool removeIconToTheRight = true)
{
if (!rootProperty.isArray)
return;
for (int i = 0; i < rootProperty.arraySize; i++)
{
SerializedProperty item = rootProperty.GetArrayElementAtIndex(i);
item.isExpanded = true;
GUILayout.BeginVertical(EditorStyles.helpBox);
// if( removeIconToTheRight )
// GUILayout.BeginHorizontal();
CustomUtilities.DrawArrayElement(item, namePropertyString);
GUILayout.Space(20);
if (GUILayout.Button("Remove element", EditorStyles.miniButton))
{
rootProperty.DeleteArrayElementAtIndex(i);
break;
}
// if( removeIconToTheRight )
// GUILayout.EndHorizontal();
GUILayout.EndVertical();
GUILayout.Space(20);
}
if (showAddElement)
if (GUILayout.Button("Add element"))
rootProperty.arraySize++;
}
public static void DrawArrayElement(SerializedProperty property, string namePropertyString = null, bool skipFirstChild = false)
{
// if( property.isArray )
// return;
EditorGUI.indentLevel++;
SerializedProperty nameProperty = null;
if (namePropertyString != null)
{
nameProperty = property.FindPropertyRelative(namePropertyString);
if (nameProperty != null)
{
string name = nameProperty.stringValue;
EditorGUILayout.LabelField(name, EditorStyles.boldLabel);
}
EditorGUI.indentLevel++;
}
SerializedProperty itr = property.Copy();
bool enterChildren = true;
while (itr.Next(enterChildren))
{
if (SerializedProperty.EqualContents(itr, property.GetEndProperty()))
break;
if (enterChildren && skipFirstChild)
{
enterChildren = false;
continue;
}
EditorGUILayout.PropertyField(itr, enterChildren);
enterChildren = false;
}
EditorGUI.indentLevel = nameProperty != null ? EditorGUI.indentLevel - 2 : EditorGUI.indentLevel - 1;
}
public static void DrawArrayElement(Rect rect, SerializedProperty property, string namePropertyString = null, bool skipFirstChild = false)
{
if (property.isArray)
return;
EditorGUI.indentLevel++;
SerializedProperty nameProperty = null;
if (namePropertyString != null)
{
nameProperty = property.FindPropertyRelative(namePropertyString);
if (nameProperty != null)
{
string name = nameProperty.stringValue;
EditorGUI.LabelField(rect, name, EditorStyles.boldLabel);
rect.y += rect.height;
}
EditorGUI.indentLevel++;
}
SerializedProperty itr = property.Copy();
bool enterChildren = true;
while (itr.Next(enterChildren))
{
if (SerializedProperty.EqualContents(itr, property.GetEndProperty()))
break;
if (enterChildren && skipFirstChild)
{
enterChildren = false;
continue;
}
EditorGUI.PropertyField(rect, itr, enterChildren);
rect.y += rect.height;
enterChildren = false;
}
EditorGUI.indentLevel = nameProperty != null ? EditorGUI.indentLevel - 2 : EditorGUI.indentLevel - 1;
}
#endif
}
}