From dd1927cbd478ee9788d01cf0bb70db8403310e65 Mon Sep 17 00:00:00 2001 From: bd_ Date: Sun, 17 Nov 2024 14:59:47 -0800 Subject: [PATCH] Enable nullable warnings for the animation API --- Editor/API/AnimatorServices/AnimationIndex.cs | 4 +- .../AnimatorServicesContext.cs | 48 ++++++------ Editor/API/AnimatorServices/CloneContext.cs | 48 +++++++----- Editor/API/AnimatorServices/ECBComparator.cs | 4 +- Editor/API/AnimatorServices/ICommitable.cs | 9 ++- Editor/API/AnimatorServices/LayerPriority.cs | 23 ++++-- .../AnimatorServices/ObjectPathRemapper.cs | 16 ++-- .../SyncedLayerOverrideAccess.cs | 7 +- .../VirtualAnimatorController.cs | 11 ++- .../VirtualObjects/VirtualBlendTree.cs | 35 ++++----- .../VirtualObjects/VirtualClip.cs | 35 +++++---- .../VirtualObjects/VirtualLayer.cs | 47 ++++++------ .../VirtualObjects/VirtualMotion.cs | 4 +- .../VirtualObjects/VirtualNode.cs | 8 +- .../VirtualObjects/VirtualState.cs | 45 ++++++----- .../VirtualObjects/VirtualStateMachine.cs | 74 ++++++++++--------- .../VirtualObjects/VirtualStateTransition.cs | 6 +- .../VirtualObjects/VirtualTransition.cs | 4 +- .../VirtualObjects/VirtualTransitionBase.cs | 29 ++++---- 19 files changed, 261 insertions(+), 196 deletions(-) diff --git a/Editor/API/AnimatorServices/AnimationIndex.cs b/Editor/API/AnimatorServices/AnimationIndex.cs index 6bcbcb4..f298bfc 100644 --- a/Editor/API/AnimatorServices/AnimationIndex.cs +++ b/Editor/API/AnimatorServices/AnimationIndex.cs @@ -1,4 +1,6 @@ -using System; +#nullable enable + +using System; using System.Collections.Generic; using System.Linq; using UnityEditor; diff --git a/Editor/API/AnimatorServices/AnimatorServicesContext.cs b/Editor/API/AnimatorServices/AnimatorServicesContext.cs index 8eb9310..2c401e4 100644 --- a/Editor/API/AnimatorServices/AnimatorServicesContext.cs +++ b/Editor/API/AnimatorServices/AnimatorServicesContext.cs @@ -1,4 +1,6 @@ -using System.Collections.Generic; +#nullable enable + +using System.Collections.Generic; using System.Linq; using UnityEngine; using VRC.SDK3.Avatars.Components; @@ -9,14 +11,20 @@ public sealed class AnimatorServicesContext : IExtensionContext { private class LayerState { - internal RuntimeAnimatorController originalController; - internal VirtualAnimatorController virtualController; - } + internal readonly RuntimeAnimatorController? OriginalController; + internal VirtualAnimatorController? VirtualController; - private CloneContext _cloneContext; + public LayerState(RuntimeAnimatorController? originalController) + { + OriginalController = originalController; + } + } + private readonly Dictionary _layerStates = new(); - private IPlatformAnimatorBindings _platformBindings; + // initialized on activate + private IPlatformAnimatorBindings? _platformBindings; + private CloneContext? _cloneContext; public void OnActivate(BuildContext context) { @@ -33,20 +41,16 @@ public void OnActivate(BuildContext context) _cloneContext = new CloneContext(_platformBindings); - foreach (var (type, controller, isDefault) in _platformBindings.GetInnateControllers(root)) + foreach (var (type, controller, _) in _platformBindings.GetInnateControllers(root)) { - _layerStates[type] = new LayerState - { - originalController = controller, - virtualController = null - }; + _layerStates[type] = new LayerState(controller); - // TEMP + // TEMP - force all layers to be processed _ = this[type]; } } - public VirtualAnimatorController this[object key] + public VirtualAnimatorController? this[object key] { get { @@ -55,16 +59,16 @@ public VirtualAnimatorController this[object key] return null; } - if (state.virtualController == null) + if (state.VirtualController == null) { - state.virtualController = _cloneContext.Clone(state.originalController); + state.VirtualController = _cloneContext!.Clone(state.OriginalController); } - return state.virtualController; + return state.VirtualController; } - set => _layerStates[key] = new LayerState + set => _layerStates[key] = new LayerState(null) { - virtualController = value + VirtualController = value }; } @@ -74,13 +78,13 @@ public void OnDeactivate(BuildContext context) var commitContext = new CommitContext(); - var controllers = _layerStates.Where(kvp => kvp.Value.virtualController != null) + var controllers = _layerStates.Where(kvp => kvp.Value.VirtualController != null) .ToDictionary( k => k.Key, - v => (RuntimeAnimatorController)commitContext.CommitObject(v.Value.virtualController) + v => (RuntimeAnimatorController)commitContext.CommitObject(v.Value.VirtualController!) ); - _platformBindings.CommitInnateControllers(root, controllers); + _platformBindings!.CommitInnateControllers(root, controllers); } } } \ No newline at end of file diff --git a/Editor/API/AnimatorServices/CloneContext.cs b/Editor/API/AnimatorServices/CloneContext.cs index 8e15210..5618f1e 100644 --- a/Editor/API/AnimatorServices/CloneContext.cs +++ b/Editor/API/AnimatorServices/CloneContext.cs @@ -1,6 +1,9 @@ -using System; +#nullable enable + +using System; using System.Collections.Generic; using System.Collections.Immutable; +using System.Diagnostics.CodeAnalysis; using UnityEditor.Animations; using UnityEngine; using Object = UnityEngine.Object; @@ -61,12 +64,14 @@ public AnimationClip MapClipOnClone(AnimationClip clip) return clip; } - - public bool TryGetValue(T key, out U value) where U: IDisposable + + public bool TryGetValue(T key, out U? value) where U : IDisposable { + if (key == null) throw new ArgumentNullException(nameof(key)); + var rv = _clones.TryGetValue(key, out var tmp); - if (rv) value = (U)tmp; + if (rv) value = (U?)tmp; else value = default; return rv; @@ -74,17 +79,18 @@ public bool TryGetValue(T key, out U value) where U: IDisposable public void Add(T key, U value) where U: IDisposable { + if (key == null) throw new ArgumentNullException(nameof(key)); _clones.Add(key, value); } - private U GetOrClone(T key, Func clone) where U : class, IDisposable + private U? GetOrClone(T? key, Func clone) where U : class, IDisposable { try { _cloneDepth++; if (key == null || (key is Object obj && obj == null)) return null; - if (TryGetValue(key, out U value)) return value; + if (TryGetValue(key, out U? value)) return value; value = clone(this, key); _clones[key] = value; return value; @@ -124,49 +130,57 @@ internal int AllocateSingleVirtualLayer() return _nextVirtualLayer++; } - public VirtualAnimatorController Clone(RuntimeAnimatorController controller) + [return: NotNullIfNotNull("controller")] + public VirtualAnimatorController? Clone(RuntimeAnimatorController? controller) { using var _ = new ProfilerScope("Clone Animator Controller", controller); return GetOrClone(controller, VirtualAnimatorController.Clone); } - - public VirtualLayer Clone(AnimatorControllerLayer layer, int index) + + [return: NotNullIfNotNull("layer")] + public VirtualLayer? Clone(AnimatorControllerLayer? layer, int index) { using var _ = new ProfilerScope("Clone Animator Layer"); - return GetOrClone(layer, (ctx, obj) => VirtualLayer.Clone(ctx, obj, index)); + return GetOrClone(layer, (ctx, obj) => VirtualLayer.Clone(ctx, obj, index)!); } - - public VirtualStateMachine Clone(AnimatorStateMachine stateMachine) + + [return: NotNullIfNotNull("stateMachine")] + public VirtualStateMachine? Clone(AnimatorStateMachine? stateMachine) { using var _ = new ProfilerScope("Clone State Machine", stateMachine); return GetOrClone(stateMachine, VirtualStateMachine.Clone); } - public VirtualStateTransition Clone(AnimatorStateTransition transition) + [return: NotNullIfNotNull("transition")] + public VirtualStateTransition? Clone(AnimatorStateTransition? transition) { using var _ = new ProfilerScope("Clone State Transition", transition); return GetOrClone(transition, VirtualStateTransition.Clone); } - public VirtualTransition Clone(AnimatorTransition transition) + [return: NotNullIfNotNull("transition")] + public VirtualTransition? Clone(AnimatorTransition? transition) { using var _ = new ProfilerScope("Clone Transition", transition); return GetOrClone(transition, VirtualTransition.Clone); } - public VirtualState Clone(AnimatorState state) + [return: NotNullIfNotNull("state")] + public VirtualState? Clone(AnimatorState? state) { using var _ = new ProfilerScope("Clone State", state); return GetOrClone(state, VirtualState.Clone); } - public VirtualMotion Clone(Motion m) + [return: NotNullIfNotNull("m")] + public VirtualMotion? Clone(Motion? m) { using var _ = new ProfilerScope("Clone Motion", m); return GetOrClone(m, VirtualMotion.Clone); } - public VirtualClip Clone(AnimationClip clip) + [return: NotNullIfNotNull("clip")] + public VirtualClip? Clone(AnimationClip? clip) { using var _ = new ProfilerScope("Clone Clip", clip); return GetOrClone(clip, VirtualClip.Clone); diff --git a/Editor/API/AnimatorServices/ECBComparator.cs b/Editor/API/AnimatorServices/ECBComparator.cs index 9ace0a6..78528b9 100644 --- a/Editor/API/AnimatorServices/ECBComparator.cs +++ b/Editor/API/AnimatorServices/ECBComparator.cs @@ -1,4 +1,6 @@ -using System; +#nullable enable + +using System; using System.Collections.Generic; using UnityEditor; diff --git a/Editor/API/AnimatorServices/ICommitable.cs b/Editor/API/AnimatorServices/ICommitable.cs index 8c85632..501648a 100644 --- a/Editor/API/AnimatorServices/ICommitable.cs +++ b/Editor/API/AnimatorServices/ICommitable.cs @@ -1,4 +1,7 @@ -using System.Collections.Generic; +#nullable enable + +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; using UnityEngine; namespace nadena.dev.ndmf.animator @@ -16,6 +19,7 @@ internal interface ICommitable /// Fills in all fields of the destination unity object. This may recurse back into the CommitContext. /// /// + /// Object returned from Prepare void Commit(CommitContext context, T obj); } @@ -25,7 +29,8 @@ internal class CommitContext private readonly Dictionary _virtIndexToVirtLayer = new(); private readonly Dictionary _virtLayerToPhysIndex = new(); - internal R CommitObject(ICommitable obj) where R : class + [return: NotNullIfNotNull("obj")] + internal R? CommitObject(ICommitable? obj) where R : class { if (obj == null) return null; if (_commitCache.TryGetValue(obj, out var result)) return (R)result; diff --git a/Editor/API/AnimatorServices/LayerPriority.cs b/Editor/API/AnimatorServices/LayerPriority.cs index 2221cfc..1f574a3 100644 --- a/Editor/API/AnimatorServices/LayerPriority.cs +++ b/Editor/API/AnimatorServices/LayerPriority.cs @@ -1,21 +1,23 @@ -using System; +#nullable enable + +using System; namespace nadena.dev.ndmf.animator { - public struct LayerPriority : IComparable + public struct LayerPriority : IComparable, IEquatable { public static LayerPriority Default = new(); - - internal int Priority; + + private readonly int _priority; public LayerPriority(int priority) { - Priority = priority; + _priority = priority; } public int CompareTo(LayerPriority other) { - if (Priority != other.Priority) return Priority.CompareTo(other.Priority); + if (_priority != other._priority) return _priority.CompareTo(other._priority); return 0; } @@ -52,12 +54,17 @@ public int CompareTo(LayerPriority other) public override bool Equals(object obj) { - return obj is LayerPriority other && this == other; + return obj is LayerPriority other && Equals(other); } public override int GetHashCode() { - return Priority.GetHashCode(); + return _priority; + } + + public bool Equals(LayerPriority other) + { + return _priority == other._priority; } } } \ No newline at end of file diff --git a/Editor/API/AnimatorServices/ObjectPathRemapper.cs b/Editor/API/AnimatorServices/ObjectPathRemapper.cs index 5546bdf..64dc6d9 100644 --- a/Editor/API/AnimatorServices/ObjectPathRemapper.cs +++ b/Editor/API/AnimatorServices/ObjectPathRemapper.cs @@ -1,4 +1,6 @@ -using System.Collections.Generic; +#nullable enable + +using System.Collections.Generic; using nadena.dev.ndmf.runtime; using UnityEngine; @@ -53,9 +55,13 @@ private void UpdateCache() foreach (var kvp in _objectToOriginalPaths) { + var virtualPath = GetVirtualPathForObject(kvp.Key); + + if (virtualPath == null) continue; + foreach (var path in kvp.Value) { - _originalToMappedPath[path] = GetVirtualPathForObject(kvp.Key); + _originalToMappedPath[path] = virtualPath; } } } @@ -70,18 +76,18 @@ public void RecordObjectTree(Transform subtree) } } - public GameObject GetObjectForPath(string path) + public GameObject? GetObjectForPath(string path) { var xform = _pathToObject.GetValueOrDefault(path); return xform ? xform.gameObject : null; } - public string GetVirtualPathForObject(GameObject obj) + public string? GetVirtualPathForObject(GameObject obj) { return GetVirtualPathForObject(obj.transform); } - public string GetVirtualPathForObject(Transform t) + public string? GetVirtualPathForObject(Transform t) { if (_objectToOriginalPaths.TryGetValue(t, out var paths)) { diff --git a/Editor/API/AnimatorServices/VirtualObjects/SyncedLayerOverrideAccess.cs b/Editor/API/AnimatorServices/VirtualObjects/SyncedLayerOverrideAccess.cs index 36fd2e5..27cff2f 100644 --- a/Editor/API/AnimatorServices/VirtualObjects/SyncedLayerOverrideAccess.cs +++ b/Editor/API/AnimatorServices/VirtualObjects/SyncedLayerOverrideAccess.cs @@ -1,4 +1,5 @@ -using System; +#nullable enable +using System; using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; using System.Linq; @@ -17,14 +18,14 @@ namespace nadena.dev.ndmf.animator [SuppressMessage("ReSharper", "InconsistentNaming")] internal class SyncedLayerOverrideAccess { - public static readonly Func>> + public static readonly Func>?> ExtractStateMotionPairs; public static readonly Action>> SetStateMotionPairs; public static readonly - Func>> + Func>?> ExtractStateBehaviourPairs; public static readonly diff --git a/Editor/API/AnimatorServices/VirtualObjects/VirtualAnimatorController.cs b/Editor/API/AnimatorServices/VirtualObjects/VirtualAnimatorController.cs index aee1e4e..22b725c 100644 --- a/Editor/API/AnimatorServices/VirtualObjects/VirtualAnimatorController.cs +++ b/Editor/API/AnimatorServices/VirtualObjects/VirtualAnimatorController.cs @@ -1,4 +1,6 @@ -using System; +#nullable enable + +using System; using System.Collections.Generic; using System.Collections.Immutable; using System.Linq; @@ -41,8 +43,8 @@ private struct LayerGroup public VirtualAnimatorController(CloneContext context, string name = "") { _context = context; + _parameters = ImmutableDictionary.Empty; Name = name; - Parameters = ImmutableDictionary.Empty; } public void AddLayer(LayerPriority priority, VirtualLayer layer) @@ -73,7 +75,7 @@ public IEnumerable Layers get { return _layers.Values.SelectMany(l => l.Layers); } } - public static VirtualAnimatorController Clone(CloneContext context, RuntimeAnimatorController controller) + internal static VirtualAnimatorController Clone(CloneContext context, RuntimeAnimatorController controller) { switch (controller) { @@ -90,8 +92,9 @@ public static VirtualAnimatorController Clone(CloneContext context, RuntimeAnima private VirtualAnimatorController(CloneContext context, AnimatorController controller) { + _context = context; Name = controller.name; - Parameters = controller.parameters.ToImmutableDictionary(p => p.name); + _parameters = controller.parameters.ToImmutableDictionary(p => p.name); var srcLayers = controller.layers; context.AllocateVirtualLayerSpace(srcLayers.Length); diff --git a/Editor/API/AnimatorServices/VirtualObjects/VirtualBlendTree.cs b/Editor/API/AnimatorServices/VirtualObjects/VirtualBlendTree.cs index cee2dc0..a19180f 100644 --- a/Editor/API/AnimatorServices/VirtualObjects/VirtualBlendTree.cs +++ b/Editor/API/AnimatorServices/VirtualObjects/VirtualBlendTree.cs @@ -1,4 +1,5 @@ -using System.Collections.Generic; +#nullable enable +using System.Collections.Generic; using System.Collections.Immutable; using System.Linq; using UnityEditor; @@ -10,13 +11,12 @@ namespace nadena.dev.ndmf.animator public class VirtualBlendTree : VirtualMotion { private readonly BlendTree _tree; - private VirtualChildMotion _motions; public sealed class VirtualChildMotion { - public VirtualMotion Motion; + public VirtualMotion? Motion; public float CycleOffset; - public string DirectBlendParameter; + public string DirectBlendParameter = "Blend"; public bool Mirror; public float Threshold; public Vector2 Position; @@ -26,32 +26,29 @@ public sealed class VirtualChildMotion private VirtualBlendTree(CloneContext context, BlendTree cloned) { _tree = cloned; + _children = ImmutableList.Empty; context.DeferCall(() => { - Children = _tree.children.Select(m => + Children = _tree.children.Select(m => new VirtualChildMotion { - return new VirtualChildMotion - { - Motion = context.Clone(m.motion), - CycleOffset = m.cycleOffset, - DirectBlendParameter = m.directBlendParameter, - Mirror = m.mirror, - Threshold = m.threshold, - Position = m.position, - TimeScale = m.timeScale - }; + Motion = context.Clone(m.motion), + CycleOffset = m.cycleOffset, + DirectBlendParameter = m.directBlendParameter, + Mirror = m.mirror, + Threshold = m.threshold, + Position = m.position, + TimeScale = m.timeScale }).ToImmutableList(); }); } - public static VirtualBlendTree Clone( + internal static VirtualBlendTree Clone( CloneContext context, BlendTree tree ) { - if (tree == null) return null; - if (context.TryGetValue(tree, out VirtualBlendTree existing)) return existing; + if (context.TryGetValue(tree, out VirtualBlendTree? existing)) return existing!; var cloned = new BlendTree(); EditorUtility.CopySerialized(tree, cloned); @@ -142,7 +139,7 @@ public override void Dispose() protected override IEnumerable _EnumerateChildren() { - return Children.Select(c => c.Motion); + return Children.Where(c => c.Motion != null).Select(c => c.Motion!); } } } \ No newline at end of file diff --git a/Editor/API/AnimatorServices/VirtualObjects/VirtualClip.cs b/Editor/API/AnimatorServices/VirtualObjects/VirtualClip.cs index 0c17f1b..86f9125 100644 --- a/Editor/API/AnimatorServices/VirtualObjects/VirtualClip.cs +++ b/Editor/API/AnimatorServices/VirtualObjects/VirtualClip.cs @@ -1,10 +1,12 @@ -using System; +#nullable enable + +using System; using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; using System.Linq; using JetBrains.Annotations; using UnityEditor; using UnityEngine; -using Debug = System.Diagnostics.Debug; using Object = UnityEngine.Object; namespace nadena.dev.ndmf.animator @@ -75,9 +77,9 @@ public AnimationClipSettings Settings } } - private VirtualMotion _additiveReferencePoseClip; + private VirtualMotion? _additiveReferencePoseClip; - public VirtualMotion AdditiveReferencePoseClip + public VirtualMotion? AdditiveReferencePoseClip { get => _additiveReferencePoseClip; set => _additiveReferencePoseClip = I(value); @@ -115,7 +117,7 @@ private struct CachedCurve { // If null and Dirty is false, the curve has not been cached yet. // If null and Dirty is true, the curve has been deleted. - public T Value; + public T? Value; public bool Dirty; public override string ToString() @@ -140,7 +142,7 @@ public static VirtualClip FromMarker(AnimationClip clip) /// Clones an animation clip into a VirtualClip. The provided BuildContext is used to determine which platform /// to use to query for marker clips; if a marker clip is found, it will be treated as immutable. /// - /// + /// /// /// public static VirtualClip Clone( @@ -148,8 +150,6 @@ public static VirtualClip Clone( AnimationClip clip ) { - if (clip == null) return null; - clip = cloneContext.MapClipOnClone(clip); if (cloneContext.PlatformBindings.IsSpecialMotion(clip)) @@ -157,11 +157,9 @@ AnimationClip clip return FromMarker(clip); } - // workaround Rider warning bug - VirtualClip clonedClip = null; - if (cloneContext?.TryGetValue(clip, out clonedClip) == true) + if (cloneContext.TryGetValue(clip, out VirtualClip? clonedClip)) { - return clonedClip; + return clonedClip!; } var newClip = Object.Instantiate(clip); @@ -320,7 +318,7 @@ public AnimationCurve GetFloatCurve(EditorCurveBinding binding) } } - return cached.Value; + return cached.Value!; } public ObjectReferenceKeyframe[] GetObjectCurve(EditorCurveBinding binding) @@ -334,7 +332,7 @@ public ObjectReferenceKeyframe[] GetObjectCurve(EditorCurveBinding binding) } } - return cached.Value; + return cached.Value!; } public void SetFloatCurve(EditorCurveBinding binding, AnimationCurve curve) @@ -388,7 +386,11 @@ protected override Motion Prepare(object context) return _clip; } - protected override void Commit(object context_, Motion obj) + protected override void Commit( + [SuppressMessage("ReSharper", "InconsistentNaming")] + object context_, + Motion obj + ) { if (IsMarkerClip || !IsDirty) return; @@ -441,8 +443,6 @@ protected override void Commit(object context_, Motion obj) : null; settings.additiveReferencePoseTime = AdditiveReferencePoseTime; AnimationUtility.SetAnimationClipSettings(clip, settings); - - this._clip = null; } public AnimationCurve GetFloatCurve(string path, Type type, string prop) @@ -468,7 +468,6 @@ public void SetObjectCurve(string path, Type type, string prop, ObjectReferenceK public override void Dispose() { if (_clip != null) Object.DestroyImmediate(_clip); - this._clip = null; } } } \ No newline at end of file diff --git a/Editor/API/AnimatorServices/VirtualObjects/VirtualLayer.cs b/Editor/API/AnimatorServices/VirtualObjects/VirtualLayer.cs index 0b78a4e..8413202 100644 --- a/Editor/API/AnimatorServices/VirtualObjects/VirtualLayer.cs +++ b/Editor/API/AnimatorServices/VirtualObjects/VirtualLayer.cs @@ -1,7 +1,10 @@ -using System; +#nullable enable + +using System; using System.Collections.Generic; using System.Collections.Immutable; using System.Linq; +using JetBrains.Annotations; using UnityEditor.Animations; using UnityEngine; using Object = UnityEngine.Object; @@ -11,6 +14,7 @@ namespace nadena.dev.ndmf.animator /// /// A layer within a VirtualAnimatorController /// + [PublicAPI] public class VirtualLayer : VirtualNode, ICommitable, IDisposable { /// @@ -18,8 +22,7 @@ public class VirtualLayer : VirtualNode, ICommitable, I /// even if layer order changes. This will typically be a very large value (>2^16). /// public int VirtualLayerIndex { get; } - - + private VirtualStateMachine _stateMachine; public VirtualStateMachine StateMachine @@ -28,9 +31,9 @@ public VirtualStateMachine StateMachine set => _stateMachine = I(value); } - private AvatarMask _avatarMask; + private AvatarMask? _avatarMask; - public AvatarMask AvatarMask + public AvatarMask? AvatarMask { get => _avatarMask; set => _avatarMask = I(value); @@ -108,14 +111,10 @@ public ImmutableDictionary> S set => _syncedLayerBehaviourOverrides = I(value); } - public static VirtualLayer Clone(CloneContext context, AnimatorControllerLayer layer, int physicalLayerIndex) + internal static VirtualLayer Clone(CloneContext context, AnimatorControllerLayer layer, int physicalLayerIndex) { - if (layer == null) return null; - var clone = new VirtualLayer(context, layer, physicalLayerIndex); - // TODO: motion, behavior overrides - return clone; } @@ -127,7 +126,7 @@ public static VirtualLayer Create(CloneContext context, string name = "(unnamed) private VirtualLayer(CloneContext context, AnimatorControllerLayer layer, int physicalLayerIndex) { VirtualLayerIndex = context.CloneSourceToVirtualLayerIndex(physicalLayerIndex); - Name = layer.name; + _name = layer.name; AvatarMask = layer.avatarMask == null ? null : Object.Instantiate(layer.avatarMask); BlendingMode = layer.blendingMode; DefaultWeight = layer.defaultWeight; @@ -135,21 +134,25 @@ private VirtualLayer(CloneContext context, AnimatorControllerLayer layer, int ph SyncedLayerAffectsTiming = layer.syncedLayerAffectsTiming; SyncedLayerIndex = context.CloneSourceToVirtualLayerIndex(layer.syncedLayerIndex); - StateMachine = VirtualStateMachine.Clone(context, layer.stateMachine); + _stateMachine = context.Clone(layer.stateMachine); _syncedLayerMotionOverrides = SyncedLayerOverrideAccess.ExtractStateMotionPairs(layer) - ?.ToImmutableDictionary(kvp => context.Clone(kvp.Key), kvp => context.Clone(kvp.Value)); + ?.ToImmutableDictionary(kvp => context.Clone(kvp.Key), + kvp => context.Clone(kvp.Value)) + ?? ImmutableDictionary.Empty; // TODO: Apply state behavior import processing _syncedLayerBehaviourOverrides = SyncedLayerOverrideAccess.ExtractStateBehaviourPairs(layer) ?.ToImmutableDictionary(kvp => context.Clone(kvp.Key), - kvp => kvp.Value.Cast().ToImmutableList()); + kvp => kvp.Value.Cast().ToImmutableList()) + ?? ImmutableDictionary> + .Empty; } private VirtualLayer(CloneContext context, string name) { VirtualLayerIndex = context.AllocateSingleVirtualLayer(); - Name = name; + _name = name; AvatarMask = null; BlendingMode = AnimatorLayerBlendingMode.Override; DefaultWeight = 1; @@ -157,7 +160,10 @@ private VirtualLayer(CloneContext context, string name) SyncedLayerAffectsTiming = false; SyncedLayerIndex = -1; - StateMachine = VirtualStateMachine.Create(context, name); + _stateMachine = VirtualStateMachine.Create(context, name); + _syncedLayerMotionOverrides = ImmutableDictionary.Empty; + _syncedLayerBehaviourOverrides = + ImmutableDictionary>.Empty; } AnimatorControllerLayer ICommitable.Prepare(CommitContext context) @@ -182,19 +188,14 @@ void ICommitable.Commit(CommitContext context, Animator obj.syncedLayerIndex = context.VirtualToPhysicalLayerIndex(SyncedLayerIndex); obj.stateMachine = context.CommitObject(StateMachine); - var motionOverrides = SyncedLayerMotionOverrides ?? ImmutableDictionary.Empty; - - SyncedLayerOverrideAccess.SetStateMotionPairs(obj, motionOverrides.Select(kvp => + SyncedLayerOverrideAccess.SetStateMotionPairs(obj, SyncedLayerMotionOverrides.Select(kvp => new KeyValuePair( context.CommitObject(kvp.Key), context.CommitObject(kvp.Value) ))); - var behaviourOverrides = SyncedLayerBehaviourOverrides ?? - ImmutableDictionary>.Empty; - // TODO: commit state behaviours - SyncedLayerOverrideAccess.SetStateBehaviourPairs(obj, behaviourOverrides.Select(kvp => + SyncedLayerOverrideAccess.SetStateBehaviourPairs(obj, SyncedLayerBehaviourOverrides.Select(kvp => new KeyValuePair( context.CommitObject(kvp.Key), kvp.Value.Cast().ToArray() diff --git a/Editor/API/AnimatorServices/VirtualObjects/VirtualMotion.cs b/Editor/API/AnimatorServices/VirtualObjects/VirtualMotion.cs index 9a64c28..4eb9b4e 100644 --- a/Editor/API/AnimatorServices/VirtualObjects/VirtualMotion.cs +++ b/Editor/API/AnimatorServices/VirtualObjects/VirtualMotion.cs @@ -1,4 +1,6 @@ -using System; +#nullable enable + +using System; using UnityEditor.Animations; using UnityEngine; diff --git a/Editor/API/AnimatorServices/VirtualObjects/VirtualNode.cs b/Editor/API/AnimatorServices/VirtualObjects/VirtualNode.cs index 87c6ea0..072b53c 100644 --- a/Editor/API/AnimatorServices/VirtualObjects/VirtualNode.cs +++ b/Editor/API/AnimatorServices/VirtualObjects/VirtualNode.cs @@ -1,4 +1,6 @@ -using System; +#nullable enable + +using System; using System.Collections.Generic; namespace nadena.dev.ndmf.animator @@ -6,7 +8,7 @@ namespace nadena.dev.ndmf.animator [ExcludeFromDocs] public abstract class VirtualNode { - private Action _lastCacheObserver; + private Action? _lastCacheObserver; internal VirtualNode() { @@ -24,7 +26,7 @@ internal T I(T val) return val; } - internal void RegisterCacheObserver(Action observer) + internal void RegisterCacheObserver(Action? observer) { if (observer != _lastCacheObserver && _lastCacheObserver != null) { diff --git a/Editor/API/AnimatorServices/VirtualObjects/VirtualState.cs b/Editor/API/AnimatorServices/VirtualObjects/VirtualState.cs index f9b66dc..96cef58 100644 --- a/Editor/API/AnimatorServices/VirtualObjects/VirtualState.cs +++ b/Editor/API/AnimatorServices/VirtualObjects/VirtualState.cs @@ -1,4 +1,6 @@ -using System; +#nullable enable + +using System; using System.Collections.Generic; using System.Collections.Immutable; using System.Linq; @@ -10,11 +12,12 @@ namespace nadena.dev.ndmf.animator { + [PublicAPI] public class VirtualState : VirtualNode, ICommitable, IDisposable { private AnimatorState _state; - private ImmutableList _behaviours; + private ImmutableList _behaviours = ImmutableList.Empty; public ImmutableList Behaviours { @@ -27,9 +30,7 @@ public static VirtualState Clone( AnimatorState state ) { - if (state == null) return null; - - if (context.TryGetValue(state, out VirtualState clone)) return clone; + if (context.TryGetValue(state, out VirtualState? clone)) return clone!; var clonedState = new AnimatorState(); // We can't use Instantiate for AnimatorStates, for some reason... @@ -47,7 +48,7 @@ private VirtualState() { _state = new AnimatorState(); Behaviours = ImmutableList.Empty; - Transitions = ImmutableList.Empty; + _transitions = ImmutableList.Empty; } private VirtualState(CloneContext context, AnimatorState clonedState) @@ -56,13 +57,22 @@ private VirtualState(CloneContext context, AnimatorState clonedState) // TODO: Should we rewrite any internal properties of these StateMachineBehaviours? Behaviours = _state.behaviours.Select(b => Object.Instantiate(b)).ToImmutableList(); - context.DeferCall(() => { Transitions = _state.transitions.Select(context.Clone).ToImmutableList(); }); + + _transitions = ImmutableList.Empty; + context.DeferCall(() => + { + Transitions = _state.transitions + .Where(t => t != null) + .Select(context.Clone) + .ToImmutableList()!; + }); + Motion = context.Clone(_state.motion); } - private VirtualMotion _motion; + private VirtualMotion? _motion; - public VirtualMotion Motion + public VirtualMotion? Motion { get => _motion; set => _motion = I(value); @@ -80,8 +90,7 @@ public float CycleOffset set => _state.cycleOffset = I(value); } - [CanBeNull] - public string CycleOffsetParameter + public string? CycleOffsetParameter { get => _state.cycleOffsetParameterActive ? _state.cycleOffsetParameter : null; set @@ -104,8 +113,7 @@ public bool Mirror set => _state.mirror = I(value); } - [CanBeNull] - public string MirrorParameter + public string? MirrorParameter { get => _state.mirrorParameterActive ? _state.mirrorParameter : null; set @@ -124,8 +132,7 @@ public float Speed set => _state.speed = I(value); } - [CanBeNull] - public string SpeedParameter + public string? SpeedParameter { get => _state.speedParameterActive ? _state.speedParameter : null; set @@ -142,8 +149,7 @@ public string Tag set => _state.tag = I(value); } - [CanBeNull] - public string TimeParameter + public string? TimeParameter { get => _state.timeParameterActive ? _state.timeParameter : null; set @@ -192,11 +198,10 @@ void IDisposable.Dispose() { Object.DestroyImmediate(behaviour); } - - Behaviours.Clear(); + + Behaviours = Behaviours.Clear(); if (_state != null) Object.DestroyImmediate(_state); - _state = null; } public override string ToString() diff --git a/Editor/API/AnimatorServices/VirtualObjects/VirtualStateMachine.cs b/Editor/API/AnimatorServices/VirtualObjects/VirtualStateMachine.cs index 3e39ab0..f835c1d 100644 --- a/Editor/API/AnimatorServices/VirtualObjects/VirtualStateMachine.cs +++ b/Editor/API/AnimatorServices/VirtualObjects/VirtualStateMachine.cs @@ -1,8 +1,9 @@ -using System; +#nullable enable + +using System; using System.Collections.Generic; using System.Collections.Immutable; using System.Linq; -using JetBrains.Annotations; using UnityEditor.Animations; using UnityEngine; using Object = UnityEngine.Object; @@ -19,8 +20,7 @@ public class VirtualStateMachine : VirtualNode, ICommitable t != null) + .Select(context.Clone) + .ToImmutableList()!; vsm.Behaviours = stateMachine.behaviours.Select(Object.Instantiate).ToImmutableList(); vsm.DefaultState = context.Clone(stateMachine.defaultState); vsm.EntryPosition = stateMachine.entryPosition; vsm.EntryTransitions = stateMachine.entryTransitions - .Select(context.Clone).ToImmutableList(); + .Where(t => t != null) + .Select(context.Clone) + .ToImmutableList()!; vsm.ExitPosition = stateMachine.exitPosition; vsm.ParentStateMachinePosition = stateMachine.parentStateMachinePosition; - vsm.StateMachines = stateMachine.stateMachines.Select(sm => new VirtualChildStateMachine - { - StateMachine = context.Clone(sm.stateMachine), - Position = sm.position - }).ToImmutableList(); - - vsm.States = stateMachine.states.Select(s => new VirtualChildState - { - State = context.Clone(s.state), - Position = s.position - }).ToImmutableList(); + vsm.StateMachines = stateMachine.stateMachines + .Where(sm => sm.stateMachine != null) + .Select(sm => new VirtualChildStateMachine + { + StateMachine = context.Clone(sm.stateMachine), + Position = sm.position + }).ToImmutableList(); + + vsm.States = stateMachine.states + .Where(s => s.state != null) + .Select(s => new VirtualChildState + { + State = context.Clone(s.state), + Position = s.position + }).ToImmutableList(); vsm.StateMachineTransitions = stateMachine.stateMachines + .Where(sm => sm.stateMachine != null) .ToImmutableDictionary( sm => context.Clone(sm.stateMachine), sm => stateMachine.GetStateMachineTransitions(sm.stateMachine) - .Select(context.Clone).ToImmutableList() - ); + .Where(t => t != null) + .Select(context.Clone) + .ToImmutableList() + )!; }); return vsm; @@ -69,24 +80,22 @@ private VirtualStateMachine(CloneContext context, string name = "") { _context = context; _stateMachine = new AnimatorStateMachine(); - Name = name; + _name = name; AnyStatePosition = _stateMachine.anyStatePosition; EntryPosition = _stateMachine.entryPosition; ExitPosition = _stateMachine.exitPosition; - EntryTransitions = ImmutableList.Empty; - AnyStateTransitions = ImmutableList.Empty; - Behaviours = ImmutableList.Empty; - StateMachines = ImmutableList.Empty; - States = ImmutableList.Empty; - StateMachineTransitions = ImmutableDictionary>.Empty; + _entryTransitions = ImmutableList.Empty; + _anyStateTransitions = ImmutableList.Empty; + _behaviours = ImmutableList.Empty; + _stateMachines = ImmutableList.Empty; + _states = ImmutableList.Empty; + _stateMachineTransitions = ImmutableDictionary>.Empty; } AnimatorStateMachine ICommitable.Prepare(CommitContext context) { - var tmp = _stateMachine; - _stateMachine = null; - return tmp; + return _stateMachine; } void ICommitable.Commit(CommitContext context, AnimatorStateMachine obj) @@ -214,9 +223,9 @@ public ImmutableDictionary set => _stateMachineTransitions = I(value); } - private VirtualState _defaultState; + private VirtualState? _defaultState; - public VirtualState DefaultState + public VirtualState? DefaultState { get => _defaultState; set => _defaultState = I(value); @@ -239,7 +248,6 @@ public void Dispose() if (_stateMachine != null) { Object.DestroyImmediate(_stateMachine); - _stateMachine = null; } } @@ -268,7 +276,7 @@ protected override IEnumerable _EnumerateChildren() } } - public VirtualState AddState(string name, [CanBeNull] VirtualMotion motion = null, Vector3? position = null) + public VirtualState AddState(string name, VirtualMotion? motion = null, Vector3? position = null) { var state = VirtualState.Create(_context, name); diff --git a/Editor/API/AnimatorServices/VirtualObjects/VirtualStateTransition.cs b/Editor/API/AnimatorServices/VirtualObjects/VirtualStateTransition.cs index b3ffa52..e6e17bb 100644 --- a/Editor/API/AnimatorServices/VirtualObjects/VirtualStateTransition.cs +++ b/Editor/API/AnimatorServices/VirtualObjects/VirtualStateTransition.cs @@ -1,7 +1,11 @@ -using UnityEditor.Animations; +#nullable enable + +using JetBrains.Annotations; +using UnityEditor.Animations; namespace nadena.dev.ndmf.animator { + [PublicAPI] public class VirtualStateTransition : VirtualTransitionBase { private readonly AnimatorStateTransition _stateTransition; diff --git a/Editor/API/AnimatorServices/VirtualObjects/VirtualTransition.cs b/Editor/API/AnimatorServices/VirtualObjects/VirtualTransition.cs index ca06db4..311b7d3 100644 --- a/Editor/API/AnimatorServices/VirtualObjects/VirtualTransition.cs +++ b/Editor/API/AnimatorServices/VirtualObjects/VirtualTransition.cs @@ -1,4 +1,6 @@ -using UnityEditor.Animations; +#nullable enable + +using UnityEditor.Animations; namespace nadena.dev.ndmf.animator { diff --git a/Editor/API/AnimatorServices/VirtualObjects/VirtualTransitionBase.cs b/Editor/API/AnimatorServices/VirtualObjects/VirtualTransitionBase.cs index a41de2e..1604ce3 100644 --- a/Editor/API/AnimatorServices/VirtualObjects/VirtualTransitionBase.cs +++ b/Editor/API/AnimatorServices/VirtualObjects/VirtualTransitionBase.cs @@ -1,17 +1,23 @@ -using System; +#nullable enable + +using System; using System.Collections.Generic; using System.Collections.Immutable; +using JetBrains.Annotations; using UnityEditor.Animations; using Object = UnityEngine.Object; namespace nadena.dev.ndmf.animator { + [PublicAPI] public class VirtualTransitionBase : VirtualNode, ICommitable, IDisposable { protected AnimatorTransitionBase _transition; - private ImmutableList _conditions; - internal VirtualTransitionBase(CloneContext context, AnimatorTransitionBase cloned) + // null indicates we've deferred reading the conditions from the transition object + private ImmutableList? _conditions; + + internal VirtualTransitionBase(CloneContext? context, AnimatorTransitionBase cloned) { _transition = cloned; @@ -53,9 +59,9 @@ public ImmutableList Conditions } } - private VirtualState _destinationState; + private VirtualState? _destinationState; - public VirtualState DestinationState + public VirtualState? DestinationState { get => _destinationState; private set @@ -65,9 +71,9 @@ private set } } - private VirtualStateMachine _destinationStateMachine; + private VirtualStateMachine? _destinationStateMachine; - public VirtualStateMachine DestinationStateMachine + public VirtualStateMachine? DestinationStateMachine { get => _destinationStateMachine; private set @@ -95,11 +101,9 @@ protected static VirtualTransitionBase CloneInternal( AnimatorTransitionBase transition ) { - if (transition == null) return null; + if (context.TryGetValue(transition, out VirtualStateTransition? clone)) return clone!; - if (context.TryGetValue(transition, out VirtualStateTransition clone)) return clone; - - var cloned = Object.Instantiate(transition); + var cloned = Object.Instantiate(transition)!; cloned.name = transition.name; switch (cloned) @@ -140,8 +144,6 @@ AnimatorTransitionBase ICommitable.Prepare(CommitContext void ICommitable.Commit(CommitContext context, AnimatorTransitionBase obj) { - _transition = null; - if (DestinationState != null) { obj.destinationState = context.CommitObject(DestinationState); @@ -162,7 +164,6 @@ void ICommitable.Commit(CommitContext context, AnimatorT public void Dispose() { if (_transition != null) Object.DestroyImmediate(_transition); - _transition = null; } protected override IEnumerable _EnumerateChildren()