mirror of
https://github.com/bdunderscore/modular-avatar.git
synced 2025-01-31 02:32:53 +08:00
Add an internal class that tracks obj refs by path
This commit is contained in:
parent
ea2011f68d
commit
74c725e987
@ -0,0 +1,3 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: f83eeca568d546a3b9a1d313e84b91cf
|
||||||
|
timeCreated: 1664754610
|
@ -0,0 +1,121 @@
|
|||||||
|
using UnityEditor;
|
||||||
|
using UnityEngine;
|
||||||
|
|
||||||
|
namespace net.fushizen.modular_avatar.core.editor
|
||||||
|
{
|
||||||
|
[CustomPropertyDrawer(typeof(AvatarObjectReference))]
|
||||||
|
public class AvatarObjectReferenceDrawer : PropertyDrawer
|
||||||
|
{
|
||||||
|
public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
|
||||||
|
{
|
||||||
|
if (!CustomGUI(position, property, label))
|
||||||
|
{
|
||||||
|
var xButtonSize = EditorStyles.miniButtonRight.CalcSize(new GUIContent("x"));
|
||||||
|
var xButtonRect = new Rect(position.xMax - xButtonSize.x, position.y, xButtonSize.x, position.height);
|
||||||
|
position = new Rect(position.x, position.y, position.width - xButtonSize.x, position.height);
|
||||||
|
|
||||||
|
var isNull = property.FindPropertyRelative(nameof(AvatarObjectReference.isNull));
|
||||||
|
property = property.FindPropertyRelative(nameof(AvatarObjectReference.referencePath));
|
||||||
|
|
||||||
|
position = EditorGUI.PrefixLabel(position, label);
|
||||||
|
|
||||||
|
EditorGUI.LabelField(position, isNull.boolValue ? "(null)" : property.stringValue);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool CustomGUI(Rect position, SerializedProperty property, GUIContent label)
|
||||||
|
{
|
||||||
|
var indentLevel = EditorGUI.indentLevel;
|
||||||
|
var color = GUI.contentColor;
|
||||||
|
|
||||||
|
var isNull = property.FindPropertyRelative(nameof(AvatarObjectReference.isNull));
|
||||||
|
property = property.FindPropertyRelative(nameof(AvatarObjectReference.referencePath));
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// Find containing object, and from that the avatar
|
||||||
|
if (property.serializedObject == null || property.serializedObject.targetObjects.Length != 1)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
var obj = property.serializedObject.targetObject as Component;
|
||||||
|
if (obj == null) return false;
|
||||||
|
|
||||||
|
var transform = obj.transform;
|
||||||
|
var avatar = RuntimeUtil.FindAvatarInParents(transform);
|
||||||
|
if (avatar == null) return false;
|
||||||
|
|
||||||
|
var target = isNull.boolValue ? null : avatar.transform.Find(property.stringValue);
|
||||||
|
|
||||||
|
var labelRect = position;
|
||||||
|
position = EditorGUI.PrefixLabel(position, label);
|
||||||
|
labelRect.width = position.x - labelRect.x;
|
||||||
|
|
||||||
|
var nullContent = GUIContent.none;
|
||||||
|
|
||||||
|
if (target != null || isNull.boolValue)
|
||||||
|
{
|
||||||
|
EditorGUI.BeginChangeCheck();
|
||||||
|
var newTarget = EditorGUI.ObjectField(position, nullContent, target, typeof(Transform), true);
|
||||||
|
if (EditorGUI.EndChangeCheck())
|
||||||
|
{
|
||||||
|
if (newTarget == null)
|
||||||
|
{
|
||||||
|
property.stringValue = "";
|
||||||
|
isNull.boolValue = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var relPath =
|
||||||
|
RuntimeUtil.RelativePath(avatar.gameObject, ((Transform) newTarget).gameObject);
|
||||||
|
if (relPath == null) return true;
|
||||||
|
|
||||||
|
property.stringValue = relPath;
|
||||||
|
isNull.boolValue = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// For some reason, this color change retroactively affects the prefix label above, so draw our own
|
||||||
|
// label as well (we still want the prefix label for highlights, etc).
|
||||||
|
EditorGUI.LabelField(labelRect, label);
|
||||||
|
|
||||||
|
GUI.contentColor = new Color(0, 0, 0, 0);
|
||||||
|
EditorGUI.BeginChangeCheck();
|
||||||
|
var newTarget = EditorGUI.ObjectField(position, nullContent, target, typeof(Transform), true);
|
||||||
|
GUI.contentColor = color;
|
||||||
|
|
||||||
|
if (EditorGUI.EndChangeCheck())
|
||||||
|
{
|
||||||
|
if (newTarget == null)
|
||||||
|
{
|
||||||
|
property.stringValue = "";
|
||||||
|
isNull.boolValue = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var relPath =
|
||||||
|
RuntimeUtil.RelativePath(avatar.gameObject, ((Transform) newTarget).gameObject);
|
||||||
|
if (relPath == null) return true;
|
||||||
|
|
||||||
|
property.stringValue = relPath;
|
||||||
|
isNull.boolValue = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
GUI.contentColor = Color.red;
|
||||||
|
EditorGUI.LabelField(position, property.stringValue);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
GUI.contentColor = color;
|
||||||
|
EditorGUI.indentLevel = indentLevel;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,3 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 2a52bc46649d4cf6863b147a830124c5
|
||||||
|
timeCreated: 1664754621
|
@ -51,6 +51,8 @@ namespace net.fushizen.modular_avatar.core.editor
|
|||||||
static Util()
|
static Util()
|
||||||
{
|
{
|
||||||
RuntimeUtil.delayCall = (cb) => EditorApplication.delayCall += cb.Invoke;
|
RuntimeUtil.delayCall = (cb) => EditorApplication.delayCall += cb.Invoke;
|
||||||
|
|
||||||
|
EditorApplication.hierarchyChanged += () => { RuntimeUtil.InvokeHierarchyChanged(); };
|
||||||
}
|
}
|
||||||
|
|
||||||
public static AnimatorController CreateAnimator(AnimatorController toClone = null)
|
public static AnimatorController CreateAnimator(AnimatorController toClone = null)
|
||||||
|
@ -0,0 +1,44 @@
|
|||||||
|
using System;
|
||||||
|
using UnityEngine;
|
||||||
|
|
||||||
|
namespace net.fushizen.modular_avatar.core
|
||||||
|
{
|
||||||
|
[Serializable]
|
||||||
|
public class AvatarObjectReference
|
||||||
|
{
|
||||||
|
public bool isNull = true;
|
||||||
|
public string referencePath = "";
|
||||||
|
|
||||||
|
private bool _cacheValid = false;
|
||||||
|
private string _cachedPath = "";
|
||||||
|
private GameObject _cachedReference;
|
||||||
|
|
||||||
|
public GameObject Get(Component container)
|
||||||
|
{
|
||||||
|
if (_cacheValid && _cachedPath == referencePath && !isNull) return _cachedReference;
|
||||||
|
|
||||||
|
_cacheValid = true;
|
||||||
|
_cachedPath = referencePath;
|
||||||
|
|
||||||
|
if (isNull)
|
||||||
|
{
|
||||||
|
_cachedReference = null;
|
||||||
|
return _cachedReference;
|
||||||
|
}
|
||||||
|
|
||||||
|
RuntimeUtil.OnHierarchyChanged -= InvalidateCache;
|
||||||
|
RuntimeUtil.OnHierarchyChanged += InvalidateCache;
|
||||||
|
|
||||||
|
var avatar = RuntimeUtil.FindAvatarInParents(container.transform);
|
||||||
|
if (avatar == null) return (_cachedReference = null);
|
||||||
|
|
||||||
|
return (_cachedReference = avatar.transform.Find(referencePath)?.gameObject);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void InvalidateCache()
|
||||||
|
{
|
||||||
|
RuntimeUtil.OnHierarchyChanged -= InvalidateCache;
|
||||||
|
_cacheValid = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,3 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 5a8276620b424854bdad151a08ebe5d0
|
||||||
|
timeCreated: 1664754280
|
@ -24,7 +24,6 @@
|
|||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Reflection;
|
|
||||||
using JetBrains.Annotations;
|
using JetBrains.Annotations;
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
using VRC.SDK3.Avatars.Components;
|
using VRC.SDK3.Avatars.Components;
|
||||||
@ -37,6 +36,7 @@ namespace net.fushizen.modular_avatar.core
|
|||||||
|
|
||||||
// Initialized in Util
|
// Initialized in Util
|
||||||
public static Action<NullCallback> delayCall = (_) => { };
|
public static Action<NullCallback> delayCall = (_) => { };
|
||||||
|
public static event NullCallback OnHierarchyChanged;
|
||||||
|
|
||||||
public enum OnDemandSource
|
public enum OnDemandSource
|
||||||
{
|
{
|
||||||
@ -52,16 +52,16 @@ namespace net.fushizen.modular_avatar.core
|
|||||||
public static string RelativePath(GameObject root, GameObject child)
|
public static string RelativePath(GameObject root, GameObject child)
|
||||||
{
|
{
|
||||||
if (root == child) return "";
|
if (root == child) return "";
|
||||||
|
|
||||||
List<string> pathSegments = new List<string>();
|
List<string> pathSegments = new List<string>();
|
||||||
while (child != root && child != null)
|
while (child != root && child != null)
|
||||||
{
|
{
|
||||||
pathSegments.Add(child.name);
|
pathSegments.Add(child.name);
|
||||||
child = child.transform.parent.gameObject;
|
child = child.transform.parent?.gameObject;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (child == null) return null;
|
if (child == null) return null;
|
||||||
|
|
||||||
pathSegments.Reverse();
|
pathSegments.Reverse();
|
||||||
return String.Join("/", pathSegments);
|
return String.Join("/", pathSegments);
|
||||||
}
|
}
|
||||||
@ -93,34 +93,38 @@ namespace net.fushizen.modular_avatar.core
|
|||||||
{
|
{
|
||||||
UnityEditor.PrefabUtility.RecordPrefabInstancePropertyModifications(obj);
|
UnityEditor.PrefabUtility.RecordPrefabInstancePropertyModifications(obj);
|
||||||
}
|
}
|
||||||
|
|
||||||
UnityEditor.EditorUtility.SetDirty(obj);
|
UnityEditor.EditorUtility.SetDirty(obj);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
#if UNITY_EDITOR
|
#if UNITY_EDITOR
|
||||||
private static UnityEngine.Object cachedAnimationWindowState;
|
private static UnityEngine.Object cachedAnimationWindowState;
|
||||||
private static readonly Type animationWindowStateType
|
|
||||||
|
private static readonly Type animationWindowStateType
|
||||||
= typeof(UnityEditor.Editor).Assembly.GetType("UnityEditorInternal.AnimationWindowState");
|
= typeof(UnityEditor.Editor).Assembly.GetType("UnityEditorInternal.AnimationWindowState");
|
||||||
|
|
||||||
private static readonly PropertyInfo recordingProp = animationWindowStateType.GetProperty(
|
private static readonly PropertyInfo recordingProp = animationWindowStateType.GetProperty(
|
||||||
"recording",
|
"recording",
|
||||||
BindingFlags.Instance | BindingFlags.Public
|
BindingFlags.Instance | BindingFlags.Public
|
||||||
);
|
);
|
||||||
|
|
||||||
private static readonly PropertyInfo previewingProp = animationWindowStateType.GetProperty(
|
private static readonly PropertyInfo previewingProp = animationWindowStateType.GetProperty(
|
||||||
"previewing",
|
"previewing",
|
||||||
BindingFlags.Instance | BindingFlags.Public
|
BindingFlags.Instance | BindingFlags.Public
|
||||||
);
|
);
|
||||||
|
|
||||||
private static readonly PropertyInfo playingProp = animationWindowStateType.GetProperty(
|
private static readonly PropertyInfo playingProp = animationWindowStateType.GetProperty(
|
||||||
"playing",
|
"playing",
|
||||||
BindingFlags.Instance | BindingFlags.Public
|
BindingFlags.Instance | BindingFlags.Public
|
||||||
);
|
);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
public static bool IsAnimationEditMode()
|
public static bool IsAnimationEditMode()
|
||||||
{
|
{
|
||||||
#if !UNITY_EDITOR
|
#if !UNITY_EDITOR
|
||||||
return false;
|
return false;
|
||||||
#else
|
#else
|
||||||
|
|
||||||
if (cachedAnimationWindowState == null)
|
if (cachedAnimationWindowState == null)
|
||||||
{
|
{
|
||||||
foreach (var obj in Resources.FindObjectsOfTypeAll(animationWindowStateType))
|
foreach (var obj in Resources.FindObjectsOfTypeAll(animationWindowStateType))
|
||||||
@ -132,15 +136,19 @@ namespace net.fushizen.modular_avatar.core
|
|||||||
if (cachedAnimationWindowState == null) return false;
|
if (cachedAnimationWindowState == null) return false;
|
||||||
|
|
||||||
return (bool) recordingProp.GetValue(cachedAnimationWindowState, null)
|
return (bool) recordingProp.GetValue(cachedAnimationWindowState, null)
|
||||||
|| (bool) previewingProp.GetValue(cachedAnimationWindowState, null)
|
|| (bool) previewingProp.GetValue(cachedAnimationWindowState, null)
|
||||||
|| (bool) playingProp.GetValue(cachedAnimationWindowState, null);
|
|| (bool) playingProp.GetValue(cachedAnimationWindowState, null);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
#if UNITY_EDITOR
|
#if UNITY_EDITOR
|
||||||
public static bool isPlaying => UnityEditor.EditorApplication.isPlayingOrWillChangePlaymode;
|
public static bool isPlaying => UnityEditor.EditorApplication.isPlayingOrWillChangePlaymode;
|
||||||
#else
|
#else
|
||||||
public static bool isPlaying => true;
|
public static bool isPlaying => true;
|
||||||
#endif
|
#endif
|
||||||
|
public static void InvokeHierarchyChanged()
|
||||||
|
{
|
||||||
|
OnHierarchyChanged?.Invoke();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
Loading…
Reference in New Issue
Block a user