diff --git a/Editor/API/AnimatorServices/AnimationIndex.cs b/Editor/API/AnimatorServices/AnimationIndex.cs index 45aea6d..829ebea 100644 --- a/Editor/API/AnimatorServices/AnimationIndex.cs +++ b/Editor/API/AnimatorServices/AnimationIndex.cs @@ -9,7 +9,7 @@ namespace nadena.dev.ndmf.animator { public sealed class AnimationIndex { - private readonly Func> _getControllers; + private readonly Func> _getRoots; private readonly Func _getInvalidationToken; private long _lastInvalidationToken; @@ -22,22 +22,21 @@ public sealed class AnimationIndex private readonly Dictionary> _objectPathToClip = new(); private readonly Dictionary> _bindingToClip = new(); private readonly Dictionary> _lastBindings = new(); - + internal AnimationIndex( - Func> getControllers, + Func> getRoots, Func getInvalidationToken) { - _getControllers = getControllers; + _getRoots = getRoots; _getInvalidationToken = getInvalidationToken; _invalidateAction = () => _isValid = false; } - - // For testing - internal AnimationIndex(IEnumerable controllers) + + public AnimationIndex(IEnumerable controllers) { _invalidateAction = () => _isValid = false; - var controllerList = new List(controllers); - _getControllers = () => controllerList; + var controllerList = new List(controllers); + _getRoots = () => controllerList; _getInvalidationToken = () => _lastInvalidationToken; } @@ -65,11 +64,19 @@ public IEnumerable GetClipsForBinding(EditorCurveBinding binding) return Enumerable.Empty(); } - public void RewritePaths(Dictionary rewriteRules) + public void RewritePaths(Func rewriteRules) { if (!IsValid) RebuildCache(); - List recacheNeeded = new(); + var rewriteSet = _objectPathToClip.Values.SelectMany(s => s).Distinct(); + + RewritePaths(rewriteSet, rewriteRules); + } + + public void RewritePaths(Dictionary rewriteRules) + { + if (!IsValid) RebuildCache(); + HashSet rewriteSet = new(); foreach (var key in rewriteRules.Keys) @@ -85,6 +92,14 @@ public void RewritePaths(Dictionary rewriteRules) if (rewriteRules.TryGetValue(k, out var v)) return v; return k; }; + + RewritePaths(rewriteSet, rewriteFunc); + } + + private void RewritePaths(IEnumerable rewriteSet, Func rewriteFunc) + { + List recacheNeeded = new(); + foreach (var clip in rewriteSet) { clip.EditPaths(rewriteFunc); @@ -185,7 +200,7 @@ private IEnumerable EnumerateClips() Queue queue = new(); _lastInvalidationToken = _getInvalidationToken(); - foreach (var controller in _getControllers()) + foreach (var controller in _getRoots()) { queue.Enqueue(controller); } diff --git a/Editor/API/AnimatorServices/ObjectPathRemapper.cs b/Editor/API/AnimatorServices/ObjectPathRemapper.cs index c0bca2b..4700894 100644 --- a/Editor/API/AnimatorServices/ObjectPathRemapper.cs +++ b/Editor/API/AnimatorServices/ObjectPathRemapper.cs @@ -1,6 +1,7 @@ #nullable enable using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; using JetBrains.Annotations; using nadena.dev.ndmf.runtime; using UnityEngine; @@ -119,7 +120,7 @@ public void RecordObjectTree(Transform subtree) /// /// /// - public string? GetVirtualPathForObject(GameObject obj) + public string GetVirtualPathForObject(GameObject obj) { return GetVirtualPathForObject(obj.transform); } @@ -131,7 +132,7 @@ public void RecordObjectTree(Transform subtree) /// /// /// - public string? GetVirtualPathForObject(Transform t) + public string GetVirtualPathForObject(Transform t) { if (_objectToOriginalPaths.TryGetValue(t, out var paths)) { @@ -139,7 +140,7 @@ public void RecordObjectTree(Transform subtree) } var path = RuntimeUtil.RelativePath(_root, t); - if (path == null) return null; + if (path == null) path = t.gameObject.name + "###UNROOTED_" + t.GetInstanceID(); if (_pathToObject.ContainsKey(path)) { diff --git a/Editor/API/AnimatorServices/VirtualControllerContext.cs b/Editor/API/AnimatorServices/VirtualControllerContext.cs index 8dbd57d..491a577 100644 --- a/Editor/API/AnimatorServices/VirtualControllerContext.cs +++ b/Editor/API/AnimatorServices/VirtualControllerContext.cs @@ -148,7 +148,7 @@ public void OnDeactivate(BuildContext context) commitContext.ActiveInnateLayerKey = kv.Key; return (RuntimeAnimatorController)commitContext.CommitObject(kv.Value.VirtualController!); }); - + _platformBindings!.CommitControllers(root, controllers); } diff --git a/Editor/API/AnimatorServices/VirtualObjects/VirtualClip.cs b/Editor/API/AnimatorServices/VirtualObjects/VirtualClip.cs index fb83e2f..a400887 100644 --- a/Editor/API/AnimatorServices/VirtualObjects/VirtualClip.cs +++ b/Editor/API/AnimatorServices/VirtualObjects/VirtualClip.cs @@ -267,9 +267,10 @@ Dictionary> Transform( var newBinding = binding; newBinding.path = pathEditor(binding.path); - if (ECBComparator.Instance.Equals(binding, newBinding)) + if (ECBComparator.Instance.Equals(binding, newBinding) + || (binding.type == typeof(Animator) && binding.path == "")) { - newCache[newBinding] = kvp.Value; + newCache[binding] = kvp.Value; continue; } diff --git a/Editor/API/AnimatorServices/VirtualObjects/VirtualMotion.cs b/Editor/API/AnimatorServices/VirtualObjects/VirtualMotion.cs index c500236..2d0f898 100644 --- a/Editor/API/AnimatorServices/VirtualObjects/VirtualMotion.cs +++ b/Editor/API/AnimatorServices/VirtualObjects/VirtualMotion.cs @@ -1,6 +1,8 @@ #nullable enable using System; +using System.Collections; +using System.Collections.Generic; using JetBrains.Annotations; using UnityEditor.Animations; using UnityEngine; diff --git a/Editor/API/AnimatorServices/VirtualObjects/VirtualNode.cs b/Editor/API/AnimatorServices/VirtualObjects/VirtualNode.cs index 3e3f707..837c623 100644 --- a/Editor/API/AnimatorServices/VirtualObjects/VirtualNode.cs +++ b/Editor/API/AnimatorServices/VirtualObjects/VirtualNode.cs @@ -41,7 +41,30 @@ internal void RegisterCacheObserver(Action? observer) _lastCacheObserver = observer; } - internal IEnumerable EnumerateChildren() + public IEnumerable AllReachableNodes() + { + var visited = new HashSet(); + var queue = new Queue(); + + queue.Enqueue(this); + visited.Add(this); + + while (queue.Count > 0) + { + var node = queue.Dequeue(); + yield return node; + + foreach (var child in node.EnumerateChildren()) + { + if (visited.Add(child)) + { + queue.Enqueue(child); + } + } + } + } + + public IEnumerable EnumerateChildren() { return _EnumerateChildren(); } diff --git a/Editor/API/AnimatorServices/VirtualObjects/VirtualState.cs b/Editor/API/AnimatorServices/VirtualObjects/VirtualState.cs index cffdc17..9959109 100644 --- a/Editor/API/AnimatorServices/VirtualObjects/VirtualState.cs +++ b/Editor/API/AnimatorServices/VirtualObjects/VirtualState.cs @@ -187,6 +187,7 @@ void ICommitable.Commit(CommitContext context, AnimatorState obj) { obj.behaviours = Behaviours.Select(context.CommitBehaviour).ToArray(); obj.transitions = Transitions.Select(t => (AnimatorStateTransition)context.CommitObject(t)).ToArray(); + obj.motion = context.CommitObject(Motion); } public override string ToString() diff --git a/Editor/API/AnimatorServices/VirtualObjects/VirtualStateMachine.cs b/Editor/API/AnimatorServices/VirtualObjects/VirtualStateMachine.cs index 58b9da1..cd6d6e6 100644 --- a/Editor/API/AnimatorServices/VirtualObjects/VirtualStateMachine.cs +++ b/Editor/API/AnimatorServices/VirtualObjects/VirtualStateMachine.cs @@ -282,5 +282,33 @@ public VirtualState AddState(string name, VirtualMotion? motion = null, Vector3? return state; } + + /// + /// Returns an enumerator of all states reachable from this state machine (including sub-state machines) + /// + /// + public IEnumerable AllStates() + { + foreach (var state in Walk(this, new())) yield return state; + + IEnumerable Walk(VirtualStateMachine sm, HashSet visited) + { + if (!visited.Add(sm)) yield break; + + foreach (var state in States) + { + yield return state.State; + } + + foreach (var ssm in StateMachines) + { + foreach (var state in Walk(ssm.StateMachine, visited)) + { + yield return state; + } + } + } + + } } } \ No newline at end of file diff --git a/Editor/API/BuildContext.cs b/Editor/API/BuildContext.cs index 8745083..587dd6d 100644 --- a/Editor/API/BuildContext.cs +++ b/Editor/API/BuildContext.cs @@ -346,11 +346,58 @@ internal void RunPass(ConcretePass pass) } } + public void DeactivateAllExtensionContexts() + { + Dictionary> depIndex = new(); + foreach (var ty in _activeExtensions.Keys) + { + foreach (var dep in ty.ContextDependencies()) + { + if (!depIndex.ContainsKey(dep)) + { + depIndex[dep] = new List(); + } + + depIndex[dep].Add(ty); + } + } + + while (_activeExtensions.Keys.Count > 0) + { + Type next = _activeExtensions.Keys.First(); + Type candidate; + do + { + candidate = next; + var revDeps = depIndex.GetValueOrDefault(next) as IEnumerable + ?? Array.Empty(); + next = revDeps.FirstOrDefault(t => _activeExtensions.ContainsKey(t)); + } while (next != null); + + DeactivateExtensionContext(candidate); + } + } + + public T ActivateExtensionContextRecurse() where T : IExtensionContext + { + return (T) ActivateExtensionContextRecurse(typeof(T)); + } + + public IExtensionContext ActivateExtensionContextRecurse(Type ty) + { + foreach (var dependency in ty.ContextDependencies()) + { + ActivateExtensionContextRecurse(dependency); + } + + return ActivateExtensionContext(ty); + } + public T ActivateExtensionContext() where T : IExtensionContext { return (T)ActivateExtensionContext(typeof(T)); } - + public IExtensionContext ActivateExtensionContext(Type ty) { using (new ExecutionScope(this))