mirror of
https://github.com/bdunderscore/modular-avatar.git
synced 2025-01-30 10:12:59 +08:00
feat: update AvatarObjectReference paths when target object is moved in scene (#1074)
Closes: #1037
This commit is contained in:
parent
682a0de0e0
commit
0a6270bb43
83
Editor/ObjectReferenceFixer.cs
Normal file
83
Editor/ObjectReferenceFixer.cs
Normal file
@ -0,0 +1,83 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using nadena.dev.ndmf.preview;
|
||||
using UnityEditor;
|
||||
using UnityEditor.SceneManagement;
|
||||
using UnityEngine;
|
||||
|
||||
namespace nadena.dev.modular_avatar.core
|
||||
{
|
||||
public static class ObjectReferenceFixer
|
||||
{
|
||||
private static ComputeContext _context;
|
||||
|
||||
private static PrefabStage _lastStage;
|
||||
|
||||
[InitializeOnLoadMethod]
|
||||
private static void Init()
|
||||
{
|
||||
EditorApplication.delayCall += ProcessObjectReferences;
|
||||
EditorApplication.update += () =>
|
||||
{
|
||||
if (PrefabStageUtility.GetCurrentPrefabStage() != _lastStage) _context?.Invalidate?.Invoke();
|
||||
};
|
||||
}
|
||||
|
||||
private static void ProcessObjectReferences()
|
||||
{
|
||||
_lastStage = PrefabStageUtility.GetCurrentPrefabStage();
|
||||
|
||||
_context = new ComputeContext("ObjectReferenceFixer");
|
||||
_context.InvokeOnInvalidate<object>(typeof(ObjectReferenceFixer), _ => ProcessObjectReferences());
|
||||
|
||||
IEnumerable<IHaveObjReferences> withReferences = _context.GetComponentsByType<IHaveObjReferences>();
|
||||
if (_lastStage != null)
|
||||
withReferences =
|
||||
withReferences.Concat(
|
||||
_context.GetComponentsInChildren<IHaveObjReferences>(_lastStage.prefabContentsRoot, true)
|
||||
);
|
||||
|
||||
foreach (var obj in withReferences)
|
||||
{
|
||||
var component = obj as Component;
|
||||
if (component == null) continue;
|
||||
|
||||
var avatar = _context.GetAvatarRoot(component.gameObject);
|
||||
if (avatar == null) continue;
|
||||
|
||||
var references = _context.Observe(component,
|
||||
c => ((IHaveObjReferences)c).GetObjectReferences().Select(
|
||||
r => (r.targetObject, r.referencePath, r)
|
||||
),
|
||||
Enumerable.SequenceEqual
|
||||
);
|
||||
|
||||
var dirty = false;
|
||||
|
||||
foreach (var (targetObject, referencePath, objRef) in references)
|
||||
{
|
||||
if (targetObject == null) continue;
|
||||
_context.ObservePath(targetObject.transform);
|
||||
|
||||
if (!targetObject.transform.IsChildOf(avatar.transform)) continue;
|
||||
|
||||
if (objRef.IsConsistent(avatar)) continue;
|
||||
|
||||
if (!dirty)
|
||||
{
|
||||
dirty = true;
|
||||
Undo.RecordObject(component, "");
|
||||
}
|
||||
|
||||
objRef.Set(targetObject);
|
||||
}
|
||||
|
||||
if (dirty)
|
||||
{
|
||||
EditorUtility.SetDirty(component);
|
||||
PrefabUtility.RecordPrefabInstancePropertyModifications(component);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
3
Editor/ObjectReferenceFixer.cs.meta
Normal file
3
Editor/ObjectReferenceFixer.cs.meta
Normal file
@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: eba8a4ec992b42d894f9206c642c49ad
|
||||
timeCreated: 1725229885
|
@ -1,8 +1,8 @@
|
||||
using System;
|
||||
using UnityEngine;
|
||||
#if UNITY_EDITOR
|
||||
using UnityEditor;
|
||||
#endif
|
||||
using UnityEngine;
|
||||
|
||||
namespace nadena.dev.modular_avatar.core
|
||||
{
|
||||
@ -124,6 +124,12 @@ namespace nadena.dev.modular_avatar.core
|
||||
targetObject = target;
|
||||
}
|
||||
|
||||
internal bool IsConsistent(GameObject avatarRoot)
|
||||
{
|
||||
if (referencePath == AVATAR_ROOT) return targetObject == avatarRoot;
|
||||
return avatarRoot.transform.Find(referencePath)?.gameObject == targetObject;
|
||||
}
|
||||
|
||||
private void InvalidateCache()
|
||||
{
|
||||
RuntimeUtil.OnHierarchyChanged -= InvalidateCache;
|
||||
|
@ -24,7 +24,6 @@
|
||||
|
||||
using System;
|
||||
using UnityEngine;
|
||||
|
||||
#if MA_VRCSDK3_AVATARS
|
||||
using VRC.SDKBase;
|
||||
#endif
|
||||
|
9
Runtime/IHaveObjReferences.cs
Normal file
9
Runtime/IHaveObjReferences.cs
Normal file
@ -0,0 +1,9 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace nadena.dev.modular_avatar.core
|
||||
{
|
||||
internal interface IHaveObjReferences
|
||||
{
|
||||
IEnumerable<AvatarObjectReference> GetObjectReferences();
|
||||
}
|
||||
}
|
3
Runtime/IHaveObjReferences.cs.meta
Normal file
3
Runtime/IHaveObjReferences.cs.meta
Normal file
@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 979eb029e78d4916a24742853e8d7e53
|
||||
timeCreated: 1725229779
|
@ -36,7 +36,7 @@ namespace nadena.dev.modular_avatar.core
|
||||
[ExecuteAlways]
|
||||
[AddComponentMenu("Modular Avatar/MA Blendshape Sync")]
|
||||
[HelpURL("https://modular-avatar.nadena.dev/docs/reference/blendshape-sync?lang=auto")]
|
||||
public class ModularAvatarBlendshapeSync : AvatarTagComponent
|
||||
public class ModularAvatarBlendshapeSync : AvatarTagComponent, IHaveObjReferences
|
||||
{
|
||||
public List<BlendshapeBinding> Bindings = new List<BlendshapeBinding>();
|
||||
|
||||
@ -126,5 +126,12 @@ namespace nadena.dev.modular_avatar.core
|
||||
localRenderer.SetBlendShapeWeight(binding.LocalBlendshapeIndex, weight);
|
||||
}
|
||||
}
|
||||
|
||||
public IEnumerable<AvatarObjectReference> GetObjectReferences()
|
||||
{
|
||||
foreach (var binding in Bindings)
|
||||
if (binding.ReferenceMesh != null)
|
||||
yield return binding.ReferenceMesh;
|
||||
}
|
||||
}
|
||||
}
|
@ -47,7 +47,7 @@ namespace nadena.dev.modular_avatar.core
|
||||
[DisallowMultipleComponent]
|
||||
[AddComponentMenu("Modular Avatar/MA Merge Armature")]
|
||||
[HelpURL("https://modular-avatar.nadena.dev/docs/reference/merge-armature?lang=auto")]
|
||||
public class ModularAvatarMergeArmature : AvatarTagComponent
|
||||
public class ModularAvatarMergeArmature : AvatarTagComponent, IHaveObjReferences
|
||||
{
|
||||
public AvatarObjectReference mergeTarget = new AvatarObjectReference();
|
||||
public GameObject mergeTargetObject => mergeTarget.Get(this);
|
||||
@ -236,5 +236,10 @@ namespace nadena.dev.modular_avatar.core
|
||||
RuntimeUtil.MarkDirty(this);
|
||||
}
|
||||
}
|
||||
|
||||
public IEnumerable<AvatarObjectReference> GetObjectReferences()
|
||||
{
|
||||
if (mergeTarget != null) yield return mergeTarget;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,4 +1,5 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
namespace nadena.dev.modular_avatar.core
|
||||
@ -6,7 +7,7 @@ namespace nadena.dev.modular_avatar.core
|
||||
[AddComponentMenu("Modular Avatar/MA Mesh Settings")]
|
||||
[DisallowMultipleComponent]
|
||||
[HelpURL("https://modular-avatar.nadena.dev/docs/reference/mesh-settings?lang=auto")]
|
||||
public class ModularAvatarMeshSettings : AvatarTagComponent
|
||||
public class ModularAvatarMeshSettings : AvatarTagComponent, IHaveObjReferences
|
||||
{
|
||||
internal static readonly Bounds DEFAULT_BOUNDS = new Bounds(Vector3.zero, Vector3.one * 2);
|
||||
|
||||
@ -34,5 +35,11 @@ namespace nadena.dev.modular_avatar.core
|
||||
ProbeAnchor?.Get(this);
|
||||
RootBone?.Get(this);
|
||||
}
|
||||
|
||||
public IEnumerable<AvatarObjectReference> GetObjectReferences()
|
||||
{
|
||||
if (ProbeAnchor != null) yield return ProbeAnchor;
|
||||
if (RootBone != null) yield return RootBone;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,11 +1,12 @@
|
||||
using UnityEngine;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
namespace nadena.dev.modular_avatar.core
|
||||
{
|
||||
[AddComponentMenu("Modular Avatar/MA Replace Object")]
|
||||
[DisallowMultipleComponent]
|
||||
[HelpURL("https://modular-avatar.nadena.dev/docs/reference/replace-object?lang=auto")]
|
||||
public class ModularAvatarReplaceObject : AvatarTagComponent
|
||||
public class ModularAvatarReplaceObject : AvatarTagComponent, IHaveObjReferences
|
||||
{
|
||||
public AvatarObjectReference targetObject = new AvatarObjectReference();
|
||||
|
||||
@ -13,5 +14,10 @@ namespace nadena.dev.modular_avatar.core
|
||||
{
|
||||
targetObject?.Get(this);
|
||||
}
|
||||
|
||||
public IEnumerable<AvatarObjectReference> GetObjectReferences()
|
||||
{
|
||||
if (targetObject != null) yield return targetObject;
|
||||
}
|
||||
}
|
||||
}
|
@ -39,8 +39,7 @@ namespace nadena.dev.modular_avatar.core
|
||||
|
||||
[AddComponentMenu("Modular Avatar/MA Material Setter")]
|
||||
[HelpURL("https://modular-avatar.nadena.dev/docs/reference/material-setter?lang=auto")]
|
||||
|
||||
public class ModularAvatarMaterialSetter : ReactiveComponent
|
||||
public class ModularAvatarMaterialSetter : ReactiveComponent, IHaveObjReferences
|
||||
{
|
||||
[SerializeField] private List<MaterialSwitchObject> m_objects = new();
|
||||
|
||||
@ -57,5 +56,12 @@ namespace nadena.dev.modular_avatar.core
|
||||
obj.Object?.Get(this);
|
||||
}
|
||||
}
|
||||
|
||||
public IEnumerable<AvatarObjectReference> GetObjectReferences()
|
||||
{
|
||||
foreach (var obj in m_objects)
|
||||
if (obj.Object != null)
|
||||
yield return obj.Object;
|
||||
}
|
||||
}
|
||||
}
|
@ -22,7 +22,7 @@ namespace nadena.dev.modular_avatar.core
|
||||
|
||||
[AddComponentMenu("Modular Avatar/MA Object Toggle")]
|
||||
[HelpURL("https://modular-avatar.nadena.dev/docs/reference/object-toggle?lang=auto")]
|
||||
public class ModularAvatarObjectToggle : ReactiveComponent
|
||||
public class ModularAvatarObjectToggle : ReactiveComponent, IHaveObjReferences
|
||||
{
|
||||
[SerializeField] private List<ToggledObject> m_objects = new();
|
||||
|
||||
@ -39,5 +39,12 @@ namespace nadena.dev.modular_avatar.core
|
||||
obj.Object?.Get(this);
|
||||
}
|
||||
}
|
||||
|
||||
public IEnumerable<AvatarObjectReference> GetObjectReferences()
|
||||
{
|
||||
foreach (var obj in m_objects)
|
||||
if (obj.Object != null)
|
||||
yield return obj.Object;
|
||||
}
|
||||
}
|
||||
}
|
@ -58,7 +58,7 @@ namespace nadena.dev.modular_avatar.core
|
||||
|
||||
[AddComponentMenu("Modular Avatar/MA Shape Changer")]
|
||||
[HelpURL("https://modular-avatar.nadena.dev/docs/reference/shape-changer?lang=auto")]
|
||||
public class ModularAvatarShapeChanger : ReactiveComponent
|
||||
public class ModularAvatarShapeChanger : ReactiveComponent, IHaveObjReferences
|
||||
{
|
||||
// Migration field to help with 1.10-beta series avatar data. Since this was never in a released version of MA,
|
||||
// this migration support will be removed in 1.10.0.
|
||||
@ -115,5 +115,12 @@ namespace nadena.dev.modular_avatar.core
|
||||
m_targetRenderer.targetObject = null;
|
||||
}
|
||||
}
|
||||
|
||||
public IEnumerable<AvatarObjectReference> GetObjectReferences()
|
||||
{
|
||||
foreach (var shape in m_shapes)
|
||||
if (shape.Object != null)
|
||||
yield return shape.Object;
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user