2022-08-28 04:38:52 +08:00
|
|
|
|
using System;
|
|
|
|
|
using System.Collections.Generic;
|
2022-08-30 06:13:26 +08:00
|
|
|
|
using System.Reflection;
|
2022-08-28 04:38:52 +08:00
|
|
|
|
using JetBrains.Annotations;
|
|
|
|
|
using UnityEngine;
|
|
|
|
|
using VRC.SDK3.Avatars.Components;
|
|
|
|
|
|
|
|
|
|
namespace net.fushizen.modular_avatar.core
|
|
|
|
|
{
|
|
|
|
|
public static class RuntimeUtil
|
|
|
|
|
{
|
|
|
|
|
[CanBeNull]
|
|
|
|
|
public static string RelativePath(GameObject root, GameObject child)
|
|
|
|
|
{
|
|
|
|
|
if (root == child) return "";
|
|
|
|
|
|
|
|
|
|
List<string> pathSegments = new List<string>();
|
|
|
|
|
while (child != root && child != null)
|
|
|
|
|
{
|
|
|
|
|
pathSegments.Add(child.name);
|
|
|
|
|
child = child.transform.parent.gameObject;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (child == null) return null;
|
|
|
|
|
|
|
|
|
|
pathSegments.Reverse();
|
|
|
|
|
return String.Join("/", pathSegments);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[CanBeNull]
|
|
|
|
|
public static string AvatarRootPath(GameObject child)
|
|
|
|
|
{
|
|
|
|
|
var avatar = FindAvatarInParents(child.transform);
|
|
|
|
|
if (avatar == null) return null;
|
|
|
|
|
return RelativePath(avatar.gameObject, child);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static VRCAvatarDescriptor FindAvatarInParents(Transform target)
|
|
|
|
|
{
|
|
|
|
|
while (target != null)
|
|
|
|
|
{
|
|
|
|
|
var av = target.GetComponent<VRCAvatarDescriptor>();
|
|
|
|
|
if (av != null) return av;
|
|
|
|
|
target = target.parent;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return null;
|
|
|
|
|
}
|
2022-08-28 10:04:53 +08:00
|
|
|
|
|
|
|
|
|
public static void MarkDirty(UnityEngine.Object obj)
|
|
|
|
|
{
|
2022-08-30 06:13:26 +08:00
|
|
|
|
#if UNITY_EDITOR
|
|
|
|
|
if (UnityEditor.PrefabUtility.IsPartOfPrefabInstance(obj))
|
2022-08-28 10:04:53 +08:00
|
|
|
|
{
|
2022-08-30 06:13:26 +08:00
|
|
|
|
UnityEditor.PrefabUtility.RecordPrefabInstancePropertyModifications(obj);
|
2022-08-28 10:04:53 +08:00
|
|
|
|
}
|
2022-08-30 06:13:26 +08:00
|
|
|
|
UnityEditor.EditorUtility.SetDirty(obj);
|
2022-08-29 09:30:08 +08:00
|
|
|
|
#endif
|
2022-08-28 10:04:53 +08:00
|
|
|
|
}
|
2022-08-30 06:13:26 +08:00
|
|
|
|
|
|
|
|
|
#if UNITY_EDITOR
|
|
|
|
|
private static UnityEngine.Object cachedAnimationWindowState;
|
|
|
|
|
private static readonly Type animationWindowStateType
|
|
|
|
|
= typeof(UnityEditor.Editor).Assembly.GetType("UnityEditorInternal.AnimationWindowState");
|
|
|
|
|
private static readonly PropertyInfo recordingProp = animationWindowStateType.GetProperty(
|
|
|
|
|
"recording",
|
|
|
|
|
BindingFlags.Instance | BindingFlags.Public
|
|
|
|
|
);
|
|
|
|
|
private static readonly PropertyInfo previewingProp = animationWindowStateType.GetProperty(
|
|
|
|
|
"previewing",
|
|
|
|
|
BindingFlags.Instance | BindingFlags.Public
|
|
|
|
|
);
|
|
|
|
|
private static readonly PropertyInfo playingProp = animationWindowStateType.GetProperty(
|
|
|
|
|
"playing",
|
|
|
|
|
BindingFlags.Instance | BindingFlags.Public
|
|
|
|
|
);
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
public static bool IsAnimationEditMode()
|
|
|
|
|
{
|
|
|
|
|
#if !UNITY_EDITOR
|
|
|
|
|
return false;
|
|
|
|
|
#else
|
|
|
|
|
|
|
|
|
|
if (cachedAnimationWindowState == null)
|
|
|
|
|
{
|
|
|
|
|
foreach (var obj in Resources.FindObjectsOfTypeAll(animationWindowStateType))
|
|
|
|
|
{
|
|
|
|
|
cachedAnimationWindowState = obj;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (cachedAnimationWindowState == null) return false;
|
|
|
|
|
|
|
|
|
|
return (bool) recordingProp.GetValue(cachedAnimationWindowState, null)
|
|
|
|
|
|| (bool) previewingProp.GetValue(cachedAnimationWindowState, null)
|
|
|
|
|
|| (bool) playingProp.GetValue(cachedAnimationWindowState, null);
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#if UNITY_EDITOR
|
|
|
|
|
public static bool isPlaying => UnityEditor.EditorApplication.isPlayingOrWillChangePlaymode;
|
|
|
|
|
#else
|
|
|
|
|
public static bool isPlaying => true;
|
|
|
|
|
#endif
|
2022-08-28 04:38:52 +08:00
|
|
|
|
}
|
|
|
|
|
}
|