modular-avatar/Runtime/ScaleAdjuster/ModularAvatarScaleAdjuster.cs
bd_ b25359a14a
fix: Scale Adjusters outside an avatar throw exceptions (#822)
* fix: Scale Adjusters outside an avatar throw exceptions

* fix: improve scale adjuster performance
2024-04-15 11:47:39 +09:00

169 lines
4.9 KiB
C#

#region
using System;
using UnityEngine;
using UnityEngine.SceneManagement;
using UnityEngine.Serialization;
#if UNITY_EDITOR
using UnityEditor;
#endif
#endregion
namespace nadena.dev.modular_avatar.core
{
[ExecuteInEditMode]
[DisallowMultipleComponent]
[AddComponentMenu("Modular Avatar/MA Scale Adjuster")]
[HelpURL("https://modular-avatar.nadena.dev/docs/reference/scale-adjuster?lang=auto")]
public sealed class ModularAvatarScaleAdjuster : AvatarTagComponent
{
private const string ADJUSTER_OBJECT = "MA Scale Adjuster Proxy Renderer";
[SerializeField] private Vector3 m_Scale = Vector3.one;
public Vector3 Scale
{
get => m_Scale;
set
{
m_Scale = value;
PreCull();
}
}
[SerializeField] [FormerlySerializedAs("scaleProxy")]
internal Transform legacyScaleProxy;
internal Transform scaleProxyChild;
[NonSerialized]
private bool initialized = false;
#if UNITY_EDITOR
void Awake()
{
ProxyManager.RegisterAdjuster(this);
initialized = false;
}
void OnValidate()
{
ProxyManager.RegisterAdjuster(this);
initialized = false;
}
internal void PreCull()
{
if (this == null)
{
EditorApplication.delayCall += () => ProxyManager.UnregisterAdjuster(this);
return;
}
if (PrefabUtility.IsPartOfPrefabAsset(this)) return;
if (scaleProxyChild == null || initialized == false)
{
InitializeProxy();
}
UpdateProxyParent(scaleProxyChild, transform);
var xform = transform;
scaleProxyChild.localScale = m_Scale;
ProxyManager.RegisterBone(xform, scaleProxyChild);
if (legacyScaleProxy != null && !PrefabUtility.IsPartOfPrefabAsset(legacyScaleProxy))
{
DestroyImmediate(legacyScaleProxy.gameObject);
legacyScaleProxy = null;
}
}
private void UpdateProxyParent(Transform proxyChild, Transform trueParent)
{
while (trueParent != null)
{
Transform parent = proxyChild.parent;
if (parent == null)
{
GameObject obj = new GameObject();
proxyChild.transform.SetParent(obj.transform, false);
#if MODULAR_AVATAR_DEBUG_HIDDEN
obj.hideFlags = HideFlags.DontSave;
#else
obj.hideFlags = HideFlags.HideAndDontSave;
#endif
parent = obj.transform;
if (obj.scene != gameObject.scene && gameObject.scene.IsValid())
{
SceneManager.MoveGameObjectToScene(obj, gameObject.scene);
}
}
parent.gameObject.name = "Proxy object for " + trueParent.gameObject.name;
parent.localPosition = trueParent.localPosition;
parent.localRotation = trueParent.localRotation;
parent.localScale = trueParent.localScale;
proxyChild = parent;
trueParent = trueParent.parent;
}
// Clean up any additional parentage we might not want
if (proxyChild.parent != null)
{
Transform parent = proxyChild.parent;
// Reparent to root
proxyChild.SetParent(null, false);
// Destroy old hierarchy
while (parent.parent != null) parent = parent.parent;
DestroyImmediate(parent.gameObject);
}
}
private void InitializeProxy()
{
if (scaleProxyChild == null)
{
scaleProxyChild = new GameObject("Child").transform;
#if MODULAR_AVATAR_DEBUG_HIDDEN
scaleProxyChild.gameObject.hideFlags = HideFlags.DontSave;
#else
scaleProxyChild.gameObject.hideFlags = HideFlags.HideAndDontSave;
#endif
}
initialized = true;
}
private void OnDestroy()
{
ProxyManager.UnregisterAdjuster(this);
if (scaleProxyChild != null)
{
Transform parent = scaleProxyChild.parent;
while (parent.parent != null) parent = parent.parent;
DestroyImmediate(parent.gameObject);
}
if (transform != null)
{
ProxyManager.UnregisterBone(transform);
}
base.OnDestroy();
}
#else
internal void PreCull() {
// build time stub
}
#endif
}
}