From ef16c56a2aa98967c15cdf8fb343a08967151787 Mon Sep 17 00:00:00 2001 From: anatawa12 Date: Fri, 4 Oct 2024 16:18:28 +0900 Subject: [PATCH 01/11] chore: separate ValueInfo for float and Object phase 1: make generic --- Editor/AnimatorParserV2/AnimationParser.cs | 20 +++--- .../AnimatorControllerPropModNode.cs | 34 +++++----- Editor/AnimatorParserV2/AnimatorParser.cs | 32 ++++----- .../AnimatorParserDebugWindow.cs | 6 +- Editor/AnimatorParserV2/NodeContainer.cs | 32 ++++----- Editor/AnimatorParserV2/PropModNode.cs | 68 ++++++++++--------- Editor/AnimatorParserV2/Utilities.cs | 16 ++--- Editor/ContextExtensions.cs | 2 +- Editor/ObjectMapping/PropertyInfo.cs | 8 +-- Editor/Processors/MergePhysBoneProcessor.cs | 2 +- Editor/Utils/AnimationLocation.cs | 4 +- Test~/AnimatorParser/TestUtil.cs | 2 +- 12 files changed, 115 insertions(+), 111 deletions(-) diff --git a/Editor/AnimatorParserV2/AnimationParser.cs b/Editor/AnimatorParserV2/AnimationParser.cs index bac7634c2..c9181ec2a 100644 --- a/Editor/AnimatorParserV2/AnimationParser.cs +++ b/Editor/AnimatorParserV2/AnimationParser.cs @@ -49,10 +49,10 @@ private ImmutableNodeContainer ParseBlendTree(GameObject root, BlendTree blendTr var children = blendTree.children; return NodesMerger.Merge< - ImmutableNodeContainer, ImmutablePropModNode, ImmutablePropModNode, + ImmutableNodeContainer, ImmutablePropModNode>, ImmutablePropModNode>, BlendTreeElement, BlendTreeElement, - ImmutableNodeContainer, ImmutableNodeContainer, ImmutablePropModNode, - ImmutablePropModNode, + ImmutableNodeContainer, ImmutableNodeContainer, ImmutablePropModNode>, + ImmutablePropModNode>, BlendTreeMergeProperty >(children.Select(x => ParseMotionInner(root, x.motion, mapping)), new BlendTreeMergeProperty(blendTree.blendType)); @@ -60,10 +60,10 @@ private ImmutableNodeContainer ParseBlendTree(GameObject root, BlendTree blendTr internal readonly struct BlendTreeMergeProperty : IMergeProperty1< - ImmutableNodeContainer, ImmutablePropModNode, ImmutablePropModNode, + ImmutableNodeContainer, ImmutablePropModNode>, ImmutablePropModNode>, BlendTreeElement, BlendTreeElement, - ImmutableNodeContainer, ImmutableNodeContainer, ImmutablePropModNode, - ImmutablePropModNode + ImmutableNodeContainer, ImmutableNodeContainer, ImmutablePropModNode>, + ImmutablePropModNode> > { private readonly BlendTreeType _blendType; @@ -77,15 +77,15 @@ public BlendTreeMergeProperty(BlendTreeType blendType) public ImmutableNodeContainer GetContainer(ImmutableNodeContainer source) => source; public BlendTreeElement GetIntermediate(ImmutableNodeContainer source, - ImmutablePropModNode node, int index) => new BlendTreeElement(index, node); + ImmutablePropModNode> node, int index) => new BlendTreeElement(index, node); public BlendTreeElement GetIntermediate(ImmutableNodeContainer source, - ImmutablePropModNode node, int index) => new BlendTreeElement(index, node); + ImmutablePropModNode> node, int index) => new BlendTreeElement(index, node); - public ImmutablePropModNode MergeNode(List> nodes, int sourceCount) => + public ImmutablePropModNode> MergeNode(List> nodes, int sourceCount) => new BlendTreeNode(nodes, _blendType, partial: nodes.Count != sourceCount); - public ImmutablePropModNode MergeNode(List> nodes, int sourceCount) => + public ImmutablePropModNode> MergeNode(List> nodes, int sourceCount) => new BlendTreeNode(nodes, _blendType, partial: nodes.Count != sourceCount); } diff --git a/Editor/AnimatorParserV2/AnimatorControllerPropModNode.cs b/Editor/AnimatorParserV2/AnimatorControllerPropModNode.cs index dfd0057e6..9f4b79e90 100644 --- a/Editor/AnimatorParserV2/AnimatorControllerPropModNode.cs +++ b/Editor/AnimatorParserV2/AnimatorControllerPropModNode.cs @@ -7,7 +7,7 @@ namespace Anatawa12.AvatarOptimizer.AnimatorParsersV2 { - class HumanoidAnimatorPropModNode : ComponentPropModNode + class HumanoidAnimatorPropModNode : ComponentPropModNode, Animator> { public HumanoidAnimatorPropModNode(Animator component) : base(component) { @@ -17,14 +17,14 @@ public HumanoidAnimatorPropModNode(Animator component) : base(component) public override bool AppliedAlways => true; } - internal readonly struct PlayableLayerNodeInfo : ILayer + internal readonly struct PlayableLayerNodeInfo : ILayer> where T : notnull { public AnimatorWeightState Weight { get; } public AnimatorLayerBlendingMode BlendingMode { get; } public int LayerIndex { get; } public readonly AnimatorControllerPropModNode Node; - PropModNode ILayer.Node => Node; + PropModNode> ILayer>.Node => Node; IPropModNode ILayer.Node => Node; public PlayableLayerNodeInfo(AnimatorWeightState weight, AnimatorLayerBlendingMode blendingMode, @@ -45,7 +45,7 @@ public PlayableLayerNodeInfo(AnimatorControllerPropModNode node, int layerInd } } - class AnimatorPropModNode : ComponentPropModNode + class AnimatorPropModNode : ComponentPropModNode, Animator> where T : notnull { private readonly IEnumerable> _layersReversed; @@ -75,14 +75,14 @@ public AnimatorPropModNode(Animator component,IEnumerable x.Node.ContextReferences)); } - internal readonly struct AnimatorLayerNodeInfo : ILayer + internal readonly struct AnimatorLayerNodeInfo : ILayer> where T : notnull { public AnimatorWeightState Weight { get; } public AnimatorLayerBlendingMode BlendingMode { get; } public int LayerIndex { get; } public readonly AnimatorLayerPropModNode Node; - PropModNode ILayer.Node => Node; + PropModNode> ILayer>.Node => Node; IPropModNode ILayer.Node => Node; public AnimatorLayerNodeInfo(AnimatorWeightState weight, AnimatorLayerBlendingMode blendingMode, @@ -95,7 +95,7 @@ public AnimatorLayerNodeInfo(AnimatorWeightState weight, AnimatorLayerBlendingMo } } - class AnimatorControllerPropModNode : PropModNode + class AnimatorControllerPropModNode : PropModNode> where T : notnull { private readonly IEnumerable> _layersReversed; @@ -133,13 +133,13 @@ internal enum AnimatorWeightState Variable } - internal class AnimatorLayerPropModNode : ImmutablePropModNode + internal class AnimatorLayerPropModNode : ImmutablePropModNode> where T : notnull { - private readonly IEnumerable> _children; + private readonly IEnumerable>> _children; private readonly bool _partial; - public AnimatorLayerPropModNode(IEnumerable> children, bool partial) + public AnimatorLayerPropModNode(ICollection>> children, bool partial) { // expected to pass list or array // ReSharper disable once PossibleMultipleEnumeration @@ -152,25 +152,25 @@ public AnimatorLayerPropModNode(IEnumerable> childre public override bool AppliedAlways => !_partial && _children.All(x => x.AppliedAlways); public override ValueInfo Value => NodeImplUtils.ConstantInfoForSideBySide(_children); public override IEnumerable ContextReferences => _children.SelectMany(x => x.ContextReferences); - public IEnumerable> Children => _children; + public IEnumerable>> Children => _children; } - internal class AnimatorStatePropModNode : ImmutablePropModNode - where T : notnull + internal class AnimatorStatePropModNode : ImmutablePropModNode + where TValueInfo : struct, IValueInfo { - private readonly ImmutablePropModNode _node; + private readonly ImmutablePropModNode _node; private readonly AnimatorState _state; - public AnimatorStatePropModNode(ImmutablePropModNode node, AnimatorState state) + public AnimatorStatePropModNode(ImmutablePropModNode node, AnimatorState state) { _node = node; _state = state; } - public ImmutablePropModNode Node => _node; + public ImmutablePropModNode Node => _node; public AnimatorState State => _state; public override bool AppliedAlways => _node.AppliedAlways; - public override ValueInfo Value => _node.Value; + public override TValueInfo Value => _node.Value; public override IEnumerable ContextReferences => _node.ContextReferences; } } diff --git a/Editor/AnimatorParserV2/AnimatorParser.cs b/Editor/AnimatorParserV2/AnimatorParser.cs index a093ee915..bf64b3ea4 100644 --- a/Editor/AnimatorParserV2/AnimatorParser.cs +++ b/Editor/AnimatorParserV2/AnimatorParser.cs @@ -136,7 +136,7 @@ public override void ModifyProperties(Component component, IEnumerable p { foreach (var prop in properties) { - _modifications.Add(component, prop, new VariableComponentPropModNode(Modifier!), true); + _modifications.Add(component, prop, new VariableComponentPropModNode(Modifier!), true); } } } @@ -284,7 +284,7 @@ void MergeLayer( { foreach (var shape in MmdBlendShapeNames) modifications.Add(bodySkinnedMesh, $"blendShape.{shape}", - new VariableComponentPropModNode(descriptor), true); + new VariableComponentPropModNode(descriptor), true); } } @@ -319,7 +319,7 @@ private static ComponentNodeContainer CollectBlendShapeProxyModifications(BuildC var blendShapePropName = $"blendShape.{skinnedMeshRenderer.sharedMesh.GetBlendShapeName(binding.Index)}"; nodes.Add(skinnedMeshRenderer, blendShapePropName, - new VariableComponentPropModNode(vrmBlendShapeProxy)); + new VariableComponentPropModNode(vrmBlendShapeProxy)); } // Currently, MaterialValueBindings are guaranteed to not change (MaterialName, in particular) @@ -344,7 +344,7 @@ private static ComponentNodeContainer CollectVrm10InstanceModifications( BuildCo var blendShapePropName = $"blendShape.{skinnedMeshRenderer.sharedMesh.GetBlendShapeName(binding.Index)}"; nodes.Add(skinnedMeshRenderer, blendShapePropName, - new VariableComponentPropModNode(vrm10Instance)); + new VariableComponentPropModNode(vrm10Instance)); } // Currently, MaterialValueBindings are guaranteed to not change (MaterialName, in particular) @@ -449,37 +449,37 @@ public AnimatorLayerNodeContainer ParseAnimatorControllerLayer( return NodesMerger.Merge< AnimatorLayerNodeContainer, AnimatorLayerPropModNode, AnimatorLayerPropModNode, - AnimatorStatePropModNode, AnimatorStatePropModNode, + AnimatorStatePropModNode>, AnimatorStatePropModNode>, (AnimatorState, ImmutableNodeContainer), - ImmutableNodeContainer, ImmutablePropModNode, ImmutablePropModNode, + ImmutableNodeContainer, ImmutablePropModNode>, ImmutablePropModNode>, LayerMerger >(parsedMotions, default); } struct LayerMerger : IMergeProperty1< AnimatorLayerNodeContainer, AnimatorLayerPropModNode, AnimatorLayerPropModNode, - AnimatorStatePropModNode, AnimatorStatePropModNode, + AnimatorStatePropModNode>, AnimatorStatePropModNode>, (AnimatorState, ImmutableNodeContainer), - ImmutableNodeContainer, ImmutablePropModNode, ImmutablePropModNode + ImmutableNodeContainer, ImmutablePropModNode>, ImmutablePropModNode> > { public AnimatorLayerNodeContainer CreateContainer() => new AnimatorLayerNodeContainer(); public ImmutableNodeContainer GetContainer((AnimatorState, ImmutableNodeContainer) source) => source.Item2; - public AnimatorStatePropModNode GetIntermediate((AnimatorState, ImmutableNodeContainer) source, - ImmutablePropModNode node, int index) => - new AnimatorStatePropModNode(node, source.Item1); + public AnimatorStatePropModNode> GetIntermediate((AnimatorState, ImmutableNodeContainer) source, + ImmutablePropModNode> node, int index) => + new AnimatorStatePropModNode>(node, source.Item1); - public AnimatorStatePropModNode GetIntermediate((AnimatorState, ImmutableNodeContainer) source, - ImmutablePropModNode node, int index) => - new AnimatorStatePropModNode(node, source.Item1); + public AnimatorStatePropModNode> GetIntermediate((AnimatorState, ImmutableNodeContainer) source, + ImmutablePropModNode> node, int index) => + new AnimatorStatePropModNode>(node, source.Item1); public AnimatorLayerPropModNode - MergeNode(List> nodes, int sourceCount) => + MergeNode(List>> nodes, int sourceCount) => new AnimatorLayerPropModNode(nodes, nodes.Count != sourceCount); public AnimatorLayerPropModNode - MergeNode(List> nodes, int sourceCount) => + MergeNode(List>> nodes, int sourceCount) => new AnimatorLayerPropModNode(nodes, nodes.Count != sourceCount); } diff --git a/Editor/AnimatorParserV2/AnimatorParserDebugWindow.cs b/Editor/AnimatorParserV2/AnimatorParserDebugWindow.cs index c071a59f5..43c6ad2ea 100644 --- a/Editor/AnimatorParserV2/AnimatorParserDebugWindow.cs +++ b/Editor/AnimatorParserV2/AnimatorParserDebugWindow.cs @@ -144,7 +144,7 @@ private string CreateText(bool detailed = false) return resultText.ToString(); } - private void AppendNodeRecursive(PropModNode propState, StringBuilder resultText, string indent) + private void AppendNodeRecursive(PropModNode> propState, StringBuilder resultText, string indent) where T : notnull { switch (propState) @@ -172,7 +172,7 @@ private void AppendNodeRecursive(PropModNode propState, StringBuilder resu case HumanoidAnimatorPropModNode humanoid: resultText.Append($"{indent}Humanoid: {humanoid.Component.name}\n"); break; - case VariableComponentPropModNode variable: + case VariableComponentPropModNode variable: resultText.Append($"{indent}Variable({variable.Component.GetType().Name}): {variable.Component.name}\n"); break; case AnimatorLayerPropModNode animatorLayer: @@ -180,7 +180,7 @@ private void AppendNodeRecursive(PropModNode propState, StringBuilder resu foreach (var childNode in animatorLayer.Children) AppendNodeRecursive(childNode, resultText, indent + " "); break; - case AnimatorStatePropModNode stateNode: + case AnimatorStatePropModNode> stateNode: resultText.Append($"{indent}AnimatorState: {stateNode.State.name}\n"); AppendNodeRecursive(stateNode.Node, resultText, indent + " "); break; diff --git a/Editor/AnimatorParserV2/NodeContainer.cs b/Editor/AnimatorParserV2/NodeContainer.cs index 9c284f360..108144ddb 100644 --- a/Editor/AnimatorParserV2/NodeContainer.cs +++ b/Editor/AnimatorParserV2/NodeContainer.cs @@ -7,8 +7,8 @@ namespace Anatawa12.AvatarOptimizer.AnimatorParsersV2 { internal interface INodeContainer { - IReadOnlyDictionary<(ComponentOrGameObject target, string prop), PropModNode> FloatNodes { get; } - IReadOnlyDictionary<(ComponentOrGameObject target, string prop), PropModNode> ObjectNodes { get; } + IReadOnlyDictionary<(ComponentOrGameObject target, string prop), PropModNode>> FloatNodes { get; } + IReadOnlyDictionary<(ComponentOrGameObject target, string prop), PropModNode>> ObjectNodes { get; } } internal interface INodeContainer @@ -24,13 +24,13 @@ internal class RootPropModNodeContainer : INodeContainer, private readonly Dictionary<(ComponentOrGameObject target, string prop), RootPropModNode> _objectNodes = new Dictionary<(ComponentOrGameObject, string), RootPropModNode>(); - IReadOnlyDictionary<(ComponentOrGameObject target, string prop), PropModNode> INodeContainer. + IReadOnlyDictionary<(ComponentOrGameObject target, string prop), PropModNode>> INodeContainer. FloatNodes => - Utils.CastDic>().CastedDic(FloatNodes); + Utils.CastDic>>().CastedDic(FloatNodes); - IReadOnlyDictionary<(ComponentOrGameObject target, string prop), PropModNode> INodeContainer. + IReadOnlyDictionary<(ComponentOrGameObject target, string prop), PropModNode>> INodeContainer. ObjectNodes => - Utils.CastDic>().CastedDic(ObjectNodes); + Utils.CastDic>>().CastedDic(ObjectNodes); public IReadOnlyDictionary<(ComponentOrGameObject target, string prop), RootPropModNode> FloatNodes => _floatNodes; @@ -57,7 +57,7 @@ public void Add(ComponentNodeContainer? container, bool alwaysApplied) } } - public void Add(Component component, string prop, ComponentPropModNodeBase node, bool alwaysApplied) + public void Add(Component component, string prop, ComponentPropModNodeBase> node, bool alwaysApplied) { var key = (component, prop); if (!FloatNodes.TryGetValue(key, out var root)) @@ -65,7 +65,7 @@ public void Add(Component component, string prop, ComponentPropModNodeBase node, bool alwaysApplied) + public void Add(Component component, string prop, ComponentPropModNodeBase> node, bool alwaysApplied) { var key = (component, prop); if (!_objectNodes.TryGetValue(key, out var root)) @@ -80,8 +80,8 @@ public void Add(Component component, string prop, ComponentPropModNodeBase : INodeContainer, INodeContainer - where TFloatNode : PropModNode - where TObjectNode : PropModNode + where TFloatNode : PropModNode> + where TObjectNode : PropModNode> { private readonly Dictionary<(ComponentOrGameObject target, string prop), TFloatNode> _floatNodes = new Dictionary<(ComponentOrGameObject, string), TFloatNode>(); @@ -92,11 +92,11 @@ internal class NodeContainerBase : INodeContainer ObjectNodes => _objectNodes; - IReadOnlyDictionary<(ComponentOrGameObject target, string prop), PropModNode> INodeContainer. - FloatNodes => Utils.CastDic>().CastedDic(_floatNodes); + IReadOnlyDictionary<(ComponentOrGameObject target, string prop), PropModNode>> INodeContainer. + FloatNodes => Utils.CastDic>>().CastedDic(_floatNodes); - IReadOnlyDictionary<(ComponentOrGameObject target, string prop), PropModNode> INodeContainer. - ObjectNodes => Utils.CastDic>().CastedDic(_objectNodes); + IReadOnlyDictionary<(ComponentOrGameObject target, string prop), PropModNode>> INodeContainer. + ObjectNodes => Utils.CastDic>>().CastedDic(_objectNodes); public void Add(ComponentOrGameObject target, string prop, TFloatNode node) { @@ -133,11 +133,11 @@ internal class AnimatorControllerNodeContainer : NodeContainerBase, ComponentPropModNodeBase> + : NodeContainerBase>, ComponentPropModNodeBase>> { } - internal class ImmutableNodeContainer : NodeContainerBase, ImmutablePropModNode> + internal class ImmutableNodeContainer : NodeContainerBase>, ImmutablePropModNode>> { } } diff --git a/Editor/AnimatorParserV2/PropModNode.cs b/Editor/AnimatorParserV2/PropModNode.cs index 2ea0b3d1e..835598c48 100644 --- a/Editor/AnimatorParserV2/PropModNode.cs +++ b/Editor/AnimatorParserV2/PropModNode.cs @@ -16,6 +16,11 @@ interface IPropModNode bool AppliedAlways { get; } } + interface IValueInfo + where TValueInfo : struct, IValueInfo + { + } + /// /// This class represents a node in the property modification tree. /// @@ -26,15 +31,15 @@ interface IPropModNode /// /// Most nodes are immutable but some nodes are mutable. /// - internal abstract class PropModNode : IErrorContext, IPropModNode - where T : notnull + internal abstract class PropModNode : IErrorContext, IPropModNode + where TValueInfo: struct, IValueInfo { /// /// Returns true if this node is always applied. For inactive nodes, this returns false. /// public abstract bool AppliedAlways { get; } - public abstract ValueInfo Value { get; } + public abstract TValueInfo Value { get; } public abstract IEnumerable ContextReferences { get; } } @@ -42,7 +47,7 @@ internal abstract class PropModNode : IErrorContext, IPropModNode /// The abstract information about actual value of PropModNode. /// // by design, this struct doesn't handle blending between two states. - internal readonly struct ValueInfo + internal readonly struct ValueInfo : IValueInfo> where T : notnull { public bool IsConstant => _possibleValues != null && _possibleValues.Length == 1; @@ -119,7 +124,7 @@ public static bool SetEquals(T[]? a, T[]? b) return new HashSet(a).SetEquals(b); } - public static ValueInfo ConstantInfoForSideBySide(IEnumerable> nodes) where T : notnull + public static ValueInfo ConstantInfoForSideBySide(IEnumerable>> nodes) where T : notnull { using (var enumerator = nodes.GetEnumerator()) { @@ -144,7 +149,7 @@ public static ValueInfo ConstantInfoForSideBySide(IEnumerable(IEnumerable layersReversed) where T : notnull - where TLayer : ILayer + where TLayer : ILayer> { return layersReversed.Any(x => x.Weight == AnimatorWeightState.AlwaysOne && x.BlendingMode == AnimatorLayerBlendingMode.Override && @@ -153,7 +158,7 @@ public static bool AlwaysAppliedForOverriding(IEnumerable lay public static ValueInfo ConstantInfoForOverriding(IEnumerable layersReversed) where T : notnull - where TLayer : ILayer + where TLayer : ILayer> { var canAdditive = default(T) != null; var allPossibleValues = new HashSet(); @@ -232,27 +237,27 @@ interface ILayer IPropModNode Node { get; } } - internal interface ILayer : ILayer - where T : notnull + internal interface ILayer : ILayer + where TValueInfo : struct, IValueInfo { new AnimatorWeightState Weight { get; } new AnimatorLayerBlendingMode BlendingMode { get; } - new PropModNode Node { get; } + new PropModNode Node { get; } } - internal sealed class RootPropModNode : PropModNode, IErrorContext + internal sealed class RootPropModNode : PropModNode>, IErrorContext where T : notnull { internal readonly struct ComponentInfo { - public readonly ComponentPropModNodeBase Node; + public readonly ComponentPropModNodeBase> Node; public readonly bool AlwaysApplied; public bool AppliedAlways => AlwaysApplied && Node.AppliedAlways; public IEnumerable ContextReferences => Node.ContextReferences; public Component Component => Node.Component; - public ComponentInfo(ComponentPropModNodeBase node, bool alwaysApplied) + public ComponentInfo(ComponentPropModNodeBase> node, bool alwaysApplied) { Node = node; AlwaysApplied = alwaysApplied; @@ -273,9 +278,9 @@ public ComponentInfo(ComponentPropModNodeBase node, bool alwaysApplied) public bool IsEmpty => _children.Count == 0; public IEnumerable SourceComponents => _children.Select(x => x.Component); - public IEnumerable> ComponentNodes => _children.Select(x => x.Node); + public IEnumerable>> ComponentNodes => _children.Select(x => x.Node); - public void Add(ComponentPropModNodeBase node, bool alwaysApplied) + public void Add(ComponentPropModNodeBase> node, bool alwaysApplied) { _children.Add(new ComponentInfo(node, alwaysApplied)); DestroyTracker.Track(node.Component, OnDestroy); @@ -303,12 +308,12 @@ public void Invalidate() public RootPropModNode? Normalize() => IsEmpty ? null : this; } - internal abstract class ImmutablePropModNode : PropModNode - where T : notnull + internal abstract class ImmutablePropModNode : PropModNode + where TValueInfo: struct, IValueInfo { } - internal class FloatAnimationCurveNode : ImmutablePropModNode + internal class FloatAnimationCurveNode : ImmutablePropModNode> { public AnimationCurve Curve { get; } public AnimationClip Clip { get; } @@ -377,7 +382,7 @@ private static ValueInfo ParseCurve(AnimationCurve curve) } } - internal class ObjectAnimationCurveNode : ImmutablePropModNode + internal class ObjectAnimationCurveNode : ImmutablePropModNode> { public ObjectReferenceKeyframe[] Frames { get; set; } public AnimationClip Clip { get; } @@ -413,16 +418,16 @@ internal struct BlendTreeElement where T : notnull { public int Index; - public ImmutablePropModNode Node; + public ImmutablePropModNode> Node; - public BlendTreeElement(int index, ImmutablePropModNode node) + public BlendTreeElement(int index, ImmutablePropModNode> node) { Index = index; Node = node ?? throw new ArgumentNullException(nameof(node)); } } - internal class BlendTreeNode : ImmutablePropModNode + internal class BlendTreeNode : ImmutablePropModNode> where T : notnull { private readonly List> _children; @@ -462,8 +467,8 @@ public override ValueInfo Value _children.SelectMany(x => x.Node.ContextReferences); } - abstract class ComponentPropModNodeBase : PropModNode - where T : notnull + abstract class ComponentPropModNodeBase : PropModNode + where TValueInfo : struct, IValueInfo { protected ComponentPropModNodeBase(Component component) { @@ -477,8 +482,8 @@ protected ComponentPropModNodeBase(Component component) new[] { ObjectRegistry.GetReference(Component) }; } - abstract class ComponentPropModNode : ComponentPropModNodeBase - where T : notnull + abstract class ComponentPropModNode : ComponentPropModNodeBase + where TValueInfo : struct, IValueInfo where TComponent : Component { protected ComponentPropModNode(TComponent component) : base(component) @@ -493,23 +498,22 @@ protected ComponentPropModNode(TComponent component) : base(component) new[] { ObjectRegistry.GetReference(Component) }; } - class VariableComponentPropModNode : ComponentPropModNode - where T : notnull + class VariableComponentPropModNode : ComponentPropModNode, Component> { public VariableComponentPropModNode(Component component) : base(component) { } public override bool AppliedAlways => false; - public override ValueInfo Value => ValueInfo.Variable; + public override ValueInfo Value => ValueInfo.Variable; } - class AnimationComponentPropModNode : ComponentPropModNode + class AnimationComponentPropModNode : ComponentPropModNode, Animation> where T : notnull { - public ImmutablePropModNode Animation { get; } + public ImmutablePropModNode> Animation { get; } - public AnimationComponentPropModNode(Animation component, ImmutablePropModNode animation) : base(component) + public AnimationComponentPropModNode(Animation component, ImmutablePropModNode> animation) : base(component) { Animation = animation; _constantInfo = new Lazy>(() => animation.Value, isThreadSafe: false); diff --git a/Editor/AnimatorParserV2/Utilities.cs b/Editor/AnimatorParserV2/Utilities.cs index 19c3f1f55..da8e14748 100644 --- a/Editor/AnimatorParserV2/Utilities.cs +++ b/Editor/AnimatorParserV2/Utilities.cs @@ -31,8 +31,8 @@ public static TResultContainer Merge< where TSourceObjectNode : notnull where TResultContainer : NodeContainerBase - where TResultFloatNode : PropModNode - where TResultObjectNode : PropModNode + where TResultFloatNode : PropModNode> + where TResultObjectNode : PropModNode> where TSourceContainer : INodeContainer @@ -96,8 +96,8 @@ interface IMergeProperty1 < TSourceObjectNode > where TResultContainer : NodeContainerBase - where TResultFloatNode : PropModNode - where TResultObjectNode : PropModNode + where TResultFloatNode : PropModNode> + where TResultObjectNode : PropModNode> where TSourceContainer : INodeContainer where TSource : notnull @@ -165,7 +165,7 @@ public static ComponentNodeContainer ComponentFromPlayableLayers(Animator animat IEnumerable<(AnimatorWeightState, AnimatorLayerBlendingMode, AnimatorControllerNodeContainer?)> playableLayers) => Merge< - ComponentNodeContainer, ComponentPropModNodeBase, ComponentPropModNodeBase, + ComponentNodeContainer, ComponentPropModNodeBase>, ComponentPropModNodeBase>, PlayableLayerNodeInfo, PlayableLayerNodeInfo, (AnimatorWeightState, AnimatorLayerBlendingMode, AnimatorControllerNodeContainer?), AnimatorControllerNodeContainer, AnimatorControllerPropModNode, @@ -174,7 +174,7 @@ public static ComponentNodeContainer ComponentFromPlayableLayers(Animator animat >(playableLayers, new PlayableLayerMerger(animator)); readonly struct PlayableLayerMerger : IMergeProperty1< - ComponentNodeContainer, ComponentPropModNodeBase, ComponentPropModNodeBase, + ComponentNodeContainer, ComponentPropModNodeBase>, ComponentPropModNodeBase>, PlayableLayerNodeInfo, PlayableLayerNodeInfo, (AnimatorWeightState, AnimatorLayerBlendingMode, AnimatorControllerNodeContainer?), AnimatorControllerNodeContainer, AnimatorControllerPropModNode, AnimatorControllerPropModNode @@ -200,10 +200,10 @@ public PlayableLayerNodeInfo GetIntermediate( AnimatorControllerPropModNode node, int index) => new PlayableLayerNodeInfo(source.Item1, source.Item2, node, index); - public ComponentPropModNodeBase MergeNode(List> nodes, int sourceCount) => + public ComponentPropModNodeBase> MergeNode(List> nodes, int sourceCount) => new AnimatorPropModNode(_animator, nodes); - public ComponentPropModNodeBase MergeNode(List> nodes, int sourceCount) => + public ComponentPropModNodeBase> MergeNode(List> nodes, int sourceCount) => new AnimatorPropModNode(_animator, nodes); } diff --git a/Editor/ContextExtensions.cs b/Editor/ContextExtensions.cs index 9d81d5a9e..cd13e3f08 100644 --- a/Editor/ContextExtensions.cs +++ b/Editor/ContextExtensions.cs @@ -44,7 +44,7 @@ public static AnimationComponentInfo GetAnimationComponent(this Bu ? currentValue : node.AsConstantValue(currentValue); - public static bool? AsConstantValue(this PropModNode? node, bool currentValue) + public static bool? AsConstantValue(this PropModNode>? node, bool currentValue) { if (node == null) return currentValue; if (node.Value.PossibleValues is { } values) diff --git a/Editor/ObjectMapping/PropertyInfo.cs b/Editor/ObjectMapping/PropertyInfo.cs index 3eee88da1..e5a395290 100644 --- a/Editor/ObjectMapping/PropertyInfo.cs +++ b/Editor/ObjectMapping/PropertyInfo.cs @@ -67,13 +67,13 @@ public void ImportProperty(RootPropModNode node) _objectNode = node; } - public void AddModification(ComponentPropModNodeBase node, bool alwaysApplied) + public void AddModification(ComponentPropModNodeBase> node, bool alwaysApplied) { if (_floatNode == null) _floatNode = new RootPropModNode(); _floatNode.Add(node, alwaysApplied); } - public void AddModification(ComponentPropModNodeBase node, bool alwaysApplied) + public void AddModification(ComponentPropModNodeBase> node, bool alwaysApplied) { if (_objectNode == null) _objectNode = new RootPropModNode(); _objectNode.Add(node, alwaysApplied); @@ -108,7 +108,7 @@ public static bool TryGetFloat(this AnimationComponentInfo info, s } public static void AddModification(this AnimationComponentInfo info, string property, - ComponentPropModNodeBase node, bool alwaysApplied) + ComponentPropModNodeBase> node, bool alwaysApplied) { if (info == null) throw new ArgumentNullException(nameof(info)); info.GetPropertyInfo(property).AddModification(node, alwaysApplied); @@ -129,7 +129,7 @@ public static bool TryGetObject(this AnimationComponentInfo info, } public static void AddModification(this AnimationComponentInfo info, string property, - ComponentPropModNodeBase node, bool alwaysApplied) + ComponentPropModNodeBase> node, bool alwaysApplied) { if (info == null) throw new ArgumentNullException(nameof(info)); info.GetPropertyInfo(property).AddModification(node, alwaysApplied); diff --git a/Editor/Processors/MergePhysBoneProcessor.cs b/Editor/Processors/MergePhysBoneProcessor.cs index 83c20019b..5d0b08e2b 100644 --- a/Editor/Processors/MergePhysBoneProcessor.cs +++ b/Editor/Processors/MergePhysBoneProcessor.cs @@ -138,7 +138,7 @@ internal static void DoMerge(MergePhysBone merge, BuildContext? context) var component = context.GetAnimationComponent(transform); foreach (var property in TransformRotationAndPositionAnimationKeys) { - component.AddModification(property, new VariableComponentPropModNode(merged), true); + component.AddModification(property, new VariableComponentPropModNode(merged), true); } } } diff --git a/Editor/Utils/AnimationLocation.cs b/Editor/Utils/AnimationLocation.cs index ce5016f14..a6e57499d 100644 --- a/Editor/Utils/AnimationLocation.cs +++ b/Editor/Utils/AnimationLocation.cs @@ -50,7 +50,7 @@ public static IEnumerable CollectAnimationLocation(RootPropMo public static IEnumerable CollectAnimationLocation(Animator animator, int playableLayer, int animatorLayer, - AnimatorState state, ImmutablePropModNode node) + AnimatorState state, ImmutablePropModNode> node) { // fast path if (node is FloatAnimationCurveNode floatNode) @@ -63,7 +63,7 @@ public static IEnumerable CollectAnimationLocation(Animator a } private static IEnumerable CollectAnimationLocationSlow(Animator animator, - int playableLayer, int animatorLayer, AnimatorState state, ImmutablePropModNode node) + int playableLayer, int animatorLayer, AnimatorState state, ImmutablePropModNode> node) { // slow path: recursively collect blend tree var queue = new Queue<(BlendTreeNode, int[])>(); diff --git a/Test~/AnimatorParser/TestUtil.cs b/Test~/AnimatorParser/TestUtil.cs index 55405fb36..65a047bd0 100644 --- a/Test~/AnimatorParser/TestUtil.cs +++ b/Test~/AnimatorParser/TestUtil.cs @@ -25,7 +25,7 @@ public Expected(bool always, ValueInfo value) public static Expected MultipleAlways(params float[] values) => new Expected(true, new ValueInfo(values)); - public static void AssertPropertyNode(PropModNode propertyNode, Expected property) + public static void AssertPropertyNode(PropModNode> propertyNode, Expected property) { Assert.That(propertyNode.AppliedAlways, Is.EqualTo(property.Always)); Assert.That(propertyNode.Value, Is.EqualTo(property.Value)); From 7221ba6b0c0e62c8ecc985c9faf269db33c77e2c Mon Sep 17 00:00:00 2001 From: anatawa12 Date: Fri, 4 Oct 2024 16:53:09 +0900 Subject: [PATCH 02/11] chore: separate ValueInfo for float and Object phase 2: add utility function onto interface --- .../AnimatorControllerPropModNode.cs | 12 +++---- Editor/AnimatorParserV2/PropModNode.cs | 34 +++++++++++++++++-- 2 files changed, 36 insertions(+), 10 deletions(-) diff --git a/Editor/AnimatorParserV2/AnimatorControllerPropModNode.cs b/Editor/AnimatorParserV2/AnimatorControllerPropModNode.cs index 9f4b79e90..19ccf03de 100644 --- a/Editor/AnimatorParserV2/AnimatorControllerPropModNode.cs +++ b/Editor/AnimatorParserV2/AnimatorControllerPropModNode.cs @@ -56,11 +56,11 @@ public AnimatorPropModNode(Animator component,IEnumerable( - () => NodeImplUtils.AlwaysAppliedForOverriding>(_layersReversed), + () => default(ValueInfo).AlwaysAppliedForOverriding(_layersReversed), isThreadSafe: false); _constantInfo = new Lazy>( - () => NodeImplUtils.ConstantInfoForOverriding>(_layersReversed), + () => default(ValueInfo).ConstantInfoForOverriding(_layersReversed), isThreadSafe: false); } @@ -115,12 +115,10 @@ private AnimatorControllerPropModNode(IEnumerable> laye public IEnumerable> LayersReversed => _layersReversed; - public override ValueInfo Value => - NodeImplUtils.ConstantInfoForOverriding>(_layersReversed); + public override ValueInfo Value => default(ValueInfo).ConstantInfoForOverriding(_layersReversed); // we may possible to implement complex logic which simulates state machine but not for now. - public override bool AppliedAlways => - NodeImplUtils.AlwaysAppliedForOverriding>(_layersReversed); + public override bool AppliedAlways => default(ValueInfo).AlwaysAppliedForOverriding(_layersReversed); public override IEnumerable ContextReferences => _layersReversed.SelectMany(x => x.Node.ContextReferences); @@ -150,7 +148,7 @@ public AnimatorLayerPropModNode(ICollection !_partial && _children.All(x => x.AppliedAlways); - public override ValueInfo Value => NodeImplUtils.ConstantInfoForSideBySide(_children); + public override ValueInfo Value => default(ValueInfo).ConstantInfoForSideBySide(_children); public override IEnumerable ContextReferences => _children.SelectMany(x => x.ContextReferences); public IEnumerable>> Children => _children; } diff --git a/Editor/AnimatorParserV2/PropModNode.cs b/Editor/AnimatorParserV2/PropModNode.cs index 835598c48..52f13a73e 100644 --- a/Editor/AnimatorParserV2/PropModNode.cs +++ b/Editor/AnimatorParserV2/PropModNode.cs @@ -19,6 +19,19 @@ interface IPropModNode interface IValueInfo where TValueInfo : struct, IValueInfo { + public bool IsConstant { get; } + + // following functions are intended to be called on default(TValueInfo) and "this" will not be affected + // Those functions should be static abstract but Unity doesn't support static abstract functions. + + TValueInfo ConstantInfoForSideBySide(IEnumerable> nodes); + TValueInfo ConstantInfoForBlendTree(IEnumerable> nodes, BlendTreeType blendTreeType); + + TValueInfo ConstantInfoForOverriding(IEnumerable layersReversed) + where TLayer : ILayer; + + bool AlwaysAppliedForOverriding(IEnumerable layersReversed) + where TLayer : ILayer; } /// @@ -104,6 +117,21 @@ public bool Equals(ValueInfo other) return NodeImplUtils.SetEquals(_possibleValues, other._possibleValues); } + public ValueInfo ConstantInfoForSideBySide(IEnumerable>> nodes) => + NodeImplUtils.ConstantInfoForSideBySide(nodes); + + public ValueInfo ConstantInfoForBlendTree(IEnumerable>> nodes, BlendTreeType blendTreeType) + { + if (default(T) == null) return ConstantInfoForSideBySide(nodes); + return blendTreeType == BlendTreeType.Direct ? Variable : ConstantInfoForSideBySide(nodes); + } + + public ValueInfo ConstantInfoForOverriding(IEnumerable layersReversed) + where TLayer : ILayer> => NodeImplUtils.ConstantInfoForOverriding(layersReversed); + + public bool AlwaysAppliedForOverriding(IEnumerable layersReversed) + where TLayer : ILayer> => NodeImplUtils.AlwaysAppliedForOverriding(layersReversed); + public override bool Equals(object obj) => obj is ValueInfo other && Equals(other); public override int GetHashCode() => _possibleValues == null ? 0 : _possibleValues.GetSetHashCode(); @@ -273,7 +301,7 @@ public ComponentInfo(ComponentPropModNodeBase> node, bool alwaysApp public override IEnumerable ContextReferences => _children.SelectMany(x => x.ContextReferences); - public override ValueInfo Value => NodeImplUtils.ConstantInfoForSideBySide(_children.Select(x => x.Node)); + public override ValueInfo Value => default(ValueInfo).ConstantInfoForSideBySide(_children.Select(x => x.Node)); public bool IsEmpty => _children.Count == 0; @@ -456,10 +484,10 @@ public override ValueInfo Value get { if (default(T) == null) - return NodeImplUtils.ConstantInfoForSideBySide(_children.Select(x => x.Node)); + return default(ValueInfo).ConstantInfoForBlendTree(_children.Select(x => x.Node), _blendTreeType); return !WeightSumIsOne ? ValueInfo.Variable - : NodeImplUtils.ConstantInfoForSideBySide(_children.Select(x => x.Node)); + : default(ValueInfo).ConstantInfoForSideBySide(_children.Select(x => x.Node)); } } From 1c6a1d6b34f13e25dfc8913c6021ebc1c5106913 Mon Sep 17 00:00:00 2001 From: anatawa12 Date: Fri, 4 Oct 2024 17:08:37 +0900 Subject: [PATCH 03/11] chore: separate ValueInfo for float and Object phase 3: more generic --- Editor/AnimatorParserV2/AnimationParser.cs | 20 +++--- .../AnimatorControllerPropModNode.cs | 72 +++++++++---------- Editor/AnimatorParserV2/AnimatorParser.cs | 12 ++-- .../AnimatorParserDebugWindow.cs | 12 ++-- Editor/AnimatorParserV2/NodeContainer.cs | 30 ++++---- Editor/AnimatorParserV2/PropModNode.cs | 61 +++++++--------- Editor/AnimatorParserV2/Utilities.cs | 70 +++++++++--------- Editor/ObjectMapping/PropertyInfo.cs | 28 ++++---- .../MergeSkinnedMeshProcessor.cs | 4 +- .../TraceAndOptimize/AutoMergeSkinnedMesh.cs | 6 +- .../TraceAndOptimize/OptimizeTexture.cs | 2 +- Editor/Utils/AnimationLocation.cs | 10 +-- 12 files changed, 160 insertions(+), 167 deletions(-) diff --git a/Editor/AnimatorParserV2/AnimationParser.cs b/Editor/AnimatorParserV2/AnimationParser.cs index c9181ec2a..cf329f4ce 100644 --- a/Editor/AnimatorParserV2/AnimationParser.cs +++ b/Editor/AnimatorParserV2/AnimationParser.cs @@ -50,7 +50,7 @@ private ImmutableNodeContainer ParseBlendTree(GameObject root, BlendTree blendTr return NodesMerger.Merge< ImmutableNodeContainer, ImmutablePropModNode>, ImmutablePropModNode>, - BlendTreeElement, BlendTreeElement, + BlendTreeElement>, BlendTreeElement>, ImmutableNodeContainer, ImmutableNodeContainer, ImmutablePropModNode>, ImmutablePropModNode>, BlendTreeMergeProperty @@ -61,7 +61,7 @@ private ImmutableNodeContainer ParseBlendTree(GameObject root, BlendTree blendTr internal readonly struct BlendTreeMergeProperty : IMergeProperty1< ImmutableNodeContainer, ImmutablePropModNode>, ImmutablePropModNode>, - BlendTreeElement, BlendTreeElement, + BlendTreeElement>, BlendTreeElement>, ImmutableNodeContainer, ImmutableNodeContainer, ImmutablePropModNode>, ImmutablePropModNode> > @@ -76,17 +76,17 @@ public BlendTreeMergeProperty(BlendTreeType blendType) public ImmutableNodeContainer CreateContainer() => new(); public ImmutableNodeContainer GetContainer(ImmutableNodeContainer source) => source; - public BlendTreeElement GetIntermediate(ImmutableNodeContainer source, - ImmutablePropModNode> node, int index) => new BlendTreeElement(index, node); + public BlendTreeElement> GetIntermediate(ImmutableNodeContainer source, + ImmutablePropModNode> node, int index) => new BlendTreeElement>(index, node); - public BlendTreeElement GetIntermediate(ImmutableNodeContainer source, - ImmutablePropModNode> node, int index) => new BlendTreeElement(index, node); + public BlendTreeElement> GetIntermediate(ImmutableNodeContainer source, + ImmutablePropModNode> node, int index) => new BlendTreeElement>(index, node); - public ImmutablePropModNode> MergeNode(List> nodes, int sourceCount) => - new BlendTreeNode(nodes, _blendType, partial: nodes.Count != sourceCount); + public ImmutablePropModNode> MergeNode(List>> nodes, int sourceCount) => + new BlendTreeNode>(nodes, _blendType, partial: nodes.Count != sourceCount); - public ImmutablePropModNode> MergeNode(List> nodes, int sourceCount) => - new BlendTreeNode(nodes, _blendType, partial: nodes.Count != sourceCount); + public ImmutablePropModNode> MergeNode(List>> nodes, int sourceCount) => + new BlendTreeNode>(nodes, _blendType, partial: nodes.Count != sourceCount); } private readonly Dictionary<(GameObject, AnimationClip), ImmutableNodeContainer> _parsedAnimationCache = new(); diff --git a/Editor/AnimatorParserV2/AnimatorControllerPropModNode.cs b/Editor/AnimatorParserV2/AnimatorControllerPropModNode.cs index 19ccf03de..23052bb17 100644 --- a/Editor/AnimatorParserV2/AnimatorControllerPropModNode.cs +++ b/Editor/AnimatorParserV2/AnimatorControllerPropModNode.cs @@ -17,18 +17,18 @@ public HumanoidAnimatorPropModNode(Animator component) : base(component) public override bool AppliedAlways => true; } - internal readonly struct PlayableLayerNodeInfo : ILayer> - where T : notnull + internal readonly struct PlayableLayerNodeInfo : ILayer + where TValueInfo : struct, IValueInfo { public AnimatorWeightState Weight { get; } public AnimatorLayerBlendingMode BlendingMode { get; } public int LayerIndex { get; } - public readonly AnimatorControllerPropModNode Node; - PropModNode> ILayer>.Node => Node; + public readonly AnimatorControllerPropModNode Node; + PropModNode ILayer.Node => Node; IPropModNode ILayer.Node => Node; public PlayableLayerNodeInfo(AnimatorWeightState weight, AnimatorLayerBlendingMode blendingMode, - AnimatorControllerPropModNode node, int layerIndex) + AnimatorControllerPropModNode node, int layerIndex) { Weight = weight; BlendingMode = blendingMode; @@ -36,7 +36,7 @@ public PlayableLayerNodeInfo(AnimatorWeightState weight, AnimatorLayerBlendingMo Node = node; } - public PlayableLayerNodeInfo(AnimatorControllerPropModNode node, int layerIndex) + public PlayableLayerNodeInfo(AnimatorControllerPropModNode node, int layerIndex) { Weight = AnimatorWeightState.AlwaysOne; BlendingMode = AnimatorLayerBlendingMode.Override; @@ -45,48 +45,48 @@ public PlayableLayerNodeInfo(AnimatorControllerPropModNode node, int layerInd } } - class AnimatorPropModNode : ComponentPropModNode, Animator> - where T : notnull + class AnimatorPropModNode : ComponentPropModNode + where TValueInfo : struct, IValueInfo { - private readonly IEnumerable> _layersReversed; + private readonly IEnumerable> _layersReversed; - public AnimatorPropModNode(Animator component,IEnumerable> layersReversed) + public AnimatorPropModNode(Animator component,IEnumerable> layersReversed) : base(component) { _layersReversed = layersReversed; _appliedAlways = new Lazy( - () => default(ValueInfo).AlwaysAppliedForOverriding(_layersReversed), + () => default(TValueInfo).AlwaysAppliedForOverriding(_layersReversed), isThreadSafe: false); - _constantInfo = new Lazy>( - () => default(ValueInfo).ConstantInfoForOverriding(_layersReversed), + _constantInfo = new Lazy( + () => default(TValueInfo).ConstantInfoForOverriding(_layersReversed), isThreadSafe: false); } private readonly Lazy _appliedAlways; - private readonly Lazy> _constantInfo; + private readonly Lazy _constantInfo; - public IEnumerable> LayersReversed => _layersReversed; + public IEnumerable> LayersReversed => _layersReversed; public override bool AppliedAlways => _appliedAlways.Value; - public override ValueInfo Value => _constantInfo.Value; + public override TValueInfo Value => _constantInfo.Value; public override IEnumerable ContextReferences => base.ContextReferences.Concat( _layersReversed.SelectMany(x => x.Node.ContextReferences)); } - internal readonly struct AnimatorLayerNodeInfo : ILayer> - where T : notnull + internal readonly struct AnimatorLayerNodeInfo : ILayer + where TValueInfo : struct, IValueInfo { public AnimatorWeightState Weight { get; } public AnimatorLayerBlendingMode BlendingMode { get; } public int LayerIndex { get; } - public readonly AnimatorLayerPropModNode Node; - PropModNode> ILayer>.Node => Node; + public readonly AnimatorLayerPropModNode Node; + PropModNode ILayer.Node => Node; IPropModNode ILayer.Node => Node; public AnimatorLayerNodeInfo(AnimatorWeightState weight, AnimatorLayerBlendingMode blendingMode, - AnimatorLayerPropModNode node, int layerIndex) + AnimatorLayerPropModNode node, int layerIndex) { Weight = weight; BlendingMode = blendingMode; @@ -95,30 +95,30 @@ public AnimatorLayerNodeInfo(AnimatorWeightState weight, AnimatorLayerBlendingMo } } - class AnimatorControllerPropModNode : PropModNode> - where T : notnull + class AnimatorControllerPropModNode : PropModNode + where TValueInfo : struct, IValueInfo { - private readonly IEnumerable> _layersReversed; + private readonly IEnumerable> _layersReversed; - public static AnimatorControllerPropModNode? Create(List> value) + public static AnimatorControllerPropModNode? Create(List> value) { if (value.Count == 0) return null; if (value.All(x => x.BlendingMode == AnimatorLayerBlendingMode.Additive && x.Node.Value.IsConstant)) return null; // unchanged constant value.Reverse(); - return new AnimatorControllerPropModNode(value); + return new AnimatorControllerPropModNode(value); } - private AnimatorControllerPropModNode(IEnumerable> layersReversed) => + private AnimatorControllerPropModNode(IEnumerable> layersReversed) => _layersReversed = layersReversed; - public IEnumerable> LayersReversed => _layersReversed; + public IEnumerable> LayersReversed => _layersReversed; - public override ValueInfo Value => default(ValueInfo).ConstantInfoForOverriding(_layersReversed); + public override TValueInfo Value => default(TValueInfo).ConstantInfoForOverriding(_layersReversed); // we may possible to implement complex logic which simulates state machine but not for now. - public override bool AppliedAlways => default(ValueInfo).AlwaysAppliedForOverriding(_layersReversed); + public override bool AppliedAlways => default(TValueInfo).AlwaysAppliedForOverriding(_layersReversed); public override IEnumerable ContextReferences => _layersReversed.SelectMany(x => x.Node.ContextReferences); @@ -131,13 +131,13 @@ internal enum AnimatorWeightState Variable } - internal class AnimatorLayerPropModNode : ImmutablePropModNode> - where T : notnull + internal class AnimatorLayerPropModNode : ImmutablePropModNode + where TValueInfo : struct, IValueInfo { - private readonly IEnumerable>> _children; + private readonly IEnumerable> _children; private readonly bool _partial; - public AnimatorLayerPropModNode(ICollection>> children, bool partial) + public AnimatorLayerPropModNode(ICollection> children, bool partial) { // expected to pass list or array // ReSharper disable once PossibleMultipleEnumeration @@ -148,9 +148,9 @@ public AnimatorLayerPropModNode(ICollection !_partial && _children.All(x => x.AppliedAlways); - public override ValueInfo Value => default(ValueInfo).ConstantInfoForSideBySide(_children); + public override TValueInfo Value => default(TValueInfo).ConstantInfoForSideBySide(_children); public override IEnumerable ContextReferences => _children.SelectMany(x => x.ContextReferences); - public IEnumerable>> Children => _children; + public IEnumerable> Children => _children; } internal class AnimatorStatePropModNode : ImmutablePropModNode diff --git a/Editor/AnimatorParserV2/AnimatorParser.cs b/Editor/AnimatorParserV2/AnimatorParser.cs index bf64b3ea4..a27795fed 100644 --- a/Editor/AnimatorParserV2/AnimatorParser.cs +++ b/Editor/AnimatorParserV2/AnimatorParser.cs @@ -448,7 +448,7 @@ public AnimatorLayerNodeContainer ParseAnimatorControllerLayer( } return NodesMerger.Merge< - AnimatorLayerNodeContainer, AnimatorLayerPropModNode, AnimatorLayerPropModNode, + AnimatorLayerNodeContainer, AnimatorLayerPropModNode>, AnimatorLayerPropModNode>, AnimatorStatePropModNode>, AnimatorStatePropModNode>, (AnimatorState, ImmutableNodeContainer), ImmutableNodeContainer, ImmutablePropModNode>, ImmutablePropModNode>, @@ -457,7 +457,7 @@ public AnimatorLayerNodeContainer ParseAnimatorControllerLayer( } struct LayerMerger : IMergeProperty1< - AnimatorLayerNodeContainer, AnimatorLayerPropModNode, AnimatorLayerPropModNode, + AnimatorLayerNodeContainer, AnimatorLayerPropModNode>, AnimatorLayerPropModNode>, AnimatorStatePropModNode>, AnimatorStatePropModNode>, (AnimatorState, ImmutableNodeContainer), ImmutableNodeContainer, ImmutablePropModNode>, ImmutablePropModNode> @@ -474,13 +474,13 @@ public AnimatorStatePropModNode> GetIntermediate((AnimatorStat ImmutablePropModNode> node, int index) => new AnimatorStatePropModNode>(node, source.Item1); - public AnimatorLayerPropModNode + public AnimatorLayerPropModNode> MergeNode(List>> nodes, int sourceCount) => - new AnimatorLayerPropModNode(nodes, nodes.Count != sourceCount); + new AnimatorLayerPropModNode>(nodes, nodes.Count != sourceCount); - public AnimatorLayerPropModNode + public AnimatorLayerPropModNode> MergeNode(List>> nodes, int sourceCount) => - new AnimatorLayerPropModNode(nodes, nodes.Count != sourceCount); + new AnimatorLayerPropModNode>(nodes, nodes.Count != sourceCount); } AnimatorWeightState? GetWeightState(float weight, AnimatorWeightChange external) diff --git a/Editor/AnimatorParserV2/AnimatorParserDebugWindow.cs b/Editor/AnimatorParserV2/AnimatorParserDebugWindow.cs index 43c6ad2ea..f5661d013 100644 --- a/Editor/AnimatorParserV2/AnimatorParserDebugWindow.cs +++ b/Editor/AnimatorParserV2/AnimatorParserDebugWindow.cs @@ -149,7 +149,7 @@ private void AppendNodeRecursive(PropModNode> propState, StringB { switch (propState) { - case AnimatorControllerPropModNode animCont: + case AnimatorControllerPropModNode> animCont: resultText.Append($"{indent}AnimatorController: \n"); foreach (var layerInfo in animCont.LayersReversed) { @@ -157,11 +157,11 @@ private void AppendNodeRecursive(PropModNode> propState, StringB AppendNodeRecursive(layerInfo.Node, resultText, indent + " "); } break; - case AnimationComponentPropModNode animation: + case AnimationComponentPropModNode> animation: resultText.Append($"{indent}Animation: {animation.Component.name}\n"); AppendNodeRecursive(animation.Animation, resultText, indent + " "); break; - case AnimatorPropModNode animator: + case AnimatorPropModNode> animator: resultText.Append($"{indent}Animator: {animator.Component.name}\n"); foreach (var layerInfo in animator.LayersReversed) { @@ -175,7 +175,7 @@ private void AppendNodeRecursive(PropModNode> propState, StringB case VariableComponentPropModNode variable: resultText.Append($"{indent}Variable({variable.Component.GetType().Name}): {variable.Component.name}\n"); break; - case AnimatorLayerPropModNode animatorLayer: + case AnimatorLayerPropModNode> animatorLayer: resultText.Append($"{indent}AnimatorLayer:\n"); foreach (var childNode in animatorLayer.Children) AppendNodeRecursive(childNode, resultText, indent + " "); @@ -184,7 +184,7 @@ private void AppendNodeRecursive(PropModNode> propState, StringB resultText.Append($"{indent}AnimatorState: {stateNode.State.name}\n"); AppendNodeRecursive(stateNode.Node, resultText, indent + " "); break; - case BlendTreeNode blendTreeNode: + case BlendTreeNode> blendTreeNode: resultText.Append($"{indent}BlendTree:\n"); foreach (var childNode in blendTreeNode.Children) { @@ -198,7 +198,7 @@ private void AppendNodeRecursive(PropModNode> propState, StringB case ObjectAnimationCurveNode curve: resultText.Append($"{indent}ObjectAnimationCurve: {curve.Clip.name}\n"); break; - case RootPropModNode rootNode: + case RootPropModNode> rootNode: resultText.Append($"{indent}Root:\n"); foreach (var rootNodeChild in rootNode.Children) { diff --git a/Editor/AnimatorParserV2/NodeContainer.cs b/Editor/AnimatorParserV2/NodeContainer.cs index 108144ddb..88894e45b 100644 --- a/Editor/AnimatorParserV2/NodeContainer.cs +++ b/Editor/AnimatorParserV2/NodeContainer.cs @@ -17,12 +17,12 @@ internal interface INodeContainer IReadOnlyDictionary<(ComponentOrGameObject target, string prop), TObjectNode> ObjectNodes { get; } } - internal class RootPropModNodeContainer : INodeContainer, RootPropModNode>, INodeContainer + internal class RootPropModNodeContainer : INodeContainer>, RootPropModNode>>, INodeContainer { - private readonly Dictionary<(ComponentOrGameObject target, string prop), RootPropModNode> _floatNodes = - new Dictionary<(ComponentOrGameObject, string), RootPropModNode>(); - private readonly Dictionary<(ComponentOrGameObject target, string prop), RootPropModNode> _objectNodes = - new Dictionary<(ComponentOrGameObject, string), RootPropModNode>(); + private readonly Dictionary<(ComponentOrGameObject target, string prop), RootPropModNode>> _floatNodes = + new Dictionary<(ComponentOrGameObject, string), RootPropModNode>>(); + private readonly Dictionary<(ComponentOrGameObject target, string prop), RootPropModNode>> _objectNodes = + new Dictionary<(ComponentOrGameObject, string), RootPropModNode>>(); IReadOnlyDictionary<(ComponentOrGameObject target, string prop), PropModNode>> INodeContainer. FloatNodes => @@ -32,10 +32,10 @@ internal class RootPropModNodeContainer : INodeContainer, ObjectNodes => Utils.CastDic>>().CastedDic(ObjectNodes); - public IReadOnlyDictionary<(ComponentOrGameObject target, string prop), RootPropModNode> FloatNodes => + public IReadOnlyDictionary<(ComponentOrGameObject target, string prop), RootPropModNode>> FloatNodes => _floatNodes; - public IReadOnlyDictionary<(ComponentOrGameObject target, string prop), RootPropModNode> ObjectNodes => + public IReadOnlyDictionary<(ComponentOrGameObject target, string prop), RootPropModNode>> ObjectNodes => _objectNodes; public void Add(ComponentNodeContainer? container, bool alwaysApplied) @@ -45,14 +45,14 @@ public void Add(ComponentNodeContainer? container, bool alwaysApplied) foreach (var (key, value) in container.FloatNodes) { if (!FloatNodes.TryGetValue(key, out var node)) - _floatNodes.Add(key, node = new RootPropModNode()); + _floatNodes.Add(key, node = new RootPropModNode>()); node.Add(value, alwaysApplied); } foreach (var (key, value) in container.ObjectNodes) { if (!ObjectNodes.TryGetValue(key, out var node)) - _objectNodes.Add(key, node = new RootPropModNode()); + _objectNodes.Add(key, node = new RootPropModNode>()); node.Add(value, alwaysApplied); } } @@ -61,7 +61,7 @@ public void Add(Component component, string prop, ComponentPropModNodeBase()); + _floatNodes.Add(key, root = new RootPropModNode>()); root.Add(node, alwaysApplied); } @@ -69,7 +69,7 @@ public void Add(Component component, string prop, ComponentPropModNodeBase()); + _objectNodes.Add(key, root = new RootPropModNode>()); root.Add(node, alwaysApplied); } @@ -122,13 +122,13 @@ public void Set(ComponentOrGameObject target, string prop, TObjectNode node) } } - internal class AnimatorLayerNodeContainer : NodeContainerBase, - AnimatorLayerPropModNode> + internal class AnimatorLayerNodeContainer : NodeContainerBase>, + AnimatorLayerPropModNode>> { } - internal class AnimatorControllerNodeContainer : NodeContainerBase, - AnimatorControllerPropModNode> + internal class AnimatorControllerNodeContainer : NodeContainerBase>, + AnimatorControllerPropModNode>> { } diff --git a/Editor/AnimatorParserV2/PropModNode.cs b/Editor/AnimatorParserV2/PropModNode.cs index 52f13a73e..5994f7a0c 100644 --- a/Editor/AnimatorParserV2/PropModNode.cs +++ b/Editor/AnimatorParserV2/PropModNode.cs @@ -273,19 +273,19 @@ internal interface ILayer : ILayer new PropModNode Node { get; } } - internal sealed class RootPropModNode : PropModNode>, IErrorContext - where T : notnull + internal sealed class RootPropModNode : PropModNode, IErrorContext + where TValueInfo : struct, IValueInfo { internal readonly struct ComponentInfo { - public readonly ComponentPropModNodeBase> Node; + public readonly ComponentPropModNodeBase Node; public readonly bool AlwaysApplied; public bool AppliedAlways => AlwaysApplied && Node.AppliedAlways; public IEnumerable ContextReferences => Node.ContextReferences; public Component Component => Node.Component; - public ComponentInfo(ComponentPropModNodeBase> node, bool alwaysApplied) + public ComponentInfo(ComponentPropModNodeBase node, bool alwaysApplied) { Node = node; AlwaysApplied = alwaysApplied; @@ -301,20 +301,20 @@ public ComponentInfo(ComponentPropModNodeBase> node, bool alwaysApp public override IEnumerable ContextReferences => _children.SelectMany(x => x.ContextReferences); - public override ValueInfo Value => default(ValueInfo).ConstantInfoForSideBySide(_children.Select(x => x.Node)); + public override TValueInfo Value => default(TValueInfo).ConstantInfoForSideBySide(_children.Select(x => x.Node)); public bool IsEmpty => _children.Count == 0; public IEnumerable SourceComponents => _children.Select(x => x.Component); - public IEnumerable>> ComponentNodes => _children.Select(x => x.Node); + public IEnumerable> ComponentNodes => _children.Select(x => x.Node); - public void Add(ComponentPropModNodeBase> node, bool alwaysApplied) + public void Add(ComponentPropModNodeBase node, bool alwaysApplied) { _children.Add(new ComponentInfo(node, alwaysApplied)); DestroyTracker.Track(node.Component, OnDestroy); } - public void Add(RootPropModNode toAdd) + public void Add(RootPropModNode toAdd) { if (toAdd == null) throw new ArgumentNullException(nameof(toAdd)); foreach (var child in toAdd._children) @@ -333,7 +333,7 @@ public void Invalidate() _children.Clear(); } - public RootPropModNode? Normalize() => IsEmpty ? null : this; + public RootPropModNode? Normalize() => IsEmpty ? null : this; } internal abstract class ImmutablePropModNode : PropModNode @@ -442,27 +442,27 @@ private static ValueInfo ParseProperty(ObjectReferenceKeyframe[] frames) new ValueInfo(frames.Select(x => x.value).Distinct().ToArray()); } - internal struct BlendTreeElement - where T : notnull + internal struct BlendTreeElement + where TValueInfo : struct, IValueInfo { public int Index; - public ImmutablePropModNode> Node; + public ImmutablePropModNode Node; - public BlendTreeElement(int index, ImmutablePropModNode> node) + public BlendTreeElement(int index, ImmutablePropModNode node) { Index = index; Node = node ?? throw new ArgumentNullException(nameof(node)); } } - internal class BlendTreeNode : ImmutablePropModNode> - where T : notnull + internal class BlendTreeNode : ImmutablePropModNode + where TValueInfo : struct, IValueInfo { - private readonly List> _children; + private readonly List> _children; private readonly BlendTreeType _blendTreeType; private readonly bool _partial; - public BlendTreeNode(List> children, + public BlendTreeNode(List> children, BlendTreeType blendTreeType, bool partial) { // expected to pass list or array @@ -476,19 +476,12 @@ public BlendTreeNode(List> children, private bool WeightSumIsOne => _blendTreeType != BlendTreeType.Direct; - public IReadOnlyList> Children => _children; + public IReadOnlyList> Children => _children; public override bool AppliedAlways => WeightSumIsOne && !_partial && _children.All(x => x.Node.AppliedAlways); - public override ValueInfo Value + public override TValueInfo Value { - get - { - if (default(T) == null) - return default(ValueInfo).ConstantInfoForBlendTree(_children.Select(x => x.Node), _blendTreeType); - return !WeightSumIsOne - ? ValueInfo.Variable - : default(ValueInfo).ConstantInfoForSideBySide(_children.Select(x => x.Node)); - } + get => default(TValueInfo).ConstantInfoForBlendTree(_children.Select(x => x.Node), _blendTreeType); } public override IEnumerable ContextReferences => @@ -536,21 +529,21 @@ public VariableComponentPropModNode(Component component) : base(component) public override ValueInfo Value => ValueInfo.Variable; } - class AnimationComponentPropModNode : ComponentPropModNode, Animation> - where T : notnull + class AnimationComponentPropModNode : ComponentPropModNode + where TValueInfo : struct, IValueInfo { - public ImmutablePropModNode> Animation { get; } + public ImmutablePropModNode Animation { get; } - public AnimationComponentPropModNode(Animation component, ImmutablePropModNode> animation) : base(component) + public AnimationComponentPropModNode(Animation component, ImmutablePropModNode animation) : base(component) { Animation = animation; - _constantInfo = new Lazy>(() => animation.Value, isThreadSafe: false); + _constantInfo = new Lazy(() => animation.Value, isThreadSafe: false); } - private readonly Lazy> _constantInfo; + private readonly Lazy _constantInfo; public override bool AppliedAlways => true; - public override ValueInfo Value => _constantInfo.Value; + public override TValueInfo Value => _constantInfo.Value; public override IEnumerable ContextReferences => base.ContextReferences.Concat(Animation.ContextReferences); diff --git a/Editor/AnimatorParserV2/Utilities.cs b/Editor/AnimatorParserV2/Utilities.cs index da8e14748..51ae96f1d 100644 --- a/Editor/AnimatorParserV2/Utilities.cs +++ b/Editor/AnimatorParserV2/Utilities.cs @@ -130,13 +130,13 @@ static partial class NodesMerger foreach (var ((target, prop), value) in controller.FloatNodes) { animatorNodeContainer.Add(target, prop, - new AnimatorPropModNode(animator, new[] { new PlayableLayerNodeInfo(value, 0) })); + new AnimatorPropModNode>(animator, new[] { new PlayableLayerNodeInfo>(value, 0) })); } foreach (var ((target, prop), value) in controller.ObjectNodes) { animatorNodeContainer.Add(target, prop, - new AnimatorPropModNode(animator, new[] { new PlayableLayerNodeInfo(value, 0) })); + new AnimatorPropModNode>(animator, new[] { new PlayableLayerNodeInfo>(value, 0) })); } return animatorNodeContainer; @@ -150,12 +150,12 @@ public static ComponentNodeContainer AnimationComponentFromAnimationClip(Animati foreach (var ((target, prop), node) in animationClip.FloatNodes) { - animatorNodeContainer.Add(target, prop, new AnimationComponentPropModNode(animation, node)); + animatorNodeContainer.Add(target, prop, new AnimationComponentPropModNode>(animation, node)); } foreach (var ((target, prop), value) in animationClip.ObjectNodes) { - animatorNodeContainer.Add(target, prop, new AnimationComponentPropModNode(animation, value)); + animatorNodeContainer.Add(target, prop, new AnimationComponentPropModNode>(animation, value)); } return animatorNodeContainer; @@ -166,18 +166,18 @@ public static ComponentNodeContainer ComponentFromPlayableLayers(Animator animat playableLayers) => Merge< ComponentNodeContainer, ComponentPropModNodeBase>, ComponentPropModNodeBase>, - PlayableLayerNodeInfo, PlayableLayerNodeInfo, + PlayableLayerNodeInfo>, PlayableLayerNodeInfo>, (AnimatorWeightState, AnimatorLayerBlendingMode, AnimatorControllerNodeContainer?), - AnimatorControllerNodeContainer, AnimatorControllerPropModNode, - AnimatorControllerPropModNode, + AnimatorControllerNodeContainer, AnimatorControllerPropModNode>, + AnimatorControllerPropModNode>, PlayableLayerMerger >(playableLayers, new PlayableLayerMerger(animator)); readonly struct PlayableLayerMerger : IMergeProperty1< ComponentNodeContainer, ComponentPropModNodeBase>, ComponentPropModNodeBase>, - PlayableLayerNodeInfo, PlayableLayerNodeInfo, + PlayableLayerNodeInfo>, PlayableLayerNodeInfo>, (AnimatorWeightState, AnimatorLayerBlendingMode, AnimatorControllerNodeContainer?), - AnimatorControllerNodeContainer, AnimatorControllerPropModNode, AnimatorControllerPropModNode + AnimatorControllerNodeContainer, AnimatorControllerPropModNode>, AnimatorControllerPropModNode> > { private readonly Animator _animator; @@ -190,39 +190,39 @@ public static ComponentNodeContainer ComponentFromPlayableLayers(Animator animat (AnimatorWeightState, AnimatorLayerBlendingMode, AnimatorControllerNodeContainer?) source) => source.Item3; - public PlayableLayerNodeInfo GetIntermediate( + public PlayableLayerNodeInfo> GetIntermediate( (AnimatorWeightState, AnimatorLayerBlendingMode, AnimatorControllerNodeContainer?) source, - AnimatorControllerPropModNode node, int index) => - new PlayableLayerNodeInfo(source.Item1, source.Item2, node, index); + AnimatorControllerPropModNode> node, int index) => + new(source.Item1, source.Item2, node, index); - public PlayableLayerNodeInfo GetIntermediate( + public PlayableLayerNodeInfo> GetIntermediate( (AnimatorWeightState, AnimatorLayerBlendingMode, AnimatorControllerNodeContainer?) source, - AnimatorControllerPropModNode node, int index) => - new PlayableLayerNodeInfo(source.Item1, source.Item2, node, index); + AnimatorControllerPropModNode> node, int index) => + new(source.Item1, source.Item2, node, index); - public ComponentPropModNodeBase> MergeNode(List> nodes, int sourceCount) => - new AnimatorPropModNode(_animator, nodes); + public ComponentPropModNodeBase> MergeNode(List>> nodes, int sourceCount) => + new AnimatorPropModNode>(_animator, nodes); - public ComponentPropModNodeBase> MergeNode(List> nodes, int sourceCount) => - new AnimatorPropModNode(_animator, nodes); + public ComponentPropModNodeBase> MergeNode(List>> nodes, int sourceCount) => + new AnimatorPropModNode>(_animator, nodes); } internal static AnimatorControllerNodeContainer AnimatorControllerFromAnimatorLayers( IEnumerable<(AnimatorWeightState, AnimatorLayerBlendingMode, AnimatorLayerNodeContainer?)> layers) => Merge< - AnimatorControllerNodeContainer, AnimatorControllerPropModNode, AnimatorControllerPropModNode, - AnimatorLayerNodeInfo, AnimatorLayerNodeInfo, + AnimatorControllerNodeContainer, AnimatorControllerPropModNode>, AnimatorControllerPropModNode>, + AnimatorLayerNodeInfo>, AnimatorLayerNodeInfo>, (AnimatorWeightState, AnimatorLayerBlendingMode, AnimatorLayerNodeContainer?), - AnimatorLayerNodeContainer, AnimatorLayerPropModNode, AnimatorLayerPropModNode, + AnimatorLayerNodeContainer, AnimatorLayerPropModNode>, AnimatorLayerPropModNode>, AnimatorLayerMerger >(layers, default); private struct AnimatorLayerMerger : IMergeProperty1< - AnimatorControllerNodeContainer, AnimatorControllerPropModNode, AnimatorControllerPropModNode + AnimatorControllerNodeContainer, AnimatorControllerPropModNode>, AnimatorControllerPropModNode> , - AnimatorLayerNodeInfo, AnimatorLayerNodeInfo, + AnimatorLayerNodeInfo>, AnimatorLayerNodeInfo>, (AnimatorWeightState, AnimatorLayerBlendingMode, AnimatorLayerNodeContainer?), - AnimatorLayerNodeContainer, AnimatorLayerPropModNode, AnimatorLayerPropModNode + AnimatorLayerNodeContainer, AnimatorLayerPropModNode>, AnimatorLayerPropModNode> > { public AnimatorControllerNodeContainer CreateContainer() => new AnimatorControllerNodeContainer(); @@ -231,23 +231,23 @@ private struct AnimatorLayerMerger : IMergeProperty1< (AnimatorWeightState, AnimatorLayerBlendingMode, AnimatorLayerNodeContainer?) source) => source.Item3; - public AnimatorLayerNodeInfo GetIntermediate( + public AnimatorLayerNodeInfo> GetIntermediate( (AnimatorWeightState, AnimatorLayerBlendingMode, AnimatorLayerNodeContainer?) source, - AnimatorLayerPropModNode node, int index) => - new AnimatorLayerNodeInfo(source.Item1, source.Item2, node, index); + AnimatorLayerPropModNode> node, int index) => + new AnimatorLayerNodeInfo>(source.Item1, source.Item2, node, index); - public AnimatorLayerNodeInfo GetIntermediate( + public AnimatorLayerNodeInfo> GetIntermediate( (AnimatorWeightState, AnimatorLayerBlendingMode, AnimatorLayerNodeContainer?) source, - AnimatorLayerPropModNode node, int index) => - new AnimatorLayerNodeInfo(source.Item1, source.Item2, node, index); + AnimatorLayerPropModNode> node, int index) => + new AnimatorLayerNodeInfo>(source.Item1, source.Item2, node, index); - public AnimatorControllerPropModNode? MergeNode(List> nodes, + public AnimatorControllerPropModNode>? MergeNode(List>> nodes, int sourceCount) => - AnimatorControllerPropModNode.Create(nodes); + AnimatorControllerPropModNode>.Create(nodes); - public AnimatorControllerPropModNode? MergeNode(List> nodes, + public AnimatorControllerPropModNode>? MergeNode(List>> nodes, int sourceCount) => - AnimatorControllerPropModNode.Create(nodes); + AnimatorControllerPropModNode>.Create(nodes); } } } diff --git a/Editor/ObjectMapping/PropertyInfo.cs b/Editor/ObjectMapping/PropertyInfo.cs index e5a395290..8e9f74da3 100644 --- a/Editor/ObjectMapping/PropertyInfo.cs +++ b/Editor/ObjectMapping/PropertyInfo.cs @@ -9,11 +9,11 @@ namespace Anatawa12.AvatarOptimizer { internal struct PropertyInfo : IPropertyInfo { - private RootPropModNode? _floatNode; - private RootPropModNode? _objectNode; + private RootPropModNode>? _floatNode; + private RootPropModNode>? _objectNode; - public RootPropModNode? FloatNode => _floatNode?.Normalize(); - public RootPropModNode? ObjectNode => _objectNode?.Normalize(); + public RootPropModNode>? FloatNode => _floatNode?.Normalize(); + public RootPropModNode>? ObjectNode => _objectNode?.Normalize(); public void MergeTo(ref PropertyInfo property) { @@ -21,7 +21,7 @@ public void MergeTo(ref PropertyInfo property) MergeNode(ref property._objectNode, ref _objectNode); } - private static void MergeNode(ref RootPropModNode? mergeTo, ref RootPropModNode? merge) + private static void MergeNode(ref RootPropModNode>? mergeTo, ref RootPropModNode>? merge) where T : notnull { if (merge == null || merge.IsEmpty) return; @@ -42,7 +42,7 @@ public void CopyTo(ref PropertyInfo property) CopyNode(ref property._objectNode, _objectNode); } - private static void CopyNode(ref RootPropModNode? mergeTo, RootPropModNode? merge) + private static void CopyNode(ref RootPropModNode>? mergeTo, RootPropModNode>? merge) where T : notnull { if (merge == null || merge.IsEmpty) return; @@ -55,13 +55,13 @@ private static void CopyNode(ref RootPropModNode? mergeTo, RootPropModNode mergeTo.Add(merge); } - public void ImportProperty(RootPropModNode node) + public void ImportProperty(RootPropModNode> node) { if (FloatNode != null) throw new InvalidOperationException(); _floatNode = node; } - public void ImportProperty(RootPropModNode node) + public void ImportProperty(RootPropModNode> node) { if (ObjectNode != null) throw new InvalidOperationException(); _objectNode = node; @@ -69,13 +69,13 @@ public void ImportProperty(RootPropModNode node) public void AddModification(ComponentPropModNodeBase> node, bool alwaysApplied) { - if (_floatNode == null) _floatNode = new RootPropModNode(); + if (_floatNode == null) _floatNode = new RootPropModNode>(); _floatNode.Add(node, alwaysApplied); } public void AddModification(ComponentPropModNodeBase> node, bool alwaysApplied) { - if (_objectNode == null) _objectNode = new RootPropModNode(); + if (_objectNode == null) _objectNode = new RootPropModNode>(); _objectNode.Add(node, alwaysApplied); } } @@ -100,7 +100,7 @@ public static bool ContainsFloat(this AnimationComponentInfo info, [JetBrains.Annotations.Pure] public static bool TryGetFloat(this AnimationComponentInfo info, string property, - [NotNullWhen(true)] out RootPropModNode? animation) + [NotNullWhen(true)] out RootPropModNode>? animation) { if (info == null) throw new ArgumentNullException(nameof(info)); animation = info.TryGetPropertyInfo(property).FloatNode; @@ -121,7 +121,7 @@ public static bool ContainsObject(this AnimationComponentInfo info } public static bool TryGetObject(this AnimationComponentInfo info, string property, - [NotNullWhen(true)] out RootPropModNode? animation) + [NotNullWhen(true)] out RootPropModNode>? animation) { if (info == null) throw new ArgumentNullException(nameof(info)); animation = info.TryGetPropertyInfo(property).ObjectNode; @@ -135,14 +135,14 @@ public static void AddModification(this AnimationComponentInfo inf info.GetPropertyInfo(property).AddModification(node, alwaysApplied); } - public static IEnumerable<(string, RootPropModNode)> GetAllFloatProperties( + public static IEnumerable<(string, RootPropModNode>)> GetAllFloatProperties( this AnimationComponentInfo info) { return info.GetAllPropertyInfo.Where(x => x.info.FloatNode != null) .Select(x => (x.name, x.info.FloatNode!)); } - public static IEnumerable<(string, RootPropModNode)> GetAllObjectProperties( + public static IEnumerable<(string, RootPropModNode>)> GetAllObjectProperties( this AnimationComponentInfo info) { return info.GetAllPropertyInfo.Where(x => x.info.ObjectNode != null) diff --git a/Editor/Processors/SkinnedMeshes/MergeSkinnedMeshProcessor.cs b/Editor/Processors/SkinnedMeshes/MergeSkinnedMeshProcessor.cs index 241c1efad..c7b331d5e 100644 --- a/Editor/Processors/SkinnedMeshes/MergeSkinnedMeshProcessor.cs +++ b/Editor/Processors/SkinnedMeshes/MergeSkinnedMeshProcessor.cs @@ -407,7 +407,7 @@ from meshInfo in meshInfos private static void MaterialParameterAnimationWarnings(MeshInfo2[] sourceRenderers, BuildContext context) { - var properties = new Dictionary, MeshInfo2)>>(); + var properties = new Dictionary>, MeshInfo2)>>(); var materialByMeshInfo2 = new List<(MeshInfo2 meshInfo2, List materials)>(); foreach (var meshInfo2 in sourceRenderers) { @@ -418,7 +418,7 @@ private static void MaterialParameterAnimationWarnings(MeshInfo2[] sourceRendere var materialPropertyName = name.Substring("material.".Length); if (!properties.TryGetValue(materialPropertyName, out var list)) - properties.Add(materialPropertyName, list = new List<(RootPropModNode, MeshInfo2)>()); + properties.Add(materialPropertyName, list = new List<(RootPropModNode>, MeshInfo2)>()); list.Add((property, meshInfo2)); } diff --git a/Editor/Processors/TraceAndOptimize/AutoMergeSkinnedMesh.cs b/Editor/Processors/TraceAndOptimize/AutoMergeSkinnedMesh.cs index ec55c85f9..f6ebbdd38 100644 --- a/Editor/Processors/TraceAndOptimize/AutoMergeSkinnedMesh.cs +++ b/Editor/Processors/TraceAndOptimize/AutoMergeSkinnedMesh.cs @@ -334,7 +334,7 @@ private static (Activeness, EqualsHashSet<(bool initial, EqualsHashSet !(x is AnimatorParsersV2.AnimatorPropModNode))) + if (p.ComponentNodes.Any(x => !(x is AnimatorParsersV2.AnimatorPropModNode>))) return null; locations.Add((component.enabled, new EqualsHashSet(AnimationLocation.CollectAnimationLocation(p)))); @@ -349,7 +349,7 @@ private static (Activeness, EqualsHashSet<(bool initial, EqualsHashSet !(x is AnimatorParsersV2.AnimatorPropModNode))) + if (p.ComponentNodes.Any(x => x is not AnimatorParsersV2.AnimatorPropModNode>)) return null; locations.Add((transform.gameObject.activeSelf, new EqualsHashSet(AnimationLocation.CollectAnimationLocation(p)))); @@ -383,7 +383,7 @@ private static (Activeness, EqualsHashSet<(bool initial, EqualsHashSet !(x is AnimatorParsersV2.AnimatorPropModNode))) + if (node.ComponentNodes.Any(x => !(x is AnimatorParsersV2.AnimatorPropModNode>))) return null; locations.UnionWith(AnimationLocation.CollectAnimationLocation(node) .Select(location => (property, location))); diff --git a/Editor/Processors/TraceAndOptimize/OptimizeTexture.cs b/Editor/Processors/TraceAndOptimize/OptimizeTexture.cs index d42067dc0..1ab2581ee 100644 --- a/Editor/Processors/TraceAndOptimize/OptimizeTexture.cs +++ b/Editor/Processors/TraceAndOptimize/OptimizeTexture.cs @@ -458,7 +458,7 @@ internal void RemapVertexUvs(ICollection<(EqualsHashSet, AtlasResult)> atl if (!component.TryGetObject($"m_Materials.Array.data[{materialSlotIndex}]", out var animation)) return (safeToMerge: true, Array.Empty()); - if (animation.ComponentNodes.SingleOrDefault() is AnimatorPropModNode componentNode) + if (animation.ComponentNodes.SingleOrDefault() is AnimatorPropModNode> componentNode) { if (componentNode.Value.PossibleValues is not {} possibleValues) throw new InvalidOperationException("PossibleValues is null"); diff --git a/Editor/Utils/AnimationLocation.cs b/Editor/Utils/AnimationLocation.cs index a6e57499d..d05eadc92 100644 --- a/Editor/Utils/AnimationLocation.cs +++ b/Editor/Utils/AnimationLocation.cs @@ -36,9 +36,9 @@ public AnimationLocation(Animator component, int playableLayerIndex, int animati Clip = clip; } - public static IEnumerable CollectAnimationLocation(RootPropModNode node) + public static IEnumerable CollectAnimationLocation(RootPropModNode> node) { - foreach (var animatorNode in node.ComponentNodes.OfType>()) + foreach (var animatorNode in node.ComponentNodes.OfType>>()) foreach (var playableNodeInfo in animatorNode.LayersReversed.WhileApplied()) foreach (var animatorNodeInfo in playableNodeInfo.Node.LayersReversed.WhileApplied()) foreach (var animatorStateNode in animatorNodeInfo.Node.Children) @@ -66,8 +66,8 @@ private static IEnumerable CollectAnimationLocationSlow(Anima int playableLayer, int animatorLayer, AnimatorState state, ImmutablePropModNode> node) { // slow path: recursively collect blend tree - var queue = new Queue<(BlendTreeNode, int[])>(); - queue.Enqueue(((BlendTreeNode)node, Array.Empty())); + var queue = new Queue<(BlendTreeNode>, int[])>(); + queue.Enqueue(((BlendTreeNode>)node, Array.Empty())); while (queue.Count != 0) { @@ -83,7 +83,7 @@ private static IEnumerable CollectAnimationLocationSlow(Anima yield return new AnimationLocation(animator, playableLayer, animatorLayer, state, newLocation, floatNode.Curve, floatNode.Clip); break; - case BlendTreeNode childBlendTree: + case BlendTreeNode> childBlendTree: queue.Enqueue((childBlendTree, newLocation)); break; default: From 0d1e167f95ddb6f431993fea04f0acb1415032cc Mon Sep 17 00:00:00 2001 From: anatawa12 Date: Fri, 4 Oct 2024 17:36:29 +0900 Subject: [PATCH 04/11] chore: separate ValueInfo for float and Object phase 4: actually separate type --- Editor/AnimatorParserV2/AnimationParser.cs | 32 ++-- .../AnimatorControllerPropModNode.cs | 4 +- Editor/AnimatorParserV2/AnimatorParser.cs | 36 ++--- .../AnimatorParserDebugWindow.cs | 18 +-- Editor/AnimatorParserV2/NodeContainer.cs | 62 ++++---- Editor/AnimatorParserV2/PropModNode.cs | 141 +++++++++++++++--- Editor/AnimatorParserV2/Utilities.cs | 78 +++++----- Editor/ContextExtensions.cs | 2 +- Editor/ObjectMapping/PropertyInfo.cs | 40 ++--- .../MergeSkinnedMeshProcessor.cs | 4 +- .../TraceAndOptimize/AutoMergeSkinnedMesh.cs | 6 +- .../TraceAndOptimize/OptimizeTexture.cs | 2 +- Editor/Utils/AnimationLocation.cs | 14 +- Test~/AnimatorParser/TestUtil.cs | 16 +- 14 files changed, 278 insertions(+), 177 deletions(-) diff --git a/Editor/AnimatorParserV2/AnimationParser.cs b/Editor/AnimatorParserV2/AnimationParser.cs index cf329f4ce..00827f28a 100644 --- a/Editor/AnimatorParserV2/AnimationParser.cs +++ b/Editor/AnimatorParserV2/AnimationParser.cs @@ -49,10 +49,10 @@ private ImmutableNodeContainer ParseBlendTree(GameObject root, BlendTree blendTr var children = blendTree.children; return NodesMerger.Merge< - ImmutableNodeContainer, ImmutablePropModNode>, ImmutablePropModNode>, - BlendTreeElement>, BlendTreeElement>, - ImmutableNodeContainer, ImmutableNodeContainer, ImmutablePropModNode>, - ImmutablePropModNode>, + ImmutableNodeContainer, ImmutablePropModNode, ImmutablePropModNode, + BlendTreeElement, BlendTreeElement, + ImmutableNodeContainer, ImmutableNodeContainer, ImmutablePropModNode, + ImmutablePropModNode, BlendTreeMergeProperty >(children.Select(x => ParseMotionInner(root, x.motion, mapping)), new BlendTreeMergeProperty(blendTree.blendType)); @@ -60,10 +60,10 @@ private ImmutableNodeContainer ParseBlendTree(GameObject root, BlendTree blendTr internal readonly struct BlendTreeMergeProperty : IMergeProperty1< - ImmutableNodeContainer, ImmutablePropModNode>, ImmutablePropModNode>, - BlendTreeElement>, BlendTreeElement>, - ImmutableNodeContainer, ImmutableNodeContainer, ImmutablePropModNode>, - ImmutablePropModNode> + ImmutableNodeContainer, ImmutablePropModNode, ImmutablePropModNode, + BlendTreeElement, BlendTreeElement, + ImmutableNodeContainer, ImmutableNodeContainer, ImmutablePropModNode, + ImmutablePropModNode > { private readonly BlendTreeType _blendType; @@ -76,17 +76,17 @@ public BlendTreeMergeProperty(BlendTreeType blendType) public ImmutableNodeContainer CreateContainer() => new(); public ImmutableNodeContainer GetContainer(ImmutableNodeContainer source) => source; - public BlendTreeElement> GetIntermediate(ImmutableNodeContainer source, - ImmutablePropModNode> node, int index) => new BlendTreeElement>(index, node); + public BlendTreeElement GetIntermediate(ImmutableNodeContainer source, + ImmutablePropModNode node, int index) => new BlendTreeElement(index, node); - public BlendTreeElement> GetIntermediate(ImmutableNodeContainer source, - ImmutablePropModNode> node, int index) => new BlendTreeElement>(index, node); + public BlendTreeElement GetIntermediate(ImmutableNodeContainer source, + ImmutablePropModNode node, int index) => new BlendTreeElement(index, node); - public ImmutablePropModNode> MergeNode(List>> nodes, int sourceCount) => - new BlendTreeNode>(nodes, _blendType, partial: nodes.Count != sourceCount); + public ImmutablePropModNode MergeNode(List> nodes, int sourceCount) => + new BlendTreeNode(nodes, _blendType, partial: nodes.Count != sourceCount); - public ImmutablePropModNode> MergeNode(List>> nodes, int sourceCount) => - new BlendTreeNode>(nodes, _blendType, partial: nodes.Count != sourceCount); + public ImmutablePropModNode MergeNode(List> nodes, int sourceCount) => + new BlendTreeNode(nodes, _blendType, partial: nodes.Count != sourceCount); } private readonly Dictionary<(GameObject, AnimationClip), ImmutableNodeContainer> _parsedAnimationCache = new(); diff --git a/Editor/AnimatorParserV2/AnimatorControllerPropModNode.cs b/Editor/AnimatorParserV2/AnimatorControllerPropModNode.cs index 23052bb17..de410e149 100644 --- a/Editor/AnimatorParserV2/AnimatorControllerPropModNode.cs +++ b/Editor/AnimatorParserV2/AnimatorControllerPropModNode.cs @@ -7,13 +7,13 @@ namespace Anatawa12.AvatarOptimizer.AnimatorParsersV2 { - class HumanoidAnimatorPropModNode : ComponentPropModNode, Animator> + class HumanoidAnimatorPropModNode : ComponentPropModNode { public HumanoidAnimatorPropModNode(Animator component) : base(component) { } - public override ValueInfo Value => ValueInfo.Variable; + public override FloatValueInfo Value => FloatValueInfo.Variable; public override bool AppliedAlways => true; } diff --git a/Editor/AnimatorParserV2/AnimatorParser.cs b/Editor/AnimatorParserV2/AnimatorParser.cs index a27795fed..04fd57893 100644 --- a/Editor/AnimatorParserV2/AnimatorParser.cs +++ b/Editor/AnimatorParserV2/AnimatorParser.cs @@ -448,39 +448,39 @@ public AnimatorLayerNodeContainer ParseAnimatorControllerLayer( } return NodesMerger.Merge< - AnimatorLayerNodeContainer, AnimatorLayerPropModNode>, AnimatorLayerPropModNode>, - AnimatorStatePropModNode>, AnimatorStatePropModNode>, + AnimatorLayerNodeContainer, AnimatorLayerPropModNode, AnimatorLayerPropModNode, + AnimatorStatePropModNode, AnimatorStatePropModNode, (AnimatorState, ImmutableNodeContainer), - ImmutableNodeContainer, ImmutablePropModNode>, ImmutablePropModNode>, + ImmutableNodeContainer, ImmutablePropModNode, ImmutablePropModNode, LayerMerger >(parsedMotions, default); } struct LayerMerger : IMergeProperty1< - AnimatorLayerNodeContainer, AnimatorLayerPropModNode>, AnimatorLayerPropModNode>, - AnimatorStatePropModNode>, AnimatorStatePropModNode>, + AnimatorLayerNodeContainer, AnimatorLayerPropModNode, AnimatorLayerPropModNode, + AnimatorStatePropModNode, AnimatorStatePropModNode, (AnimatorState, ImmutableNodeContainer), - ImmutableNodeContainer, ImmutablePropModNode>, ImmutablePropModNode> + ImmutableNodeContainer, ImmutablePropModNode, ImmutablePropModNode > { public AnimatorLayerNodeContainer CreateContainer() => new AnimatorLayerNodeContainer(); public ImmutableNodeContainer GetContainer((AnimatorState, ImmutableNodeContainer) source) => source.Item2; - public AnimatorStatePropModNode> GetIntermediate((AnimatorState, ImmutableNodeContainer) source, - ImmutablePropModNode> node, int index) => - new AnimatorStatePropModNode>(node, source.Item1); + public AnimatorStatePropModNode GetIntermediate((AnimatorState, ImmutableNodeContainer) source, + ImmutablePropModNode node, int index) => + new AnimatorStatePropModNode(node, source.Item1); - public AnimatorStatePropModNode> GetIntermediate((AnimatorState, ImmutableNodeContainer) source, - ImmutablePropModNode> node, int index) => - new AnimatorStatePropModNode>(node, source.Item1); + public AnimatorStatePropModNode GetIntermediate((AnimatorState, ImmutableNodeContainer) source, + ImmutablePropModNode node, int index) => + new AnimatorStatePropModNode(node, source.Item1); - public AnimatorLayerPropModNode> - MergeNode(List>> nodes, int sourceCount) => - new AnimatorLayerPropModNode>(nodes, nodes.Count != sourceCount); + public AnimatorLayerPropModNode + MergeNode(List> nodes, int sourceCount) => + new AnimatorLayerPropModNode(nodes, nodes.Count != sourceCount); - public AnimatorLayerPropModNode> - MergeNode(List>> nodes, int sourceCount) => - new AnimatorLayerPropModNode>(nodes, nodes.Count != sourceCount); + public AnimatorLayerPropModNode + MergeNode(List> nodes, int sourceCount) => + new AnimatorLayerPropModNode(nodes, nodes.Count != sourceCount); } AnimatorWeightState? GetWeightState(float weight, AnimatorWeightChange external) diff --git a/Editor/AnimatorParserV2/AnimatorParserDebugWindow.cs b/Editor/AnimatorParserV2/AnimatorParserDebugWindow.cs index f5661d013..b1da2030d 100644 --- a/Editor/AnimatorParserV2/AnimatorParserDebugWindow.cs +++ b/Editor/AnimatorParserV2/AnimatorParserDebugWindow.cs @@ -144,12 +144,12 @@ private string CreateText(bool detailed = false) return resultText.ToString(); } - private void AppendNodeRecursive(PropModNode> propState, StringBuilder resultText, string indent) - where T : notnull + private void AppendNodeRecursive(PropModNode propState, StringBuilder resultText, string indent) + where TValueInfo : struct, IValueInfo { switch (propState) { - case AnimatorControllerPropModNode> animCont: + case AnimatorControllerPropModNode animCont: resultText.Append($"{indent}AnimatorController: \n"); foreach (var layerInfo in animCont.LayersReversed) { @@ -157,11 +157,11 @@ private void AppendNodeRecursive(PropModNode> propState, StringB AppendNodeRecursive(layerInfo.Node, resultText, indent + " "); } break; - case AnimationComponentPropModNode> animation: + case AnimationComponentPropModNode animation: resultText.Append($"{indent}Animation: {animation.Component.name}\n"); AppendNodeRecursive(animation.Animation, resultText, indent + " "); break; - case AnimatorPropModNode> animator: + case AnimatorPropModNode animator: resultText.Append($"{indent}Animator: {animator.Component.name}\n"); foreach (var layerInfo in animator.LayersReversed) { @@ -175,16 +175,16 @@ private void AppendNodeRecursive(PropModNode> propState, StringB case VariableComponentPropModNode variable: resultText.Append($"{indent}Variable({variable.Component.GetType().Name}): {variable.Component.name}\n"); break; - case AnimatorLayerPropModNode> animatorLayer: + case AnimatorLayerPropModNode animatorLayer: resultText.Append($"{indent}AnimatorLayer:\n"); foreach (var childNode in animatorLayer.Children) AppendNodeRecursive(childNode, resultText, indent + " "); break; - case AnimatorStatePropModNode> stateNode: + case AnimatorStatePropModNode stateNode: resultText.Append($"{indent}AnimatorState: {stateNode.State.name}\n"); AppendNodeRecursive(stateNode.Node, resultText, indent + " "); break; - case BlendTreeNode> blendTreeNode: + case BlendTreeNode blendTreeNode: resultText.Append($"{indent}BlendTree:\n"); foreach (var childNode in blendTreeNode.Children) { @@ -198,7 +198,7 @@ private void AppendNodeRecursive(PropModNode> propState, StringB case ObjectAnimationCurveNode curve: resultText.Append($"{indent}ObjectAnimationCurve: {curve.Clip.name}\n"); break; - case RootPropModNode> rootNode: + case RootPropModNode rootNode: resultText.Append($"{indent}Root:\n"); foreach (var rootNodeChild in rootNode.Children) { diff --git a/Editor/AnimatorParserV2/NodeContainer.cs b/Editor/AnimatorParserV2/NodeContainer.cs index 88894e45b..1a6f31fd8 100644 --- a/Editor/AnimatorParserV2/NodeContainer.cs +++ b/Editor/AnimatorParserV2/NodeContainer.cs @@ -7,8 +7,8 @@ namespace Anatawa12.AvatarOptimizer.AnimatorParsersV2 { internal interface INodeContainer { - IReadOnlyDictionary<(ComponentOrGameObject target, string prop), PropModNode>> FloatNodes { get; } - IReadOnlyDictionary<(ComponentOrGameObject target, string prop), PropModNode>> ObjectNodes { get; } + IReadOnlyDictionary<(ComponentOrGameObject target, string prop), PropModNode> FloatNodes { get; } + IReadOnlyDictionary<(ComponentOrGameObject target, string prop), PropModNode> ObjectNodes { get; } } internal interface INodeContainer @@ -17,25 +17,25 @@ internal interface INodeContainer IReadOnlyDictionary<(ComponentOrGameObject target, string prop), TObjectNode> ObjectNodes { get; } } - internal class RootPropModNodeContainer : INodeContainer>, RootPropModNode>>, INodeContainer + internal class RootPropModNodeContainer : INodeContainer, RootPropModNode>, INodeContainer { - private readonly Dictionary<(ComponentOrGameObject target, string prop), RootPropModNode>> _floatNodes = - new Dictionary<(ComponentOrGameObject, string), RootPropModNode>>(); - private readonly Dictionary<(ComponentOrGameObject target, string prop), RootPropModNode>> _objectNodes = - new Dictionary<(ComponentOrGameObject, string), RootPropModNode>>(); + private readonly Dictionary<(ComponentOrGameObject target, string prop), RootPropModNode> _floatNodes = + new Dictionary<(ComponentOrGameObject, string), RootPropModNode>(); + private readonly Dictionary<(ComponentOrGameObject target, string prop), RootPropModNode> _objectNodes = + new Dictionary<(ComponentOrGameObject, string), RootPropModNode>(); - IReadOnlyDictionary<(ComponentOrGameObject target, string prop), PropModNode>> INodeContainer. + IReadOnlyDictionary<(ComponentOrGameObject target, string prop), PropModNode> INodeContainer. FloatNodes => - Utils.CastDic>>().CastedDic(FloatNodes); + Utils.CastDic>().CastedDic(FloatNodes); - IReadOnlyDictionary<(ComponentOrGameObject target, string prop), PropModNode>> INodeContainer. + IReadOnlyDictionary<(ComponentOrGameObject target, string prop), PropModNode> INodeContainer. ObjectNodes => - Utils.CastDic>>().CastedDic(ObjectNodes); + Utils.CastDic>().CastedDic(ObjectNodes); - public IReadOnlyDictionary<(ComponentOrGameObject target, string prop), RootPropModNode>> FloatNodes => + public IReadOnlyDictionary<(ComponentOrGameObject target, string prop), RootPropModNode> FloatNodes => _floatNodes; - public IReadOnlyDictionary<(ComponentOrGameObject target, string prop), RootPropModNode>> ObjectNodes => + public IReadOnlyDictionary<(ComponentOrGameObject target, string prop), RootPropModNode> ObjectNodes => _objectNodes; public void Add(ComponentNodeContainer? container, bool alwaysApplied) @@ -45,31 +45,31 @@ public void Add(ComponentNodeContainer? container, bool alwaysApplied) foreach (var (key, value) in container.FloatNodes) { if (!FloatNodes.TryGetValue(key, out var node)) - _floatNodes.Add(key, node = new RootPropModNode>()); + _floatNodes.Add(key, node = new RootPropModNode()); node.Add(value, alwaysApplied); } foreach (var (key, value) in container.ObjectNodes) { if (!ObjectNodes.TryGetValue(key, out var node)) - _objectNodes.Add(key, node = new RootPropModNode>()); + _objectNodes.Add(key, node = new RootPropModNode()); node.Add(value, alwaysApplied); } } - public void Add(Component component, string prop, ComponentPropModNodeBase> node, bool alwaysApplied) + public void Add(Component component, string prop, ComponentPropModNodeBase node, bool alwaysApplied) { var key = (component, prop); if (!FloatNodes.TryGetValue(key, out var root)) - _floatNodes.Add(key, root = new RootPropModNode>()); + _floatNodes.Add(key, root = new RootPropModNode()); root.Add(node, alwaysApplied); } - public void Add(Component component, string prop, ComponentPropModNodeBase> node, bool alwaysApplied) + public void Add(Component component, string prop, ComponentPropModNodeBase node, bool alwaysApplied) { var key = (component, prop); if (!_objectNodes.TryGetValue(key, out var root)) - _objectNodes.Add(key, root = new RootPropModNode>()); + _objectNodes.Add(key, root = new RootPropModNode()); root.Add(node, alwaysApplied); } @@ -80,8 +80,8 @@ public void Add(Component component, string prop, ComponentPropModNodeBase : INodeContainer, INodeContainer - where TFloatNode : PropModNode> - where TObjectNode : PropModNode> + where TFloatNode : PropModNode + where TObjectNode : PropModNode { private readonly Dictionary<(ComponentOrGameObject target, string prop), TFloatNode> _floatNodes = new Dictionary<(ComponentOrGameObject, string), TFloatNode>(); @@ -92,11 +92,11 @@ internal class NodeContainerBase : INodeContainer ObjectNodes => _objectNodes; - IReadOnlyDictionary<(ComponentOrGameObject target, string prop), PropModNode>> INodeContainer. - FloatNodes => Utils.CastDic>>().CastedDic(_floatNodes); + IReadOnlyDictionary<(ComponentOrGameObject target, string prop), PropModNode> INodeContainer. + FloatNodes => Utils.CastDic>().CastedDic(_floatNodes); - IReadOnlyDictionary<(ComponentOrGameObject target, string prop), PropModNode>> INodeContainer. - ObjectNodes => Utils.CastDic>>().CastedDic(_objectNodes); + IReadOnlyDictionary<(ComponentOrGameObject target, string prop), PropModNode> INodeContainer. + ObjectNodes => Utils.CastDic>().CastedDic(_objectNodes); public void Add(ComponentOrGameObject target, string prop, TFloatNode node) { @@ -122,22 +122,22 @@ public void Set(ComponentOrGameObject target, string prop, TObjectNode node) } } - internal class AnimatorLayerNodeContainer : NodeContainerBase>, - AnimatorLayerPropModNode>> + internal class AnimatorLayerNodeContainer : NodeContainerBase, + AnimatorLayerPropModNode> { } - internal class AnimatorControllerNodeContainer : NodeContainerBase>, - AnimatorControllerPropModNode>> + internal class AnimatorControllerNodeContainer : NodeContainerBase, + AnimatorControllerPropModNode> { } internal class ComponentNodeContainer - : NodeContainerBase>, ComponentPropModNodeBase>> + : NodeContainerBase, ComponentPropModNodeBase> { } - internal class ImmutableNodeContainer : NodeContainerBase>, ImmutablePropModNode>> + internal class ImmutableNodeContainer : NodeContainerBase, ImmutablePropModNode> { } } diff --git a/Editor/AnimatorParserV2/PropModNode.cs b/Editor/AnimatorParserV2/PropModNode.cs index 5994f7a0c..488137e4d 100644 --- a/Editor/AnimatorParserV2/PropModNode.cs +++ b/Editor/AnimatorParserV2/PropModNode.cs @@ -56,6 +56,107 @@ internal abstract class PropModNode : IErrorContext, IPropModNode public abstract IEnumerable ContextReferences { get; } } + class PropModNodeWrapper : PropModNode + where TValueInfoOut: struct, IValueInfo + where TValueInfoInner: struct, IValueInfo + { + private PropModNode _innerNode; + private Func _converter; + + public PropModNodeWrapper(PropModNode innerNode, Func converter) + { + _innerNode = innerNode; + _converter = converter; + } + + public override bool AppliedAlways => _innerNode.AppliedAlways; + public override TValueInfoOut Value => _converter(_innerNode.Value); + public override IEnumerable ContextReferences => _innerNode.ContextReferences; + } + + struct LayerWrapper : ILayer + where TValueInfoOut : struct, IValueInfo + where TValueInfoInner : struct, IValueInfo + { + private ILayer _innerLayer; + private Func _converter; + + public LayerWrapper(ILayer innerLayer, Func converter) + { + _innerLayer = innerLayer; + _converter = converter; + } + + public AnimatorWeightState Weight => _innerLayer.Weight; + public AnimatorLayerBlendingMode BlendingMode => _innerLayer.BlendingMode; + IPropModNode ILayer.Node => Node; + + public PropModNode Node => new PropModNodeWrapper(_innerLayer.Node, _converter); + } + + internal readonly struct FloatValueInfo : IValueInfo + { + private readonly ValueInfo _value; + + public FloatValueInfo(float value) => this = new FloatValueInfo(new ValueInfo(value)); + public FloatValueInfo(float[] values) => this = new FloatValueInfo(new ValueInfo(values)); + private FloatValueInfo(ValueInfo value) => _value = value; + + public bool IsConstant => _value.IsConstant; + public float ConstantValue => _value.ConstantValue; + public float[]? PossibleValues => _value.PossibleValues; + public static FloatValueInfo Variable => new(ValueInfo.Variable); + + private PropModNode> Wrap(PropModNode node) => + new PropModNodeWrapper>(node, x => x._value); + private LayerWrapper> Wrap(TLayer layer) where TLayer : ILayer => + new(layer, x => x._value); + + public bool TryGetConstantValue(out float o) => _value.TryGetConstantValue(out o); + + public FloatValueInfo ConstantInfoForSideBySide(IEnumerable> nodes) => + new(_value.ConstantInfoForSideBySide(nodes.Select(Wrap))); + + public FloatValueInfo ConstantInfoForBlendTree(IEnumerable> nodes, + BlendTreeType blendTreeType) => new(_value.ConstantInfoForBlendTree(nodes.Select(Wrap), blendTreeType)); + + public FloatValueInfo ConstantInfoForOverriding(IEnumerable layersReversed) + where TLayer : ILayer => new(_value.ConstantInfoForOverriding(layersReversed.Select(Wrap))); + + public bool AlwaysAppliedForOverriding(IEnumerable layersReversed) + where TLayer : ILayer => _value.AlwaysAppliedForOverriding(layersReversed.Select(Wrap)); + } + + + internal readonly struct ObjectValueInfo : IValueInfo + { + private readonly ValueInfo _value; + + public ObjectValueInfo(Object value) => this = new ObjectValueInfo(new ValueInfo(value)); + public ObjectValueInfo(Object[] values) => this = new ObjectValueInfo(new ValueInfo(values)); + private ObjectValueInfo(ValueInfo value) => _value = value; + + public bool IsConstant => _value.IsConstant; + public Object ConstantValue => _value.ConstantValue; + public Object[]? PossibleValues => _value.PossibleValues; + + private PropModNode> Wrap(PropModNode node) => + new PropModNodeWrapper>(node, x => x._value); + private LayerWrapper> Wrap(TLayer layer) where TLayer : ILayer => + new(layer, x => x._value); + + public ObjectValueInfo ConstantInfoForSideBySide(IEnumerable> nodes) => + new(_value.ConstantInfoForSideBySide(nodes.Select(Wrap))); + + public ObjectValueInfo ConstantInfoForBlendTree(IEnumerable> nodes, + BlendTreeType blendTreeType) => new(_value.ConstantInfoForBlendTree(nodes.Select(Wrap), blendTreeType)); + + public ObjectValueInfo ConstantInfoForOverriding(IEnumerable layersReversed) + where TLayer : ILayer => new(_value.ConstantInfoForOverriding(layersReversed.Select(Wrap))); + + public bool AlwaysAppliedForOverriding(IEnumerable layersReversed) + where TLayer : ILayer => _value.AlwaysAppliedForOverriding(layersReversed.Select(Wrap)); + } /// /// The abstract information about actual value of PropModNode. /// @@ -341,7 +442,7 @@ internal abstract class ImmutablePropModNode : PropModNode> + internal class FloatAnimationCurveNode : ImmutablePropModNode { public AnimationCurve Curve { get; } public AnimationClip Clip { get; } @@ -370,26 +471,26 @@ private FloatAnimationCurveNode(AnimationClip clip, AnimationCurve curve, float Debug.Assert(curve.keys.Length > 0); Clip = clip; Curve = curve; - _constantInfo = new Lazy>(() => ParseProperty(curve, referenceValue), isThreadSafe: false); + _constantInfo = new Lazy(() => ParseProperty(curve, referenceValue), isThreadSafe: false); } - private readonly Lazy> _constantInfo; + private readonly Lazy _constantInfo; public override bool AppliedAlways => true; - public override ValueInfo Value => _constantInfo.Value; + public override FloatValueInfo Value => _constantInfo.Value; public override IEnumerable ContextReferences => new[] { ObjectRegistry.GetReference(Clip) }; - private static ValueInfo ParseProperty(AnimationCurve curve, float referenceValue) + private static FloatValueInfo ParseProperty(AnimationCurve curve, float referenceValue) { var curveValue = ParseCurve(curve); - if (curveValue.PossibleValues == null) return ValueInfo.Variable; - return new ValueInfo(curveValue.PossibleValues.Concat(new[] { referenceValue }).Distinct() + if (curveValue.PossibleValues == null) return FloatValueInfo.Variable; + return new FloatValueInfo(curveValue.PossibleValues.Concat(new[] { referenceValue }).Distinct() .ToArray()); } - private static ValueInfo ParseCurve(AnimationCurve curve) + private static FloatValueInfo ParseCurve(AnimationCurve curve) { - if (curve.keys.Length == 1) return new ValueInfo(curve.keys[0].value); + if (curve.keys.Length == 1) return new FloatValueInfo(curve.keys[0].value); float constValue = 0; foreach (var (preKey, postKey) in curve.keys.ZipWithNext()) @@ -397,20 +498,20 @@ private static ValueInfo ParseCurve(AnimationCurve curve) var preWeighted = preKey.weightedMode == WeightedMode.Out || preKey.weightedMode == WeightedMode.Both; var postWeighted = postKey.weightedMode == WeightedMode.In || postKey.weightedMode == WeightedMode.Both; - if (preKey.value.CompareTo(postKey.value) != 0) return ValueInfo.Variable; + if (preKey.value.CompareTo(postKey.value) != 0) return FloatValueInfo.Variable; constValue = preKey.value; // it's constant if (float.IsInfinity(preKey.outWeight) || float.IsInfinity(postKey.inTangent)) continue; if (preKey.outTangent == 0 && postKey.inTangent == 0) continue; if (preWeighted && postWeighted && preKey.outWeight == 0 && postKey.inWeight == 0) continue; - return ValueInfo.Variable; + return FloatValueInfo.Variable; } - return new ValueInfo(constValue); + return new FloatValueInfo(constValue); } } - internal class ObjectAnimationCurveNode : ImmutablePropModNode> + internal class ObjectAnimationCurveNode : ImmutablePropModNode { public ObjectReferenceKeyframe[] Frames { get; set; } public AnimationClip Clip { get; } @@ -428,18 +529,18 @@ private ObjectAnimationCurveNode(AnimationClip clip, ObjectReferenceKeyframe[] f Debug.Assert(frames.Length > 0); Clip = clip; Frames = frames; - _constantInfo = new Lazy>(() => ParseProperty(frames), isThreadSafe: false); + _constantInfo = new Lazy(() => ParseProperty(frames), isThreadSafe: false); } - private readonly Lazy> _constantInfo; + private readonly Lazy _constantInfo; public override bool AppliedAlways => true; - public override ValueInfo Value => _constantInfo.Value; + public override ObjectValueInfo Value => _constantInfo.Value; public override IEnumerable ContextReferences => new[] { ObjectRegistry.GetReference(Clip) }; - private static ValueInfo ParseProperty(ObjectReferenceKeyframe[] frames) => - new ValueInfo(frames.Select(x => x.value).Distinct().ToArray()); + private static ObjectValueInfo ParseProperty(ObjectReferenceKeyframe[] frames) => + new(frames.Select(x => x.value).Distinct().ToArray()); } internal struct BlendTreeElement @@ -519,14 +620,14 @@ protected ComponentPropModNode(TComponent component) : base(component) new[] { ObjectRegistry.GetReference(Component) }; } - class VariableComponentPropModNode : ComponentPropModNode, Component> + class VariableComponentPropModNode : ComponentPropModNode { public VariableComponentPropModNode(Component component) : base(component) { } public override bool AppliedAlways => false; - public override ValueInfo Value => ValueInfo.Variable; + public override FloatValueInfo Value => FloatValueInfo.Variable; } class AnimationComponentPropModNode : ComponentPropModNode diff --git a/Editor/AnimatorParserV2/Utilities.cs b/Editor/AnimatorParserV2/Utilities.cs index 51ae96f1d..7d674bd22 100644 --- a/Editor/AnimatorParserV2/Utilities.cs +++ b/Editor/AnimatorParserV2/Utilities.cs @@ -31,8 +31,8 @@ public static TResultContainer Merge< where TSourceObjectNode : notnull where TResultContainer : NodeContainerBase - where TResultFloatNode : PropModNode> - where TResultObjectNode : PropModNode> + where TResultFloatNode : PropModNode + where TResultObjectNode : PropModNode where TSourceContainer : INodeContainer @@ -96,8 +96,8 @@ interface IMergeProperty1 < TSourceObjectNode > where TResultContainer : NodeContainerBase - where TResultFloatNode : PropModNode> - where TResultObjectNode : PropModNode> + where TResultFloatNode : PropModNode + where TResultObjectNode : PropModNode where TSourceContainer : INodeContainer where TSource : notnull @@ -130,13 +130,13 @@ static partial class NodesMerger foreach (var ((target, prop), value) in controller.FloatNodes) { animatorNodeContainer.Add(target, prop, - new AnimatorPropModNode>(animator, new[] { new PlayableLayerNodeInfo>(value, 0) })); + new AnimatorPropModNode(animator, new[] { new PlayableLayerNodeInfo(value, 0) })); } foreach (var ((target, prop), value) in controller.ObjectNodes) { animatorNodeContainer.Add(target, prop, - new AnimatorPropModNode>(animator, new[] { new PlayableLayerNodeInfo>(value, 0) })); + new AnimatorPropModNode(animator, new[] { new PlayableLayerNodeInfo(value, 0) })); } return animatorNodeContainer; @@ -150,12 +150,12 @@ public static ComponentNodeContainer AnimationComponentFromAnimationClip(Animati foreach (var ((target, prop), node) in animationClip.FloatNodes) { - animatorNodeContainer.Add(target, prop, new AnimationComponentPropModNode>(animation, node)); + animatorNodeContainer.Add(target, prop, new AnimationComponentPropModNode(animation, node)); } foreach (var ((target, prop), value) in animationClip.ObjectNodes) { - animatorNodeContainer.Add(target, prop, new AnimationComponentPropModNode>(animation, value)); + animatorNodeContainer.Add(target, prop, new AnimationComponentPropModNode(animation, value)); } return animatorNodeContainer; @@ -165,19 +165,19 @@ public static ComponentNodeContainer ComponentFromPlayableLayers(Animator animat IEnumerable<(AnimatorWeightState, AnimatorLayerBlendingMode, AnimatorControllerNodeContainer?)> playableLayers) => Merge< - ComponentNodeContainer, ComponentPropModNodeBase>, ComponentPropModNodeBase>, - PlayableLayerNodeInfo>, PlayableLayerNodeInfo>, + ComponentNodeContainer, ComponentPropModNodeBase, ComponentPropModNodeBase, + PlayableLayerNodeInfo, PlayableLayerNodeInfo, (AnimatorWeightState, AnimatorLayerBlendingMode, AnimatorControllerNodeContainer?), - AnimatorControllerNodeContainer, AnimatorControllerPropModNode>, - AnimatorControllerPropModNode>, + AnimatorControllerNodeContainer, AnimatorControllerPropModNode, + AnimatorControllerPropModNode, PlayableLayerMerger >(playableLayers, new PlayableLayerMerger(animator)); readonly struct PlayableLayerMerger : IMergeProperty1< - ComponentNodeContainer, ComponentPropModNodeBase>, ComponentPropModNodeBase>, - PlayableLayerNodeInfo>, PlayableLayerNodeInfo>, + ComponentNodeContainer, ComponentPropModNodeBase, ComponentPropModNodeBase, + PlayableLayerNodeInfo, PlayableLayerNodeInfo, (AnimatorWeightState, AnimatorLayerBlendingMode, AnimatorControllerNodeContainer?), - AnimatorControllerNodeContainer, AnimatorControllerPropModNode>, AnimatorControllerPropModNode> + AnimatorControllerNodeContainer, AnimatorControllerPropModNode, AnimatorControllerPropModNode > { private readonly Animator _animator; @@ -190,39 +190,39 @@ public static ComponentNodeContainer ComponentFromPlayableLayers(Animator animat (AnimatorWeightState, AnimatorLayerBlendingMode, AnimatorControllerNodeContainer?) source) => source.Item3; - public PlayableLayerNodeInfo> GetIntermediate( + public PlayableLayerNodeInfo GetIntermediate( (AnimatorWeightState, AnimatorLayerBlendingMode, AnimatorControllerNodeContainer?) source, - AnimatorControllerPropModNode> node, int index) => + AnimatorControllerPropModNode node, int index) => new(source.Item1, source.Item2, node, index); - public PlayableLayerNodeInfo> GetIntermediate( + public PlayableLayerNodeInfo GetIntermediate( (AnimatorWeightState, AnimatorLayerBlendingMode, AnimatorControllerNodeContainer?) source, - AnimatorControllerPropModNode> node, int index) => + AnimatorControllerPropModNode node, int index) => new(source.Item1, source.Item2, node, index); - public ComponentPropModNodeBase> MergeNode(List>> nodes, int sourceCount) => - new AnimatorPropModNode>(_animator, nodes); + public ComponentPropModNodeBase MergeNode(List> nodes, int sourceCount) => + new AnimatorPropModNode(_animator, nodes); - public ComponentPropModNodeBase> MergeNode(List>> nodes, int sourceCount) => - new AnimatorPropModNode>(_animator, nodes); + public ComponentPropModNodeBase MergeNode(List> nodes, int sourceCount) => + new AnimatorPropModNode(_animator, nodes); } internal static AnimatorControllerNodeContainer AnimatorControllerFromAnimatorLayers( IEnumerable<(AnimatorWeightState, AnimatorLayerBlendingMode, AnimatorLayerNodeContainer?)> layers) => Merge< - AnimatorControllerNodeContainer, AnimatorControllerPropModNode>, AnimatorControllerPropModNode>, - AnimatorLayerNodeInfo>, AnimatorLayerNodeInfo>, + AnimatorControllerNodeContainer, AnimatorControllerPropModNode, AnimatorControllerPropModNode, + AnimatorLayerNodeInfo, AnimatorLayerNodeInfo, (AnimatorWeightState, AnimatorLayerBlendingMode, AnimatorLayerNodeContainer?), - AnimatorLayerNodeContainer, AnimatorLayerPropModNode>, AnimatorLayerPropModNode>, + AnimatorLayerNodeContainer, AnimatorLayerPropModNode, AnimatorLayerPropModNode, AnimatorLayerMerger >(layers, default); private struct AnimatorLayerMerger : IMergeProperty1< - AnimatorControllerNodeContainer, AnimatorControllerPropModNode>, AnimatorControllerPropModNode> + AnimatorControllerNodeContainer, AnimatorControllerPropModNode, AnimatorControllerPropModNode , - AnimatorLayerNodeInfo>, AnimatorLayerNodeInfo>, + AnimatorLayerNodeInfo, AnimatorLayerNodeInfo, (AnimatorWeightState, AnimatorLayerBlendingMode, AnimatorLayerNodeContainer?), - AnimatorLayerNodeContainer, AnimatorLayerPropModNode>, AnimatorLayerPropModNode> + AnimatorLayerNodeContainer, AnimatorLayerPropModNode, AnimatorLayerPropModNode > { public AnimatorControllerNodeContainer CreateContainer() => new AnimatorControllerNodeContainer(); @@ -231,23 +231,23 @@ private struct AnimatorLayerMerger : IMergeProperty1< (AnimatorWeightState, AnimatorLayerBlendingMode, AnimatorLayerNodeContainer?) source) => source.Item3; - public AnimatorLayerNodeInfo> GetIntermediate( + public AnimatorLayerNodeInfo GetIntermediate( (AnimatorWeightState, AnimatorLayerBlendingMode, AnimatorLayerNodeContainer?) source, - AnimatorLayerPropModNode> node, int index) => - new AnimatorLayerNodeInfo>(source.Item1, source.Item2, node, index); + AnimatorLayerPropModNode node, int index) => + new AnimatorLayerNodeInfo(source.Item1, source.Item2, node, index); - public AnimatorLayerNodeInfo> GetIntermediate( + public AnimatorLayerNodeInfo GetIntermediate( (AnimatorWeightState, AnimatorLayerBlendingMode, AnimatorLayerNodeContainer?) source, - AnimatorLayerPropModNode> node, int index) => - new AnimatorLayerNodeInfo>(source.Item1, source.Item2, node, index); + AnimatorLayerPropModNode node, int index) => + new AnimatorLayerNodeInfo(source.Item1, source.Item2, node, index); - public AnimatorControllerPropModNode>? MergeNode(List>> nodes, + public AnimatorControllerPropModNode? MergeNode(List> nodes, int sourceCount) => - AnimatorControllerPropModNode>.Create(nodes); + AnimatorControllerPropModNode.Create(nodes); - public AnimatorControllerPropModNode>? MergeNode(List>> nodes, + public AnimatorControllerPropModNode? MergeNode(List> nodes, int sourceCount) => - AnimatorControllerPropModNode>.Create(nodes); + AnimatorControllerPropModNode.Create(nodes); } } } diff --git a/Editor/ContextExtensions.cs b/Editor/ContextExtensions.cs index cd13e3f08..014040490 100644 --- a/Editor/ContextExtensions.cs +++ b/Editor/ContextExtensions.cs @@ -44,7 +44,7 @@ public static AnimationComponentInfo GetAnimationComponent(this Bu ? currentValue : node.AsConstantValue(currentValue); - public static bool? AsConstantValue(this PropModNode>? node, bool currentValue) + public static bool? AsConstantValue(this PropModNode? node, bool currentValue) { if (node == null) return currentValue; if (node.Value.PossibleValues is { } values) diff --git a/Editor/ObjectMapping/PropertyInfo.cs b/Editor/ObjectMapping/PropertyInfo.cs index 8e9f74da3..c3d453184 100644 --- a/Editor/ObjectMapping/PropertyInfo.cs +++ b/Editor/ObjectMapping/PropertyInfo.cs @@ -9,11 +9,11 @@ namespace Anatawa12.AvatarOptimizer { internal struct PropertyInfo : IPropertyInfo { - private RootPropModNode>? _floatNode; - private RootPropModNode>? _objectNode; + private RootPropModNode? _floatNode; + private RootPropModNode? _objectNode; - public RootPropModNode>? FloatNode => _floatNode?.Normalize(); - public RootPropModNode>? ObjectNode => _objectNode?.Normalize(); + public RootPropModNode? FloatNode => _floatNode?.Normalize(); + public RootPropModNode? ObjectNode => _objectNode?.Normalize(); public void MergeTo(ref PropertyInfo property) { @@ -21,8 +21,8 @@ public void MergeTo(ref PropertyInfo property) MergeNode(ref property._objectNode, ref _objectNode); } - private static void MergeNode(ref RootPropModNode>? mergeTo, ref RootPropModNode>? merge) - where T : notnull + private static void MergeNode(ref RootPropModNode? mergeTo, ref RootPropModNode? merge) + where TValueInfo : struct, IValueInfo { if (merge == null || merge.IsEmpty) return; if (mergeTo == null || merge.IsEmpty) @@ -42,8 +42,8 @@ public void CopyTo(ref PropertyInfo property) CopyNode(ref property._objectNode, _objectNode); } - private static void CopyNode(ref RootPropModNode>? mergeTo, RootPropModNode>? merge) - where T : notnull + private static void CopyNode(ref RootPropModNode? mergeTo, RootPropModNode? merge) + where TValueInfo: struct, IValueInfo { if (merge == null || merge.IsEmpty) return; if (mergeTo == null || merge.IsEmpty) @@ -55,27 +55,27 @@ private static void CopyNode(ref RootPropModNode>? mergeTo, Root mergeTo.Add(merge); } - public void ImportProperty(RootPropModNode> node) + public void ImportProperty(RootPropModNode node) { if (FloatNode != null) throw new InvalidOperationException(); _floatNode = node; } - public void ImportProperty(RootPropModNode> node) + public void ImportProperty(RootPropModNode node) { if (ObjectNode != null) throw new InvalidOperationException(); _objectNode = node; } - public void AddModification(ComponentPropModNodeBase> node, bool alwaysApplied) + public void AddModification(ComponentPropModNodeBase node, bool alwaysApplied) { - if (_floatNode == null) _floatNode = new RootPropModNode>(); + if (_floatNode == null) _floatNode = new RootPropModNode(); _floatNode.Add(node, alwaysApplied); } - public void AddModification(ComponentPropModNodeBase> node, bool alwaysApplied) + public void AddModification(ComponentPropModNodeBase node, bool alwaysApplied) { - if (_objectNode == null) _objectNode = new RootPropModNode>(); + if (_objectNode == null) _objectNode = new RootPropModNode(); _objectNode.Add(node, alwaysApplied); } } @@ -100,7 +100,7 @@ public static bool ContainsFloat(this AnimationComponentInfo info, [JetBrains.Annotations.Pure] public static bool TryGetFloat(this AnimationComponentInfo info, string property, - [NotNullWhen(true)] out RootPropModNode>? animation) + [NotNullWhen(true)] out RootPropModNode? animation) { if (info == null) throw new ArgumentNullException(nameof(info)); animation = info.TryGetPropertyInfo(property).FloatNode; @@ -108,7 +108,7 @@ public static bool TryGetFloat(this AnimationComponentInfo info, s } public static void AddModification(this AnimationComponentInfo info, string property, - ComponentPropModNodeBase> node, bool alwaysApplied) + ComponentPropModNodeBase node, bool alwaysApplied) { if (info == null) throw new ArgumentNullException(nameof(info)); info.GetPropertyInfo(property).AddModification(node, alwaysApplied); @@ -121,7 +121,7 @@ public static bool ContainsObject(this AnimationComponentInfo info } public static bool TryGetObject(this AnimationComponentInfo info, string property, - [NotNullWhen(true)] out RootPropModNode>? animation) + [NotNullWhen(true)] out RootPropModNode? animation) { if (info == null) throw new ArgumentNullException(nameof(info)); animation = info.TryGetPropertyInfo(property).ObjectNode; @@ -129,20 +129,20 @@ public static bool TryGetObject(this AnimationComponentInfo info, } public static void AddModification(this AnimationComponentInfo info, string property, - ComponentPropModNodeBase> node, bool alwaysApplied) + ComponentPropModNodeBase node, bool alwaysApplied) { if (info == null) throw new ArgumentNullException(nameof(info)); info.GetPropertyInfo(property).AddModification(node, alwaysApplied); } - public static IEnumerable<(string, RootPropModNode>)> GetAllFloatProperties( + public static IEnumerable<(string, RootPropModNode)> GetAllFloatProperties( this AnimationComponentInfo info) { return info.GetAllPropertyInfo.Where(x => x.info.FloatNode != null) .Select(x => (x.name, x.info.FloatNode!)); } - public static IEnumerable<(string, RootPropModNode>)> GetAllObjectProperties( + public static IEnumerable<(string, RootPropModNode)> GetAllObjectProperties( this AnimationComponentInfo info) { return info.GetAllPropertyInfo.Where(x => x.info.ObjectNode != null) diff --git a/Editor/Processors/SkinnedMeshes/MergeSkinnedMeshProcessor.cs b/Editor/Processors/SkinnedMeshes/MergeSkinnedMeshProcessor.cs index c7b331d5e..0acc570fe 100644 --- a/Editor/Processors/SkinnedMeshes/MergeSkinnedMeshProcessor.cs +++ b/Editor/Processors/SkinnedMeshes/MergeSkinnedMeshProcessor.cs @@ -407,7 +407,7 @@ from meshInfo in meshInfos private static void MaterialParameterAnimationWarnings(MeshInfo2[] sourceRenderers, BuildContext context) { - var properties = new Dictionary>, MeshInfo2)>>(); + var properties = new Dictionary, MeshInfo2)>>(); var materialByMeshInfo2 = new List<(MeshInfo2 meshInfo2, List materials)>(); foreach (var meshInfo2 in sourceRenderers) { @@ -418,7 +418,7 @@ private static void MaterialParameterAnimationWarnings(MeshInfo2[] sourceRendere var materialPropertyName = name.Substring("material.".Length); if (!properties.TryGetValue(materialPropertyName, out var list)) - properties.Add(materialPropertyName, list = new List<(RootPropModNode>, MeshInfo2)>()); + properties.Add(materialPropertyName, list = new List<(RootPropModNode, MeshInfo2)>()); list.Add((property, meshInfo2)); } diff --git a/Editor/Processors/TraceAndOptimize/AutoMergeSkinnedMesh.cs b/Editor/Processors/TraceAndOptimize/AutoMergeSkinnedMesh.cs index f6ebbdd38..b1847ce2d 100644 --- a/Editor/Processors/TraceAndOptimize/AutoMergeSkinnedMesh.cs +++ b/Editor/Processors/TraceAndOptimize/AutoMergeSkinnedMesh.cs @@ -334,7 +334,7 @@ private static (Activeness, EqualsHashSet<(bool initial, EqualsHashSet !(x is AnimatorParsersV2.AnimatorPropModNode>))) + if (p.ComponentNodes.Any(x => !(x is AnimatorParsersV2.AnimatorPropModNode))) return null; locations.Add((component.enabled, new EqualsHashSet(AnimationLocation.CollectAnimationLocation(p)))); @@ -349,7 +349,7 @@ private static (Activeness, EqualsHashSet<(bool initial, EqualsHashSet x is not AnimatorParsersV2.AnimatorPropModNode>)) + if (p.ComponentNodes.Any(x => x is not AnimatorParsersV2.AnimatorPropModNode)) return null; locations.Add((transform.gameObject.activeSelf, new EqualsHashSet(AnimationLocation.CollectAnimationLocation(p)))); @@ -383,7 +383,7 @@ private static (Activeness, EqualsHashSet<(bool initial, EqualsHashSet !(x is AnimatorParsersV2.AnimatorPropModNode>))) + if (node.ComponentNodes.Any(x => !(x is AnimatorParsersV2.AnimatorPropModNode))) return null; locations.UnionWith(AnimationLocation.CollectAnimationLocation(node) .Select(location => (property, location))); diff --git a/Editor/Processors/TraceAndOptimize/OptimizeTexture.cs b/Editor/Processors/TraceAndOptimize/OptimizeTexture.cs index 1ab2581ee..aaac690cf 100644 --- a/Editor/Processors/TraceAndOptimize/OptimizeTexture.cs +++ b/Editor/Processors/TraceAndOptimize/OptimizeTexture.cs @@ -458,7 +458,7 @@ internal void RemapVertexUvs(ICollection<(EqualsHashSet, AtlasResult)> atl if (!component.TryGetObject($"m_Materials.Array.data[{materialSlotIndex}]", out var animation)) return (safeToMerge: true, Array.Empty()); - if (animation.ComponentNodes.SingleOrDefault() is AnimatorPropModNode> componentNode) + if (animation.ComponentNodes.SingleOrDefault() is AnimatorPropModNode componentNode) { if (componentNode.Value.PossibleValues is not {} possibleValues) throw new InvalidOperationException("PossibleValues is null"); diff --git a/Editor/Utils/AnimationLocation.cs b/Editor/Utils/AnimationLocation.cs index d05eadc92..01d7725dd 100644 --- a/Editor/Utils/AnimationLocation.cs +++ b/Editor/Utils/AnimationLocation.cs @@ -36,9 +36,9 @@ public AnimationLocation(Animator component, int playableLayerIndex, int animati Clip = clip; } - public static IEnumerable CollectAnimationLocation(RootPropModNode> node) + public static IEnumerable CollectAnimationLocation(RootPropModNode node) { - foreach (var animatorNode in node.ComponentNodes.OfType>>()) + foreach (var animatorNode in node.ComponentNodes.OfType>()) foreach (var playableNodeInfo in animatorNode.LayersReversed.WhileApplied()) foreach (var animatorNodeInfo in playableNodeInfo.Node.LayersReversed.WhileApplied()) foreach (var animatorStateNode in animatorNodeInfo.Node.Children) @@ -50,7 +50,7 @@ public static IEnumerable CollectAnimationLocation(RootPropMo public static IEnumerable CollectAnimationLocation(Animator animator, int playableLayer, int animatorLayer, - AnimatorState state, ImmutablePropModNode> node) + AnimatorState state, ImmutablePropModNode node) { // fast path if (node is FloatAnimationCurveNode floatNode) @@ -63,11 +63,11 @@ public static IEnumerable CollectAnimationLocation(Animator a } private static IEnumerable CollectAnimationLocationSlow(Animator animator, - int playableLayer, int animatorLayer, AnimatorState state, ImmutablePropModNode> node) + int playableLayer, int animatorLayer, AnimatorState state, ImmutablePropModNode node) { // slow path: recursively collect blend tree - var queue = new Queue<(BlendTreeNode>, int[])>(); - queue.Enqueue(((BlendTreeNode>)node, Array.Empty())); + var queue = new Queue<(BlendTreeNode, int[])>(); + queue.Enqueue(((BlendTreeNode)node, Array.Empty())); while (queue.Count != 0) { @@ -83,7 +83,7 @@ private static IEnumerable CollectAnimationLocationSlow(Anima yield return new AnimationLocation(animator, playableLayer, animatorLayer, state, newLocation, floatNode.Curve, floatNode.Clip); break; - case BlendTreeNode> childBlendTree: + case BlendTreeNode childBlendTree: queue.Enqueue((childBlendTree, newLocation)); break; default: diff --git a/Test~/AnimatorParser/TestUtil.cs b/Test~/AnimatorParser/TestUtil.cs index 65a047bd0..729362bf1 100644 --- a/Test~/AnimatorParser/TestUtil.cs +++ b/Test~/AnimatorParser/TestUtil.cs @@ -9,26 +9,26 @@ internal static class TestUtil public struct Expected { public readonly bool Always; - public readonly ValueInfo Value; + public readonly FloatValueInfo Value; - public Expected(bool always, ValueInfo value) + public Expected(bool always, FloatValueInfo value) { Always = always; Value = value; } } - public static Expected ConstantAlways(float value) => new Expected(true, new ValueInfo(value)); - public static Expected ConstantPartially(float value) => new Expected(false, new ValueInfo(value)); - public static Expected Variable(bool always = true) => new Expected(always, ValueInfo.Variable); + public static Expected ConstantAlways(float value) => new Expected(true, new FloatValueInfo(value)); + public static Expected ConstantPartially(float value) => new Expected(false, new FloatValueInfo(value)); + public static Expected Variable(bool always = true) => new Expected(always, FloatValueInfo.Variable); public static Expected MultipleAlways(params float[] values) => - new Expected(true, new ValueInfo(values)); + new Expected(true, new FloatValueInfo(values)); - public static void AssertPropertyNode(PropModNode> propertyNode, Expected property) + public static void AssertPropertyNode(PropModNode propertyNode, Expected property) { Assert.That(propertyNode.AppliedAlways, Is.EqualTo(property.Always)); Assert.That(propertyNode.Value, Is.EqualTo(property.Value)); } } -} \ No newline at end of file +} From ab13e9f82b3c7381c519eb77dfca80e9625c333e Mon Sep 17 00:00:00 2001 From: anatawa12 Date: Fri, 4 Oct 2024 17:46:12 +0900 Subject: [PATCH 05/11] chore: remove nullability from ObjectValueInfo.PossibleValues --- Editor/AnimatorParserV2/AnimatorParserDebugWindow.cs | 10 ++-------- Editor/AnimatorParserV2/PropModNode.cs | 2 +- .../SkinnedMeshes/MergeSkinnedMeshProcessor.cs | 3 +-- Editor/Processors/TraceAndOptimize/OptimizeTexture.cs | 9 +++------ 4 files changed, 7 insertions(+), 17 deletions(-) diff --git a/Editor/AnimatorParserV2/AnimatorParserDebugWindow.cs b/Editor/AnimatorParserV2/AnimatorParserDebugWindow.cs index b1da2030d..fc99d6883 100644 --- a/Editor/AnimatorParserV2/AnimatorParserDebugWindow.cs +++ b/Editor/AnimatorParserV2/AnimatorParserDebugWindow.cs @@ -72,10 +72,7 @@ private void OnGUI() if (!propState.AppliedAlways) propStateInfo += "Partial:"; - if (propState.Value.PossibleValues is { } values) - propStateInfo += $"Const:{string.Join(",", values.Select(x => x.name))}"; - else - propStateInfo += "Variable"; + propStateInfo += $"Const:{string.Join(",", propState.Value.PossibleValues.Select(x => x.name))}"; NarrowValueLabelField(propName, propStateInfo); } @@ -129,10 +126,7 @@ private string CreateText(bool detailed = false) if (!propState.AppliedAlways) propStateInfo += "Partial:"; - if (propState.Value.PossibleValues is { } values) - propStateInfo += $"Const:{string.Join(",", values.Select(x => x.name))}"; - else - propStateInfo += "Variable"; + propStateInfo += $"Const:{string.Join(",", propState.Value.PossibleValues.Select(x => x.name))}"; resultText.Append(" ").Append(propName).Append(": ").Append(propStateInfo).Append('\n'); if (detailed) diff --git a/Editor/AnimatorParserV2/PropModNode.cs b/Editor/AnimatorParserV2/PropModNode.cs index 488137e4d..152787065 100644 --- a/Editor/AnimatorParserV2/PropModNode.cs +++ b/Editor/AnimatorParserV2/PropModNode.cs @@ -138,7 +138,7 @@ public bool AlwaysAppliedForOverriding(IEnumerable layersReverse public bool IsConstant => _value.IsConstant; public Object ConstantValue => _value.ConstantValue; - public Object[]? PossibleValues => _value.PossibleValues; + public Object[] PossibleValues => _value.PossibleValues ?? throw new InvalidOperationException("Variable type is not allowed with Object"); private PropModNode> Wrap(PropModNode node) => new PropModNodeWrapper>(node, x => x._value); diff --git a/Editor/Processors/SkinnedMeshes/MergeSkinnedMeshProcessor.cs b/Editor/Processors/SkinnedMeshes/MergeSkinnedMeshProcessor.cs index 0acc570fe..8a1c88d99 100644 --- a/Editor/Processors/SkinnedMeshes/MergeSkinnedMeshProcessor.cs +++ b/Editor/Processors/SkinnedMeshes/MergeSkinnedMeshProcessor.cs @@ -426,8 +426,7 @@ private static void MaterialParameterAnimationWarnings(MeshInfo2[] sourceRendere for (var i = 0; i < meshInfo2.SubMeshes.Count; i++) { if (component.TryGetObject($"m_Materials.Array.data[{i}]", out var objectNode)) - materials.AddRange(objectNode.Value.PossibleValues?.OfType().Where(x => x) ?? - Enumerable.Empty()); + materials.AddRange(objectNode.Value.PossibleValues.OfType().Where(x => x)); if (meshInfo2.SubMeshes[i].SharedMaterial is {} newMaterial) materials.Add(newMaterial); } diff --git a/Editor/Processors/TraceAndOptimize/OptimizeTexture.cs b/Editor/Processors/TraceAndOptimize/OptimizeTexture.cs index aaac690cf..5959100d1 100644 --- a/Editor/Processors/TraceAndOptimize/OptimizeTexture.cs +++ b/Editor/Processors/TraceAndOptimize/OptimizeTexture.cs @@ -460,19 +460,16 @@ internal void RemapVertexUvs(ICollection<(EqualsHashSet, AtlasResult)> atl if (animation.ComponentNodes.SingleOrDefault() is AnimatorPropModNode componentNode) { - if (componentNode.Value.PossibleValues is not {} possibleValues) - throw new InvalidOperationException("PossibleValues is null"); + var possibleValues = componentNode.Value.PossibleValues; - if (possibleValues.All(x => x is Material)) + if (componentNode.Value.PossibleValues.All(x => x is Material)) return (safeToMerge: true, materials: possibleValues.Cast()); return (safeToMerge: false, materials: possibleValues.OfType()); } else { - if (animation.Value.PossibleValues is not { } possibleValues) - throw new InvalidOperationException("PossibleValues is null"); - + var possibleValues = animation.Value.PossibleValues; return (safeToMerge: false, materials: possibleValues.OfType()); } } From a37d4d72df5e97601b256a588b399e639b804556 Mon Sep 17 00:00:00 2001 From: anatawa12 Date: Fri, 4 Oct 2024 17:54:59 +0900 Subject: [PATCH 06/11] chore: implement FloatValueInfo individually --- Editor/AnimatorParserV2/PropModNode.cs | 119 +++++++++++++++++++++---- 1 file changed, 101 insertions(+), 18 deletions(-) diff --git a/Editor/AnimatorParserV2/PropModNode.cs b/Editor/AnimatorParserV2/PropModNode.cs index 152787065..7b3e8f3c7 100644 --- a/Editor/AnimatorParserV2/PropModNode.cs +++ b/Editor/AnimatorParserV2/PropModNode.cs @@ -96,35 +96,118 @@ public LayerWrapper(ILayer innerLayer, Func { - private readonly ValueInfo _value; + public bool IsConstant => _possibleValues is { Length: 1 }; + private readonly float[]? _possibleValues; - public FloatValueInfo(float value) => this = new FloatValueInfo(new ValueInfo(value)); - public FloatValueInfo(float[] values) => this = new FloatValueInfo(new ValueInfo(values)); - private FloatValueInfo(ValueInfo value) => _value = value; + public FloatValueInfo(float value) => _possibleValues = new[] { value }; + public FloatValueInfo(float[] values) => _possibleValues = values; - public bool IsConstant => _value.IsConstant; - public float ConstantValue => _value.ConstantValue; - public float[]? PossibleValues => _value.PossibleValues; - public static FloatValueInfo Variable => new(ValueInfo.Variable); + public float ConstantValue + { + get + { + if (!IsConstant) throw new InvalidOperationException("Not Constant"); + return _possibleValues![0]; // non constant => there is value + } + } - private PropModNode> Wrap(PropModNode node) => - new PropModNodeWrapper>(node, x => x._value); - private LayerWrapper> Wrap(TLayer layer) where TLayer : ILayer => - new(layer, x => x._value); + public float[]? PossibleValues => _possibleValues; + public static FloatValueInfo Variable => default; + + public bool TryGetConstantValue(out float o) { + if (IsConstant) + { + o = ConstantValue; + return true; + } + else + { + o = default; + return false; + } + } - public bool TryGetConstantValue(out float o) => _value.TryGetConstantValue(out o); + public FloatValueInfo ConstantInfoForSideBySide(IEnumerable> nodes) + { + using var enumerator = nodes.GetEnumerator(); + Debug.Assert(enumerator.MoveNext()); - public FloatValueInfo ConstantInfoForSideBySide(IEnumerable> nodes) => - new(_value.ConstantInfoForSideBySide(nodes.Select(Wrap))); + if (enumerator.Current!.Value.PossibleValues is not { } possibleValues) + return Variable; + + var allPossibleValues = new HashSet(possibleValues); + + while (enumerator.MoveNext()) + { + if (enumerator.Current.Value.PossibleValues is not { } otherValues) + return Variable; + + allPossibleValues.UnionWith(otherValues); + } + + return new FloatValueInfo(allPossibleValues.ToArray()); + } public FloatValueInfo ConstantInfoForBlendTree(IEnumerable> nodes, - BlendTreeType blendTreeType) => new(_value.ConstantInfoForBlendTree(nodes.Select(Wrap), blendTreeType)); + BlendTreeType blendTreeType) => + blendTreeType == BlendTreeType.Direct ? Variable : ConstantInfoForSideBySide(nodes); public FloatValueInfo ConstantInfoForOverriding(IEnumerable layersReversed) - where TLayer : ILayer => new(_value.ConstantInfoForOverriding(layersReversed.Select(Wrap))); + where TLayer : ILayer + { + var allPossibleValues = new HashSet(); + + foreach (var layer in layersReversed) + { + switch (layer.Weight) + { + case AnimatorWeightState.AlwaysOne: + case AnimatorWeightState.EitherZeroOrOne: + { + if (layer.Node.Value.PossibleValues is not { } otherValues) return Variable; + + switch (layer.BlendingMode) + { + case AnimatorLayerBlendingMode.Additive: + // ObjectReference will work as override even with additive mode. + // additive with changing value: value cannot be determined + if (otherValues.Length != 1) return Variable; + break; + case AnimatorLayerBlendingMode.Override: + allPossibleValues.UnionWith(otherValues); + + if (layer.IsAlwaysOverride()) + { + // the layer is always applied at the highest property. + return new FloatValueInfo(allPossibleValues.ToArray()); + } + + break; + default: + throw new ArgumentOutOfRangeException(); + } + } + break; + case AnimatorWeightState.Variable: + { + return Variable; // float: variable + } + break; + default: + throw new ArgumentOutOfRangeException(); + } + } + + return new FloatValueInfo(allPossibleValues.ToArray()); + } public bool AlwaysAppliedForOverriding(IEnumerable layersReversed) - where TLayer : ILayer => _value.AlwaysAppliedForOverriding(layersReversed.Select(Wrap)); + where TLayer : ILayer + { + return layersReversed.Any(x => + x.Weight == AnimatorWeightState.AlwaysOne && x.BlendingMode == AnimatorLayerBlendingMode.Override && + x.Node.AppliedAlways); + } } From 727bc18790cf3dc4abfac971bc8586b070fea296 Mon Sep 17 00:00:00 2001 From: anatawa12 Date: Fri, 4 Oct 2024 18:28:22 +0900 Subject: [PATCH 07/11] chore: implement ObjectValueInfo individually --- Editor/AnimatorParserV2/PropModNode.cs | 86 +++++++++++++++++++++----- 1 file changed, 69 insertions(+), 17 deletions(-) diff --git a/Editor/AnimatorParserV2/PropModNode.cs b/Editor/AnimatorParserV2/PropModNode.cs index 7b3e8f3c7..033cad8d0 100644 --- a/Editor/AnimatorParserV2/PropModNode.cs +++ b/Editor/AnimatorParserV2/PropModNode.cs @@ -210,35 +210,87 @@ public bool AlwaysAppliedForOverriding(IEnumerable layersReverse } } - + // note: no default is allowed internal readonly struct ObjectValueInfo : IValueInfo { - private readonly ValueInfo _value; + private readonly Object[] _possibleValues; + + public ObjectValueInfo(Object value) => _possibleValues = new[] { value }; + public ObjectValueInfo(Object[] values) => _possibleValues = values; + + public bool IsConstant => _possibleValues is { Length: 1 }; - public ObjectValueInfo(Object value) => this = new ObjectValueInfo(new ValueInfo(value)); - public ObjectValueInfo(Object[] values) => this = new ObjectValueInfo(new ValueInfo(values)); - private ObjectValueInfo(ValueInfo value) => _value = value; + public Object[] PossibleValues => + _possibleValues ?? throw new InvalidOperationException("default is not allowd"); - public bool IsConstant => _value.IsConstant; - public Object ConstantValue => _value.ConstantValue; - public Object[] PossibleValues => _value.PossibleValues ?? throw new InvalidOperationException("Variable type is not allowed with Object"); + public ObjectValueInfo ConstantInfoForSideBySide(IEnumerable> nodes) + { + using var enumerator = nodes.GetEnumerator(); + Debug.Assert(enumerator.MoveNext()); - private PropModNode> Wrap(PropModNode node) => - new PropModNodeWrapper>(node, x => x._value); - private LayerWrapper> Wrap(TLayer layer) where TLayer : ILayer => - new(layer, x => x._value); + var possibleValues = enumerator.Current.Value.PossibleValues; - public ObjectValueInfo ConstantInfoForSideBySide(IEnumerable> nodes) => - new(_value.ConstantInfoForSideBySide(nodes.Select(Wrap))); + var allPossibleValues = new HashSet(possibleValues); + + while (enumerator.MoveNext()) + { + allPossibleValues.UnionWith(enumerator.Current.Value.PossibleValues); + } + + return new ObjectValueInfo(allPossibleValues.ToArray()); + } public ObjectValueInfo ConstantInfoForBlendTree(IEnumerable> nodes, - BlendTreeType blendTreeType) => new(_value.ConstantInfoForBlendTree(nodes.Select(Wrap), blendTreeType)); + BlendTreeType blendTreeType) => ConstantInfoForSideBySide(nodes); public ObjectValueInfo ConstantInfoForOverriding(IEnumerable layersReversed) - where TLayer : ILayer => new(_value.ConstantInfoForOverriding(layersReversed.Select(Wrap))); + where TLayer : ILayer + { + var allPossibleValues = new HashSet(); + + foreach (var layer in layersReversed) + { + switch (layer.Weight) + { + case AnimatorWeightState.AlwaysOne: + case AnimatorWeightState.EitherZeroOrOne: + { + var otherValues = layer.Node.Value.PossibleValues; + + switch (layer.BlendingMode) + { + case AnimatorLayerBlendingMode.Additive: + case AnimatorLayerBlendingMode.Override: + allPossibleValues.UnionWith(otherValues); + + if (layer.IsAlwaysOverride()) + { + // the layer is always applied at the highest property. + return new ObjectValueInfo(allPossibleValues.ToArray()); + } + + break; + default: + throw new ArgumentOutOfRangeException(); + } + } + break; + case AnimatorWeightState.Variable: + allPossibleValues.UnionWith(layer.Node.Value.PossibleValues); + break; + default: + throw new ArgumentOutOfRangeException(); + } + } + + return new ObjectValueInfo(allPossibleValues.ToArray()); + } public bool AlwaysAppliedForOverriding(IEnumerable layersReversed) - where TLayer : ILayer => _value.AlwaysAppliedForOverriding(layersReversed.Select(Wrap)); + where TLayer : ILayer => + layersReversed.Any(x => + x.Weight == AnimatorWeightState.AlwaysOne && x.BlendingMode == AnimatorLayerBlendingMode.Override && + x.Node.AppliedAlways); } /// /// The abstract information about actual value of PropModNode. From 69bdb21cada2595be48f4a6f885cab6f45b8ecf9 Mon Sep 17 00:00:00 2001 From: anatawa12 Date: Fri, 4 Oct 2024 18:49:14 +0900 Subject: [PATCH 08/11] chore: remove unused code --- .../AnimatorControllerPropModNode.cs | 4 +- Editor/AnimatorParserV2/PropModNode.cs | 228 +----------------- 2 files changed, 5 insertions(+), 227 deletions(-) diff --git a/Editor/AnimatorParserV2/AnimatorControllerPropModNode.cs b/Editor/AnimatorParserV2/AnimatorControllerPropModNode.cs index de410e149..58e89b4ac 100644 --- a/Editor/AnimatorParserV2/AnimatorControllerPropModNode.cs +++ b/Editor/AnimatorParserV2/AnimatorControllerPropModNode.cs @@ -56,7 +56,7 @@ public AnimatorPropModNode(Animator component,IEnumerable( - () => default(TValueInfo).AlwaysAppliedForOverriding(_layersReversed), + () => NodeImplUtils.AlwaysAppliedForOverriding(_layersReversed), isThreadSafe: false); _constantInfo = new Lazy( @@ -118,7 +118,7 @@ private AnimatorControllerPropModNode(IEnumerable default(TValueInfo).ConstantInfoForOverriding(_layersReversed); // we may possible to implement complex logic which simulates state machine but not for now. - public override bool AppliedAlways => default(TValueInfo).AlwaysAppliedForOverriding(_layersReversed); + public override bool AppliedAlways => NodeImplUtils.AlwaysAppliedForOverriding(_layersReversed); public override IEnumerable ContextReferences => _layersReversed.SelectMany(x => x.Node.ContextReferences); diff --git a/Editor/AnimatorParserV2/PropModNode.cs b/Editor/AnimatorParserV2/PropModNode.cs index 033cad8d0..f35c57153 100644 --- a/Editor/AnimatorParserV2/PropModNode.cs +++ b/Editor/AnimatorParserV2/PropModNode.cs @@ -1,6 +1,5 @@ using System; using System.Collections.Generic; -using System.Diagnostics.CodeAnalysis; using System.Linq; using nadena.dev.ndmf; using UnityEditor; @@ -29,9 +28,6 @@ interface IValueInfo TValueInfo ConstantInfoForOverriding(IEnumerable layersReversed) where TLayer : ILayer; - - bool AlwaysAppliedForOverriding(IEnumerable layersReversed) - where TLayer : ILayer; } /// @@ -56,44 +52,6 @@ internal abstract class PropModNode : IErrorContext, IPropModNode public abstract IEnumerable ContextReferences { get; } } - class PropModNodeWrapper : PropModNode - where TValueInfoOut: struct, IValueInfo - where TValueInfoInner: struct, IValueInfo - { - private PropModNode _innerNode; - private Func _converter; - - public PropModNodeWrapper(PropModNode innerNode, Func converter) - { - _innerNode = innerNode; - _converter = converter; - } - - public override bool AppliedAlways => _innerNode.AppliedAlways; - public override TValueInfoOut Value => _converter(_innerNode.Value); - public override IEnumerable ContextReferences => _innerNode.ContextReferences; - } - - struct LayerWrapper : ILayer - where TValueInfoOut : struct, IValueInfo - where TValueInfoInner : struct, IValueInfo - { - private ILayer _innerLayer; - private Func _converter; - - public LayerWrapper(ILayer innerLayer, Func converter) - { - _innerLayer = innerLayer; - _converter = converter; - } - - public AnimatorWeightState Weight => _innerLayer.Weight; - public AnimatorLayerBlendingMode BlendingMode => _innerLayer.BlendingMode; - IPropModNode ILayer.Node => Node; - - public PropModNode Node => new PropModNodeWrapper(_innerLayer.Node, _converter); - } - internal readonly struct FloatValueInfo : IValueInfo { public bool IsConstant => _possibleValues is { Length: 1 }; @@ -200,14 +158,6 @@ public FloatValueInfo ConstantInfoForOverriding(IEnumerable laye return new FloatValueInfo(allPossibleValues.ToArray()); } - - public bool AlwaysAppliedForOverriding(IEnumerable layersReversed) - where TLayer : ILayer - { - return layersReversed.Any(x => - x.Weight == AnimatorWeightState.AlwaysOne && x.BlendingMode == AnimatorLayerBlendingMode.Override && - x.Node.AppliedAlways); - } } // note: no default is allowed @@ -220,8 +170,7 @@ public bool AlwaysAppliedForOverriding(IEnumerable layersReverse public bool IsConstant => _possibleValues is { Length: 1 }; - public Object[] PossibleValues => - _possibleValues ?? throw new InvalidOperationException("default is not allowd"); + public Object[] PossibleValues => _possibleValues ?? Array.Empty(); public ObjectValueInfo ConstantInfoForSideBySide(IEnumerable> nodes) { @@ -285,97 +234,6 @@ public ObjectValueInfo ConstantInfoForOverriding(IEnumerable lay return new ObjectValueInfo(allPossibleValues.ToArray()); } - - public bool AlwaysAppliedForOverriding(IEnumerable layersReversed) - where TLayer : ILayer => - layersReversed.Any(x => - x.Weight == AnimatorWeightState.AlwaysOne && x.BlendingMode == AnimatorLayerBlendingMode.Override && - x.Node.AppliedAlways); - } - /// - /// The abstract information about actual value of PropModNode. - /// - // by design, this struct doesn't handle blending between two states. - internal readonly struct ValueInfo : IValueInfo> - where T : notnull - { - public bool IsConstant => _possibleValues != null && _possibleValues.Length == 1; - private readonly T[]? _possibleValues; - - public T ConstantValue - { - get - { - if (!IsConstant) throw new InvalidOperationException("Not Constant"); - return _possibleValues![0]; // non constant => there is value - } - } - - public T[]? PossibleValues => _possibleValues; - - public static ValueInfo Variable - { - get - { - if (default(T) == null) throw new InvalidOperationException("Variable type is not allowed with Object"); - return default; - } - } - - public ValueInfo(T value) => _possibleValues = new[] { value }; - - public ValueInfo(T[] possibleValues) - { - if (possibleValues == null) throw new ArgumentNullException(nameof(possibleValues)); - if (possibleValues.Length == 0) - throw new ArgumentException("Value cannot be an empty array.", nameof(possibleValues)); - if (possibleValues.Distinct().Count() != possibleValues.Length) - throw new ArgumentException("Value cannot contain duplicate values.", nameof(possibleValues)); - _possibleValues = possibleValues; - } - - public bool TryGetConstantValue([NotNullWhen(true)] out T? o) - { - if (IsConstant) - { - o = ConstantValue; - return true; - } - else - { - o = default; - return false; - } - } - - public bool Equals(ValueInfo other) - { - return NodeImplUtils.SetEquals(_possibleValues, other._possibleValues); - } - - public ValueInfo ConstantInfoForSideBySide(IEnumerable>> nodes) => - NodeImplUtils.ConstantInfoForSideBySide(nodes); - - public ValueInfo ConstantInfoForBlendTree(IEnumerable>> nodes, BlendTreeType blendTreeType) - { - if (default(T) == null) return ConstantInfoForSideBySide(nodes); - return blendTreeType == BlendTreeType.Direct ? Variable : ConstantInfoForSideBySide(nodes); - } - - public ValueInfo ConstantInfoForOverriding(IEnumerable layersReversed) - where TLayer : ILayer> => NodeImplUtils.ConstantInfoForOverriding(layersReversed); - - public bool AlwaysAppliedForOverriding(IEnumerable layersReversed) - where TLayer : ILayer> => NodeImplUtils.AlwaysAppliedForOverriding(layersReversed); - - public override bool Equals(object obj) => obj is ValueInfo other && Equals(other); - - public override int GetHashCode() => _possibleValues == null ? 0 : _possibleValues.GetSetHashCode(); - - public override string ToString() => - _possibleValues == null - ? $"ValueInfo<{typeof(T).Name}>{{Variable}}" - : $"ValueInfo<{typeof(T).Name}>{{PossibleValues={string.Join(",", _possibleValues)}}}"; } internal static class NodeImplUtils @@ -388,94 +246,14 @@ public static bool SetEquals(T[]? a, T[]? b) return new HashSet(a).SetEquals(b); } - public static ValueInfo ConstantInfoForSideBySide(IEnumerable>> nodes) where T : notnull - { - using (var enumerator = nodes.GetEnumerator()) - { - Debug.Assert(enumerator.MoveNext()); - - if (!(enumerator.Current.Value.PossibleValues is T[] possibleValues)) - return ValueInfo.Variable; - - var allPossibleValues = new HashSet(possibleValues); - - while (enumerator.MoveNext()) - { - if (!(enumerator.Current.Value.PossibleValues is T[] otherValues)) - return ValueInfo.Variable; - - allPossibleValues.UnionWith(otherValues); - } - - return new ValueInfo(allPossibleValues.ToArray()); - } - } - - public static bool AlwaysAppliedForOverriding(IEnumerable layersReversed) - where T : notnull - where TLayer : ILayer> + public static bool AlwaysAppliedForOverriding(IEnumerable layersReversed) + where TLayer : ILayer { return layersReversed.Any(x => x.Weight == AnimatorWeightState.AlwaysOne && x.BlendingMode == AnimatorLayerBlendingMode.Override && x.Node.AppliedAlways); } - public static ValueInfo ConstantInfoForOverriding(IEnumerable layersReversed) - where T : notnull - where TLayer : ILayer> - { - var canAdditive = default(T) != null; - var allPossibleValues = new HashSet(); - - foreach (var layer in layersReversed) - { - switch (layer.Weight) - { - case AnimatorWeightState.AlwaysOne: - case AnimatorWeightState.EitherZeroOrOne: - { - if (!(layer.Node.Value.PossibleValues is T[] otherValues)) return ValueInfo.Variable; - - switch (layer.BlendingMode) - { - case AnimatorLayerBlendingMode.Additive: - // ObjectReference will work as override even with additive mode. - if (!canAdditive) goto case AnimatorLayerBlendingMode.Override; - - // additive with changing value: value cannot be determined - if (otherValues.Length != 1) return ValueInfo.Variable; - break; - case AnimatorLayerBlendingMode.Override: - allPossibleValues.UnionWith(otherValues); - - if (layer.IsAlwaysOverride()) - { - // the layer is always applied at the highest property. - return new ValueInfo(allPossibleValues.ToArray()); - } - - break; - default: - throw new ArgumentOutOfRangeException(); - } - } - break; - case AnimatorWeightState.Variable: - { - if (default(T) != null) return ValueInfo.Variable; // float: variable - if (!(layer.Node.Value.PossibleValues is T[] otherValues)) - throw new InvalidOperationException(); - allPossibleValues.UnionWith(otherValues); - } - break; - default: - throw new ArgumentOutOfRangeException(); - } - } - - return new ValueInfo(allPossibleValues.ToArray()); - } - public static bool IsAlwaysOverride(this TLayer layer) where TLayer : ILayer { From 59d8194cec637a6fe89f54e9a3c09773a9b247dd Mon Sep 17 00:00:00 2001 From: anatawa12 Date: Fri, 4 Oct 2024 18:49:29 +0900 Subject: [PATCH 09/11] chore: implement equals in ***ValueInfo --- Editor/AnimatorParserV2/PropModNode.cs | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/Editor/AnimatorParserV2/PropModNode.cs b/Editor/AnimatorParserV2/PropModNode.cs index f35c57153..2152d6140 100644 --- a/Editor/AnimatorParserV2/PropModNode.cs +++ b/Editor/AnimatorParserV2/PropModNode.cs @@ -52,7 +52,7 @@ internal abstract class PropModNode : IErrorContext, IPropModNode public abstract IEnumerable ContextReferences { get; } } - internal readonly struct FloatValueInfo : IValueInfo + internal readonly struct FloatValueInfo : IValueInfo, IEquatable { public bool IsConstant => _possibleValues is { Length: 1 }; private readonly float[]? _possibleValues; @@ -60,7 +60,7 @@ internal abstract class PropModNode : IErrorContext, IPropModNode public FloatValueInfo(float value) => _possibleValues = new[] { value }; public FloatValueInfo(float[] values) => _possibleValues = values; - public float ConstantValue + public float ConstantValue { get { @@ -72,7 +72,8 @@ public float ConstantValue public float[]? PossibleValues => _possibleValues; public static FloatValueInfo Variable => default; - public bool TryGetConstantValue(out float o) { + public bool TryGetConstantValue(out float o) + { if (IsConstant) { o = ConstantValue; @@ -158,10 +159,16 @@ public FloatValueInfo ConstantInfoForOverriding(IEnumerable laye return new FloatValueInfo(allPossibleValues.ToArray()); } + + public bool Equals(FloatValueInfo other) => NodeImplUtils.SetEquals(_possibleValues, other._possibleValues); + public override bool Equals(object? obj) => obj is FloatValueInfo other && Equals(other); + public override int GetHashCode() => _possibleValues != null ? _possibleValues.GetSetHashCode() : 0; + public static bool operator ==(FloatValueInfo left, FloatValueInfo right) => left.Equals(right); + public static bool operator !=(FloatValueInfo left, FloatValueInfo right) => !left.Equals(right); } // note: no default is allowed - internal readonly struct ObjectValueInfo : IValueInfo + internal readonly struct ObjectValueInfo : IValueInfo, IEquatable { private readonly Object[] _possibleValues; @@ -234,6 +241,12 @@ public ObjectValueInfo ConstantInfoForOverriding(IEnumerable lay return new ObjectValueInfo(allPossibleValues.ToArray()); } + + public bool Equals(ObjectValueInfo other) => NodeImplUtils.SetEquals(PossibleValues, PossibleValues); + public override bool Equals(object? obj) => obj is ObjectValueInfo other && Equals(other); + public override int GetHashCode() => _possibleValues.GetHashCode(); + public static bool operator ==(ObjectValueInfo left, ObjectValueInfo right) => left.Equals(right); + public static bool operator !=(ObjectValueInfo left, ObjectValueInfo right) => !left.Equals(right); } internal static class NodeImplUtils From d3d0f42e4fc7ae9324de3ac8943795acf92fe2e9 Mon Sep 17 00:00:00 2001 From: anatawa12 Date: Fri, 4 Oct 2024 18:58:05 +0900 Subject: [PATCH 10/11] refactor: simplify and add comments --- Editor/AnimatorParserV2/PropModNode.cs | 87 ++++---------------------- 1 file changed, 13 insertions(+), 74 deletions(-) diff --git a/Editor/AnimatorParserV2/PropModNode.cs b/Editor/AnimatorParserV2/PropModNode.cs index 2152d6140..5b01a604c 100644 --- a/Editor/AnimatorParserV2/PropModNode.cs +++ b/Editor/AnimatorParserV2/PropModNode.cs @@ -88,22 +88,12 @@ public bool TryGetConstantValue(out float o) public FloatValueInfo ConstantInfoForSideBySide(IEnumerable> nodes) { - using var enumerator = nodes.GetEnumerator(); - Debug.Assert(enumerator.MoveNext()); - - if (enumerator.Current!.Value.PossibleValues is not { } possibleValues) - return Variable; - - var allPossibleValues = new HashSet(possibleValues); - - while (enumerator.MoveNext()) + var allPossibleValues = new HashSet(); + foreach (var propModNode in nodes) { - if (enumerator.Current.Value.PossibleValues is not { } otherValues) - return Variable; - - allPossibleValues.UnionWith(otherValues); + if (propModNode.Value.PossibleValues is not { } values) return Variable; + allPossibleValues.UnionWith(values); } - return new FloatValueInfo(allPossibleValues.ToArray()); } @@ -128,8 +118,11 @@ public FloatValueInfo ConstantInfoForOverriding(IEnumerable laye switch (layer.BlendingMode) { case AnimatorLayerBlendingMode.Additive: - // ObjectReference will work as override even with additive mode. - // additive with changing value: value cannot be determined + // having multiple possible value means animated, and this means variable. + // if only one value is exists with additive layer, noting is added so skip this layer. + // for additive reference pose, length of otherValues will be two or more with + // reference post value. + // see implementation of FloatAnimationCurveNode.ParseProperty if (otherValues.Length != 1) return Variable; break; case AnimatorLayerBlendingMode.Override: @@ -148,10 +141,7 @@ public FloatValueInfo ConstantInfoForOverriding(IEnumerable laye } break; case AnimatorWeightState.Variable: - { - return Variable; // float: variable - } - break; + return Variable; default: throw new ArgumentOutOfRangeException(); } @@ -179,22 +169,8 @@ public FloatValueInfo ConstantInfoForOverriding(IEnumerable laye public Object[] PossibleValues => _possibleValues ?? Array.Empty(); - public ObjectValueInfo ConstantInfoForSideBySide(IEnumerable> nodes) - { - using var enumerator = nodes.GetEnumerator(); - Debug.Assert(enumerator.MoveNext()); - - var possibleValues = enumerator.Current.Value.PossibleValues; - - var allPossibleValues = new HashSet(possibleValues); - - while (enumerator.MoveNext()) - { - allPossibleValues.UnionWith(enumerator.Current.Value.PossibleValues); - } - - return new ObjectValueInfo(allPossibleValues.ToArray()); - } + public ObjectValueInfo ConstantInfoForSideBySide(IEnumerable> nodes) => + new(nodes.SelectMany(node => node.Value.PossibleValues).Distinct().ToArray()); public ObjectValueInfo ConstantInfoForBlendTree(IEnumerable> nodes, BlendTreeType blendTreeType) => ConstantInfoForSideBySide(nodes); @@ -202,44 +178,7 @@ public ObjectValueInfo ConstantInfoForBlendTree(IEnumerable(IEnumerable layersReversed) where TLayer : ILayer { - var allPossibleValues = new HashSet(); - - foreach (var layer in layersReversed) - { - switch (layer.Weight) - { - case AnimatorWeightState.AlwaysOne: - case AnimatorWeightState.EitherZeroOrOne: - { - var otherValues = layer.Node.Value.PossibleValues; - - switch (layer.BlendingMode) - { - case AnimatorLayerBlendingMode.Additive: - case AnimatorLayerBlendingMode.Override: - allPossibleValues.UnionWith(otherValues); - - if (layer.IsAlwaysOverride()) - { - // the layer is always applied at the highest property. - return new ObjectValueInfo(allPossibleValues.ToArray()); - } - - break; - default: - throw new ArgumentOutOfRangeException(); - } - } - break; - case AnimatorWeightState.Variable: - allPossibleValues.UnionWith(layer.Node.Value.PossibleValues); - break; - default: - throw new ArgumentOutOfRangeException(); - } - } - - return new ObjectValueInfo(allPossibleValues.ToArray()); + return new ObjectValueInfo(layersReversed.WhileApplied().SelectMany(layer => layer.Node.Value.PossibleValues).Distinct().ToArray()); } public bool Equals(ObjectValueInfo other) => NodeImplUtils.SetEquals(PossibleValues, PossibleValues); From c3d90406ab3e251bd84e4d07cd7db770335c3e72 Mon Sep 17 00:00:00 2001 From: anatawa12 Date: Sat, 5 Oct 2024 14:05:27 +0900 Subject: [PATCH 11/11] docs(changelog): Reimplemented Animator Parser node system --- CHANGELOG-PRERELEASE.md | 1 + CHANGELOG.md | 1 + 2 files changed, 2 insertions(+) diff --git a/CHANGELOG-PRERELEASE.md b/CHANGELOG-PRERELEASE.md index 009d3ba5d..21d584f3d 100644 --- a/CHANGELOG-PRERELEASE.md +++ b/CHANGELOG-PRERELEASE.md @@ -11,6 +11,7 @@ The format is based on [Keep a Changelog]. ### Changed - Animator Parser Debug Window now supports ObjectReference animation support `#1222` +- Reimplemented Animator Parser node system `#1227` ### Deprecated diff --git a/CHANGELOG.md b/CHANGELOG.md index 20509c2a8..b68410b1a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -51,6 +51,7 @@ The format is based on [Keep a Changelog]. - Allow multiple component for Remove Mesh components with API `#1216` `#1218` - This allows non-destructive tools to add Remove Mesh components even if Remove Mesh component are added before. - Animator Parser Debug Window now supports ObjectReference animation support `#1222` +- Reimplemented Animator Parser node system `#1227` ### Deprecated