From 32ea6678f72515cce69c5817ef87133553894077 Mon Sep 17 00:00:00 2001 From: bd_ Date: Sun, 27 Oct 2024 10:07:23 -0700 Subject: [PATCH] feat: object references are now corrected when their target path is renamed/changes (#1323) --- Editor/ObjectReferenceFixer.cs | 53 +++++++++++++++++++++++++++----- Runtime/AvatarObjectReference.cs | 5 +++ 2 files changed, 50 insertions(+), 8 deletions(-) diff --git a/Editor/ObjectReferenceFixer.cs b/Editor/ObjectReferenceFixer.cs index b6fe69e6..b1c6108d 100644 --- a/Editor/ObjectReferenceFixer.cs +++ b/Editor/ObjectReferenceFixer.cs @@ -11,30 +11,51 @@ namespace nadena.dev.modular_avatar.core { private static ComputeContext _context; - private static PrefabStage _lastStage; + private static int? _lastStage; + private static int? GetCurrentContentsRootId(out GameObject contentsRoot) + { + contentsRoot = null; + + var stage = PrefabStageUtility.GetCurrentPrefabStage(); + if (stage == null || stage.prefabContentsRoot == null) return null; + + contentsRoot = stage.prefabContentsRoot; + + return stage.prefabContentsRoot.GetInstanceID(); + } + [InitializeOnLoadMethod] private static void Init() { EditorApplication.delayCall += ProcessObjectReferences; EditorApplication.update += () => { - if (PrefabStageUtility.GetCurrentPrefabStage() != _lastStage) _context?.Invalidate?.Invoke(); + var curStage = GetCurrentContentsRootId(out _); + + Debug.Log($"{_lastStage} => {curStage}"); + + if (curStage != _lastStage) + { + _context?.Invalidate?.Invoke(); + } }; } private static void ProcessObjectReferences() { - _lastStage = PrefabStageUtility.GetCurrentPrefabStage(); + _lastStage = GetCurrentContentsRootId(out var contentsRoot); + + AvatarObjectReference.InvalidateAll(); _context = new ComputeContext("ObjectReferenceFixer"); _context.InvokeOnInvalidate(typeof(ObjectReferenceFixer), _ => ProcessObjectReferences()); IEnumerable withReferences = _context.GetComponentsByType(); - if (_lastStage != null) + if (contentsRoot != null) withReferences = withReferences.Concat( - _context.GetComponentsInChildren(_lastStage.prefabContentsRoot, true) + _context.GetComponentsInChildren(contentsRoot, true) ); foreach (var obj in withReferences) @@ -56,10 +77,26 @@ namespace nadena.dev.modular_avatar.core foreach (var (targetObject, referencePath, objRef) in references) { - if (targetObject == null) continue; - _context.ObservePath(targetObject.transform); + var resolvedTarget = objRef.Get(component); + if (objRef.Get(component) == null) continue; + if (targetObject == null) + { + Undo.RecordObject(component, ""); + objRef.targetObject = resolvedTarget; + dirty = true; + } + else + { + // Direct object reference always wins in the event of a conflict. + resolvedTarget = targetObject; + } - if (!targetObject.transform.IsChildOf(avatar.transform)) continue; + foreach (var t in _context.ObservePath(resolvedTarget.transform)) + { + _context.Observe(t.gameObject, g => g.name); + } + + if (!resolvedTarget.transform.IsChildOf(avatar.transform)) continue; if (objRef.IsConsistent(avatar)) continue; diff --git a/Runtime/AvatarObjectReference.cs b/Runtime/AvatarObjectReference.cs index bc6407a0..db3c88df 100644 --- a/Runtime/AvatarObjectReference.cs +++ b/Runtime/AvatarObjectReference.cs @@ -29,6 +29,11 @@ namespace nadena.dev.modular_avatar.core EditorApplication.hierarchyChanged += () => HIERARCHY_CHANGED_SEQ += 1; } #endif + + internal static void InvalidateAll() + { + HIERARCHY_CHANGED_SEQ++; + } public AvatarObjectReference Clone() {