From d22d73cc8244eb62456f7a85ebc618dc4e972351 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ha=C3=AF=7E?= Date: Sun, 3 Sep 2023 16:23:24 +0200 Subject: [PATCH] =?UTF-8?q?(BREAKING)=20Add=20AnimatorAsCode=20V1:=20-=20B?= =?UTF-8?q?reaking=20changes:=20=C2=A0=20-=20Remove=20dependency=20to=20VR?= =?UTF-8?q?Chat=20in=20the=20AnimatorAsCode.V1=20namespace.=20The=20namesp?= =?UTF-8?q?ace=20should=20now=20be=20usable=20in=20non-VRChat=20projects.?= =?UTF-8?q?=20=C2=A0=20-=20All=20VRChat-specific=20methods=20are=20now=20e?= =?UTF-8?q?xtension=20functions=20in=20a=20separate=20namespace,=20Animato?= =?UTF-8?q?rAsCode.V1.VRC.=20=C2=A0=20-=20VRChat=20methods=20that=20modify?= =?UTF-8?q?=20existing=20assets=20are=20split=20into=20a=20separate=20name?= =?UTF-8?q?space,=20AnimatorAsCode.V1.VRCDestructiveWorkflow.=20-=20Breaki?= =?UTF-8?q?ng=20fixes:=20=C2=A0=20-=20Fix=20incorrect=20type=20signature?= =?UTF-8?q?=20on=20AacFlFloatParameterGroup.ToList()=20and=20AacFlIntParam?= =?UTF-8?q?eterGroup.ToList().=20-=20Add=20AacFlBase.NewBlendTree():=20?= =?UTF-8?q?=C2=A0=20-=20This=20allows=20creating=20blend=20trees=20as=20co?= =?UTF-8?q?de.=20=C2=A0=20-=20Add=20AacFlState.WithAnimation(AacFlBlendTre?= =?UTF-8?q?e).=20-=20Add=20AacFlBase.NoAnimator():=20=C2=A0=20-=20This=20c?= =?UTF-8?q?an=20be=20used=20to=20obtain=20AacFlParameter=20objects=20for?= =?UTF-8?q?=20use=20in=20the=20generation=20of=20BlendTrees=20and=20other?= =?UTF-8?q?=20systems,=20without=20requiring=20the=20existence=20of=20a=20?= =?UTF-8?q?backing=20animator=20controller.=20=C2=A0=20-=20This=20can=20al?= =?UTF-8?q?so=20be=20used=20in=20some=20cases=20where=20there=20are=20type?= =?UTF-8?q?=20casts=20(Bool=20to=20Float,=20Float=20to=20Bool).=20-=20Add?= =?UTF-8?q?=20AacFlBase.NewAnimatorController():=20=C2=A0=20-=20This=20is?= =?UTF-8?q?=20meant=20to=20be=20used=20for=20non-destructive=20workflows.?= =?UTF-8?q?=20=C2=A0=20-=20This=20creates=20an=20animator=20controller=20i?= =?UTF-8?q?nside=20the=20asset=20container.=20This=20animator=20controller?= =?UTF-8?q?=20will=20be=20reaped=20in=20the=20same=20way=20as=20other=20as?= =?UTF-8?q?sets=20are=20reaped.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Framework/Editor/V1/Aac.cs | 351 ++++++++++++------ Framework/Editor/V1/AacFlConditions.cs | 4 +- Framework/Editor/V1/AacFlStates.cs | 10 +- ...RChatExtensions.cs => AacVRCExtensions.cs} | 161 +++++++- ...sions.cs.meta => AacVRCExtensions.cs.meta} | 0 Framework/Editor/V1VRC/TrackingElement.cs | 17 - .../Editor/V1VRC/TrackingElement.cs.meta | 11 - MigratingFromV0ToV1.md | 63 ++++ MigratingFromV0ToV1.md.meta | 3 + .../AIACVRCExtensionsMiscGenerationTest.cs | 32 +- 10 files changed, 483 insertions(+), 169 deletions(-) rename Framework/Editor/V1VRC/{VRChatExtensions.cs => AacVRCExtensions.cs} (69%) rename Framework/Editor/V1VRC/{VRChatExtensions.cs.meta => AacVRCExtensions.cs.meta} (100%) delete mode 100644 Framework/Editor/V1VRC/TrackingElement.cs delete mode 100644 Framework/Editor/V1VRC/TrackingElement.cs.meta create mode 100644 MigratingFromV0ToV1.md create mode 100644 MigratingFromV0ToV1.md.meta diff --git a/Framework/Editor/V1/Aac.cs b/Framework/Editor/V1/Aac.cs index c70f13b..8ade46a 100644 --- a/Framework/Editor/V1/Aac.cs +++ b/Framework/Editor/V1/Aac.cs @@ -16,6 +16,19 @@ namespace AnimatorAsCode.V1 return new AacFlBase(configuration); } + internal static AnimatorController NewAnimatorController(AacConfiguration component, string suffix) + { + return RegisterAnimatorController(component, suffix, new AnimatorController()); + } + + internal static AnimatorController RegisterAnimatorController(AacConfiguration component, string suffix, AnimatorController animatorController) + { + animatorController.name = "zAutogenerated__" + component.AssetKey + "__" + suffix + "_" + Random.Range(0, Int32.MaxValue); // FIXME animation name conflict + animatorController.hideFlags = HideFlags.None; + AssetDatabase.AddObjectToAsset(animatorController, component.AssetContainer); + return animatorController; + } + internal static AnimationClip NewClip(AacConfiguration component, string suffix) { return RegisterClip(component, suffix, new AnimationClip()); @@ -77,6 +90,8 @@ namespace AnimatorAsCode.V1 public struct AacConfiguration { public string SystemName; + // Please consult "MigratingFromV0ToV1.md" on how to migrate this property + // public VRCAvatarDescriptor AvatarDescriptor; public Transform AnimatorRoot; public Transform DefaultValueRoot; public AnimatorController AssetContainer; @@ -157,19 +172,18 @@ namespace AnimatorAsCode.V1 return _stateMachine.EntryTransitionsTo(destination); } - public AacFlBoolParameter BoolParameter(string parameterName) => _stateMachine.BackingAnimator().BoolParameter(parameterName); - public AacFlBoolParameter TriggerParameterAsBool(string parameterName) => _stateMachine.BackingAnimator().TriggerParameter(parameterName); - public AacFlFloatParameter FloatParameter(string parameterName) => _stateMachine.BackingAnimator().FloatParameter(parameterName); - public AacFlIntParameter IntParameter(string parameterName) => _stateMachine.BackingAnimator().IntParameter(parameterName); - public AacFlBoolParameterGroup BoolParameters(params string[] parameterNames) => _stateMachine.BackingAnimator().BoolParameters(parameterNames); - public AacFlBoolParameterGroup TriggerParametersAsBools(params string[] parameterNames) => _stateMachine.BackingAnimator().TriggerParameters(parameterNames); - public AacFlFloatParameterGroup FloatParameters(params string[] parameterNames) => _stateMachine.BackingAnimator().FloatParameters(parameterNames); - public AacFlIntParameterGroup IntParameters(params string[] parameterNames) => _stateMachine.BackingAnimator().IntParameters(parameterNames); - public AacFlBoolParameterGroup BoolParameters(params AacFlBoolParameter[] parameters) => _stateMachine.BackingAnimator().BoolParameters(parameters); - public AacFlBoolParameterGroup TriggerParametersAsBools(params AacFlBoolParameter[] parameters) => _stateMachine.BackingAnimator().TriggerParameters(parameters); - public AacFlFloatParameterGroup FloatParameters(params AacFlFloatParameter[] parameters) => _stateMachine.BackingAnimator().FloatParameters(parameters); - public AacFlIntParameterGroup IntParameters(params AacFlIntParameter[] parameters) => _stateMachine.BackingAnimator().IntParameters(parameters); - public AacAv3 Av3() => new AacAv3(_stateMachine.BackingAnimator()); + public AacFlBoolParameter BoolParameter(string parameterName) => _stateMachine.InternalBackingAnimator().BoolParameter(parameterName); + public AacFlBoolParameter TriggerParameterAsBool(string parameterName) => _stateMachine.InternalBackingAnimator().TriggerParameter(parameterName); + public AacFlFloatParameter FloatParameter(string parameterName) => _stateMachine.InternalBackingAnimator().FloatParameter(parameterName); + public AacFlIntParameter IntParameter(string parameterName) => _stateMachine.InternalBackingAnimator().IntParameter(parameterName); + public AacFlBoolParameterGroup BoolParameters(params string[] parameterNames) => _stateMachine.InternalBackingAnimator().BoolParameters(parameterNames); + public AacFlBoolParameterGroup TriggerParametersAsBools(params string[] parameterNames) => _stateMachine.InternalBackingAnimator().TriggerParameters(parameterNames); + public AacFlFloatParameterGroup FloatParameters(params string[] parameterNames) => _stateMachine.InternalBackingAnimator().FloatParameters(parameterNames); + public AacFlIntParameterGroup IntParameters(params string[] parameterNames) => _stateMachine.InternalBackingAnimator().IntParameters(parameterNames); + public AacFlBoolParameterGroup BoolParameters(params AacFlBoolParameter[] parameters) => _stateMachine.InternalBackingAnimator().BoolParameters(parameters); + public AacFlBoolParameterGroup TriggerParametersAsBools(params AacFlBoolParameter[] parameters) => _stateMachine.InternalBackingAnimator().TriggerParameters(parameters); + public AacFlFloatParameterGroup FloatParameters(params AacFlFloatParameter[] parameters) => _stateMachine.InternalBackingAnimator().FloatParameters(parameters); + public AacFlIntParameterGroup IntParameters(params AacFlIntParameter[] parameters) => _stateMachine.InternalBackingAnimator().IntParameters(parameters); public AacFlLayer OverrideValue(AacFlBoolParameter toBeForced, bool value) { @@ -285,6 +299,11 @@ namespace AnimatorAsCode.V1 _stateMachine.WithDefaultState(newDefaultState); return this; } + + public AacFlStateMachine InternalStateMachine() + { + return _stateMachine; + } } public class AacFlBase @@ -313,6 +332,11 @@ namespace AnimatorAsCode.V1 var clip = AacV1.RegisterClip(_configuration, Guid.NewGuid().ToString(), newClip); return new AacFlClip(_configuration, clip); } + + public AacFlNonInitializedBlendTree NewBlendTree() + { + return new AacFlNonInitializedBlendTree(AacV1.NewBlendTreeAsRaw(_configuration, Guid.NewGuid().ToString())); + } public BlendTree NewBlendTreeAsRaw() { @@ -353,6 +377,18 @@ namespace AnimatorAsCode.V1 .WithUnit(unit, keyframes => keyframes.Constant(0, 0f).Constant(duration, 0f))); } + public AacFlController NewAnimatorController() + { + var animatorController = AacV1.NewAnimatorController(_configuration, Guid.NewGuid().ToString()); + return new AacFlController(_configuration, animatorController, this); + } + + public AacFlController NewAnimatorController(string name) + { + var animatorController = AacV1.NewAnimatorController(_configuration, name); + return new AacFlController(_configuration, animatorController, this); + } + public AacFlLayer CreateMainArbitraryControllerLayer(AnimatorController controller) => InternalDoCreateLayer(controller, _configuration.DefaultsProvider.ConvertLayerName(_configuration.SystemName)); public AacFlLayer CreateSupportingArbitraryControllerLayer(AnimatorController controller, string suffix) => InternalDoCreateLayer(controller, _configuration.DefaultsProvider.ConvertLayerNameWithSuffix(_configuration.SystemName, suffix)); public AacFlLayer CreateFirstArbitraryControllerLayer(AnimatorController controller) => InternalDoCreateLayer(controller, controller.layers[0].name); @@ -365,17 +401,20 @@ namespace AnimatorAsCode.V1 return new AacFlLayer(animator, _configuration, machine, layerName); } + internal AacFlLayer DoCreateLayerWithoutDeleting(AnimatorController animator, string layerName) + { + var ag = new AacAnimatorGenerator(animator, CreateEmptyClip().Clip, _configuration.DefaultsProvider); + var machine = ag.CreateOrClearLayerAtSameIndex(layerName, 1f, null, false); + + return new AacFlLayer(animator, _configuration, machine, layerName); + } + private AacFlClip CreateEmptyClip() { var emptyClip = AnomalousSingleKeyframeClip(); return emptyClip; } - public AacVrcAssetLibrary VrcAssets() - { - return new AacVrcAssetLibrary(); - } - public void ClearPreviousAssets() { var allSubAssets = AssetDatabase.LoadAllAssetsAtPath(AssetDatabase.GetAssetPath(_configuration.AssetContainer)); @@ -388,113 +427,209 @@ namespace AnimatorAsCode.V1 } } } - } - public class AacAv3 - { - private readonly AacBackingAnimator _backingAnimator; - - internal AacAv3(AacBackingAnimator backingAnimator) + public AacFlNoAnimator NoAnimator() { - _backingAnimator = backingAnimator; - } - - // ReSharper disable InconsistentNaming - public AacFlBoolParameter IsLocal => _backingAnimator.BoolParameter("IsLocal"); - public AacFlEnumIntParameter Viseme => _backingAnimator.EnumParameter("Viseme"); - public AacFlEnumIntParameter GestureLeft => _backingAnimator.EnumParameter("GestureLeft"); - public AacFlEnumIntParameter GestureRight => _backingAnimator.EnumParameter("GestureRight"); - public AacFlFloatParameter GestureLeftWeight => _backingAnimator.FloatParameter("GestureLeftWeight"); - public AacFlFloatParameter GestureRightWeight => _backingAnimator.FloatParameter("GestureRightWeight"); - public AacFlFloatParameter AngularY => _backingAnimator.FloatParameter("AngularY"); - public AacFlFloatParameter VelocityX => _backingAnimator.FloatParameter("VelocityX"); - public AacFlFloatParameter VelocityY => _backingAnimator.FloatParameter("VelocityY"); - public AacFlFloatParameter VelocityZ => _backingAnimator.FloatParameter("VelocityZ"); - public AacFlFloatParameter Upright => _backingAnimator.FloatParameter("Upright"); - public AacFlBoolParameter Grounded => _backingAnimator.BoolParameter("Grounded"); - public AacFlBoolParameter Seated => _backingAnimator.BoolParameter("Seated"); - public AacFlBoolParameter AFK => _backingAnimator.BoolParameter("AFK"); - public AacFlIntParameter TrackingType => _backingAnimator.IntParameter("TrackingType"); - public AacFlIntParameter VRMode => _backingAnimator.IntParameter("VRMode"); - public AacFlBoolParameter MuteSelf => _backingAnimator.BoolParameter("MuteSelf"); - public AacFlBoolParameter InStation => _backingAnimator.BoolParameter("InStation"); - public AacFlFloatParameter Voice => _backingAnimator.FloatParameter("Voice"); - // ReSharper restore InconsistentNaming - - public IAacFlCondition ItIsRemote() => IsLocal.IsFalse(); - public IAacFlCondition ItIsLocal() => IsLocal.IsTrue(); - - public enum Av3Gesture - { - // Specify all the values explicitly because they should be dictated by VRChat, not enumeration order. - Neutral = 0, - Fist = 1, - HandOpen = 2, - Fingerpoint = 3, - Victory = 4, - RockNRoll = 5, - HandGun = 6, - ThumbsUp = 7 - } - - public enum Av3Viseme - { - // Specify all the values explicitly because they should be dictated by VRChat, not enumeration order. - // ReSharper disable InconsistentNaming - sil = 0, - pp = 1, - ff = 2, - th = 3, - dd = 4, - kk = 5, - ch = 6, - ss = 7, - nn = 8, - rr = 9, - aa = 10, - e = 11, - ih = 12, - oh = 13, - ou = 14 - // ReSharper restore InconsistentNaming + return new AacFlNoAnimator(); } } - public class AacVrcAssetLibrary + public class AacFlNoAnimator { - public AvatarMask LeftHandAvatarMask() + public AacFlFloatParameter FloatParameter(string parameterName) => AacFlFloatParameter.Internally(parameterName); + public AacFlIntParameter IntParameter(string parameterName) => AacFlIntParameter.Internally(parameterName); + public AacFlBoolParameter BoolParameter(string parameterName) => AacFlBoolParameter.Internally(parameterName); + } + + public class AacFlBlendTree + { + protected AacFlBlendTree(BlendTree blendTree) { - return AssetDatabase.LoadAssetAtPath("Packages/com.vrchat.avatars/Samples/AV3 Demo Assets/Animation/Masks/vrc_Hand Left.mask"); + BlendTree = blendTree; } - public AvatarMask RightHandAvatarMask() + public BlendTree BlendTree { get; } + } + + public class AacFlNonInitializedBlendTree : AacFlBlendTree + { + public AacFlNonInitializedBlendTree(BlendTree blendTree) : base(blendTree) { - return AssetDatabase.LoadAssetAtPath("Packages/com.vrchat.avatars/Samples/AV3 Demo Assets/Animation/Masks/vrc_Hand Right.mask"); } - public AnimationClip ProxyForGesture(AacAv3.Av3Gesture gesture, bool masculine) + public AacFlBlendTree2D FreeformCartesian(AacFlFloatParameter parameterX, AacFlFloatParameter parameterY) { - return AssetDatabase.LoadAssetAtPath("Packages/com.vrchat.avatars/Samples/AV3 Demo Assets/Animation/ProxyAnim/" + ResolveProxyFilename(gesture, masculine)); + BlendTree.blendType = BlendTreeType.FreeformCartesian2D; + BlendTree.blendParameter = parameterX.Name; + BlendTree.blendParameterY = parameterY.Name; + + return new AacFlBlendTree2D(BlendTree); } - private static string ResolveProxyFilename(AacAv3.Av3Gesture gesture, bool masculine) + public AacFlBlendTree2D FreeformDirectional(AacFlFloatParameter parameterX, AacFlFloatParameter parameterY) { - switch (gesture) + BlendTree.blendType = BlendTreeType.FreeformDirectional2D; + BlendTree.blendParameter = parameterX.Name; + BlendTree.blendParameterY = parameterY.Name; + + return new AacFlBlendTree2D(BlendTree); + } + + public AacFlBlendTree2D SimpleDirectional(AacFlFloatParameter parameterX, AacFlFloatParameter parameterY) + { + BlendTree.blendType = BlendTreeType.SimpleDirectional2D; + BlendTree.blendParameter = parameterX.Name; + BlendTree.blendParameterY = parameterY.Name; + + return new AacFlBlendTree2D(BlendTree); + } + + public AacFlBlendTree1D Simple(AacFlFloatParameter parameter) + { + BlendTree.blendType = BlendTreeType.Simple1D; + BlendTree.blendParameter = parameter.Name; + BlendTree.useAutomaticThresholds = false; + + return new AacFlBlendTree1D(BlendTree); + } + + public AacFlBlendTreeDirect Direct() + { + BlendTree.blendType = BlendTreeType.Direct; + + return new AacFlBlendTreeDirect(BlendTree); + } + } + + public class AacFlBlendTree2D : AacFlBlendTree + { + public AacFlBlendTree2D(BlendTree blendTree) : base(blendTree) + { + } + + public AacFlBlendTree2D WithAnimation(AacFlBlendTree blendTree, Vector2 pos) + { + return WithAnimation(blendTree.BlendTree, pos); + } + + public AacFlBlendTree2D WithAnimation(AacFlBlendTree blendTree, float x, float y) + { + return WithAnimation(blendTree.BlendTree, x, y); + } + + public AacFlBlendTree2D WithAnimation(AacFlClip clip, Vector2 pos) + { + return WithAnimation(clip.Clip, pos); + } + + public AacFlBlendTree2D WithAnimation(AacFlClip clip, float x, float y) + { + return WithAnimation(clip.Clip, x, y); + } + + public AacFlBlendTree2D WithAnimation(Motion motion, Vector2 pos) + { + return WithAnimation(motion, pos.x, pos.y); + } + + public AacFlBlendTree2D WithAnimation(Motion motion, float x, float y) + { + var children = BlendTree.children ?? new ChildMotion[0]; + var childrenList = children.ToList(); + childrenList.Add(new ChildMotion { - case AacAv3.Av3Gesture.Neutral: return masculine ? "proxy_hands_idle.anim" : "proxy_hands_idle2.anim"; - case AacAv3.Av3Gesture.Fist: return "proxy_hands_fist.anim"; - case AacAv3.Av3Gesture.HandOpen: return "proxy_hands_open.anim"; - case AacAv3.Av3Gesture.Fingerpoint: return "proxy_hands_point.anim"; - case AacAv3.Av3Gesture.Victory: return "proxy_hands_peace.anim"; - case AacAv3.Av3Gesture.RockNRoll: return "proxy_hands_rock.anim"; - case AacAv3.Av3Gesture.HandGun: return "proxy_hands_gun.anim"; - case AacAv3.Av3Gesture.ThumbsUp: return "proxy_hands_thumbs_up.anim"; - default: - throw new ArgumentOutOfRangeException(nameof(gesture), gesture, null); - } + motion = motion, + position = new Vector2(x, y), + timeScale = 1f + }); + BlendTree.children = childrenList.ToArray(); + + return this; } } + public class AacFlBlendTree1D : AacFlBlendTree + { + public AacFlBlendTree1D(BlendTree blendTree) : base(blendTree) + { + } + + public AacFlBlendTree1D WithAnimation(AacFlClip clip, float threshold) + { + return WithAnimation(clip.Clip, threshold); + } + + public AacFlBlendTree1D WithAnimation(AacFlBlendTree blendTree, float threshold) + { + return WithAnimation(blendTree.BlendTree, threshold); + } + + public AacFlBlendTree1D WithAnimation(Motion motion, float threshold) + { + var children = BlendTree.children ?? new ChildMotion[0]; + var childrenList = children.ToList(); + childrenList.Add(new ChildMotion + { + motion = motion, + threshold = threshold, + timeScale = 1f + }); + BlendTree.children = childrenList.ToArray(); + + return this; + } + } + + public class AacFlBlendTreeDirect : AacFlBlendTree + { + public AacFlBlendTreeDirect(BlendTree blendTree) : base(blendTree) + { + } + + public AacFlBlendTreeDirect WithAnimation(AacFlClip clip, AacFlFloatParameter parameter) + { + return WithAnimation(clip.Clip, parameter); + } + + public AacFlBlendTreeDirect WithAnimation(AacFlBlendTree blendTree, AacFlFloatParameter parameter) + { + return WithAnimation(blendTree.BlendTree, parameter); + } + + public AacFlBlendTreeDirect WithAnimation(Motion motion, AacFlFloatParameter parameter) + { + var children = BlendTree.children ?? new ChildMotion[0]; + var childrenList = children.ToList(); + childrenList.Add(new ChildMotion + { + motion = motion, + directBlendParameter = parameter.Name, + timeScale = 1f + }); + BlendTree.children = childrenList.ToArray(); + + return this; + } + } + + public class AacFlController + { + public AnimatorController AnimatorController; + + private readonly AacConfiguration _configuration; + private readonly AacFlBase _base; + + public AacFlController(AacConfiguration configuration, AnimatorController animatorController, AacFlBase originalBase) + { + AnimatorController = animatorController; + _configuration = configuration; + _base = originalBase; + } + + public AacFlLayer CreateLayer(string suffix) => _base.DoCreateLayerWithoutDeleting(AnimatorController, _configuration.DefaultsProvider.ConvertLayerNameWithSuffix(_configuration.SystemName, suffix)); + public AacFlLayer CreateLayer() => _base.DoCreateLayerWithoutDeleting(AnimatorController, _configuration.SystemName); + } + public class AacAnimatorRemoval { private readonly AnimatorController _animatorController; @@ -592,11 +727,15 @@ namespace AnimatorAsCode.V1 .WithExitPosition(7, -1); } - internal AacFlStateMachine CreateOrClearLayerAtSameIndex(string layerName, float weightWhenCreating, AvatarMask maskWhenCreating = null) + internal AacFlStateMachine CreateOrClearLayerAtSameIndex(string layerName, float weightWhenCreating, AvatarMask maskWhenCreating = null, bool allowDeletion = true) { var originalIndexToPreserveOrdering = FindIndexOf(layerName); if (originalIndexToPreserveOrdering != -1) { + if (!allowDeletion) + { + throw new InvalidOperationException($"Cannot create layer with name {layerName} as it already exists. When creating layers using NewAnimatorController, you may only use unique names."); + } RecursivelyClearChildrenMachines(_animatorController.layers[originalIndexToPreserveOrdering].stateMachine); _animatorController.layers[originalIndexToPreserveOrdering].stateMachine.stateMachines = new ChildAnimatorStateMachine[0]; diff --git a/Framework/Editor/V1/AacFlConditions.cs b/Framework/Editor/V1/AacFlConditions.cs index 5108f92..778a647 100644 --- a/Framework/Editor/V1/AacFlConditions.cs +++ b/Framework/Editor/V1/AacFlConditions.cs @@ -124,7 +124,7 @@ namespace AnimatorAsCode.V1 internal static AacFlFloatParameterGroup Internally(params string[] names) => new AacFlFloatParameterGroup(names); private readonly string[] _names; private AacFlFloatParameterGroup(params string[] names) { _names = names; } - public List ToList() => _names.Select(AacFlBoolParameter.Internally).ToList(); + public List ToList() => _names.Select(AacFlFloatParameter.Internally).ToList(); public IAacFlCondition AreGreaterThan(float other) => ForEach(_names, (name, condition) => condition.Add(name, Greater, other)); public IAacFlCondition AreLessThan(float other) => ForEach(_names, (name, condition) => condition.Add(name, Less, other)); @@ -135,7 +135,7 @@ namespace AnimatorAsCode.V1 internal static AacFlIntParameterGroup Internally(params string[] names) => new AacFlIntParameterGroup(names); private readonly string[] _names; private AacFlIntParameterGroup(params string[] names) { _names = names; } - public List ToList() => _names.Select(AacFlBoolParameter.Internally).ToList(); + public List ToList() => _names.Select(AacFlIntParameter.Internally).ToList(); public IAacFlCondition AreGreaterThan(float other) => ForEach(_names, (name, condition) => condition.Add(name, Greater, other)); public IAacFlCondition AreLessThan(float other) => ForEach(_names, (name, condition) => condition.Add(name, Less, other)); diff --git a/Framework/Editor/V1/AacFlStates.cs b/Framework/Editor/V1/AacFlStates.cs index 5552f00..dd554e5 100644 --- a/Framework/Editor/V1/AacFlStates.cs +++ b/Framework/Editor/V1/AacFlStates.cs @@ -7,7 +7,7 @@ using UnityEngine; // ReSharper disable once CheckNamespace namespace AnimatorAsCode.V1 { - internal class AacBackingAnimator + public class AacBackingAnimator { private readonly AacAnimatorGenerator _generator; @@ -134,7 +134,7 @@ namespace AnimatorAsCode.V1 _childNodes = new List(); } - internal AacBackingAnimator BackingAnimator() + public AacBackingAnimator InternalBackingAnimator() { return _backingAnimator; } @@ -332,6 +332,12 @@ namespace AnimatorAsCode.V1 return this; } + public AacFlState WithAnimation(AacFlBlendTree blendTree) + { + State.motion = blendTree.BlendTree; + return this; + } + public AacFlTransition TransitionsTo(AacFlState destination) { return new AacFlTransition(ConfigureTransition(State.AddTransition(destination.State)), _machine, State, destination.State); diff --git a/Framework/Editor/V1VRC/VRChatExtensions.cs b/Framework/Editor/V1VRC/AacVRCExtensions.cs similarity index 69% rename from Framework/Editor/V1VRC/VRChatExtensions.cs rename to Framework/Editor/V1VRC/AacVRCExtensions.cs index 63c9786..e9d72ed 100644 --- a/Framework/Editor/V1VRC/VRChatExtensions.cs +++ b/Framework/Editor/V1VRC/AacVRCExtensions.cs @@ -1,12 +1,24 @@ using System; +using UnityEditor; +using UnityEngine; using VRC.SDK3.Avatars.Components; using VRC.SDKBase; // ReSharper disable once CheckNamespace namespace AnimatorAsCode.V1.VRC { - public static class VRChatExtensions + public static class AacVRCExtensions { + public static AacVrcAssetLibrary VrcAssets(this AacFlBase that) + { + return new AacVrcAssetLibrary(); + } + + public static AacAv3 Av3(this AacFlLayer that) + { + return new AacAv3(that.InternalStateMachine().InternalBackingAnimator()); + } + /// /// Set parameter to a given value. For unsynced parameters, also see DrivingLocally. /// @@ -196,7 +208,7 @@ namespace AnimatorAsCode.V1.VRC return node; } - public static TNode TrackingTracks(this TNode node, TrackingElement element) where TNode : AacAnimatorNode + public static TNode TrackingTracks(this TNode node, AacAv3.Av3TrackingElement element) where TNode : AacAnimatorNode { var tracking = node.EnsureBehaviour(); SettingElementTo(tracking, element, VRC_AnimatorTrackingControl.TrackingType.Tracking); @@ -204,7 +216,7 @@ namespace AnimatorAsCode.V1.VRC return node; } - public static TNode TrackingAnimates(this TNode node, TrackingElement element) where TNode : AacAnimatorNode + public static TNode TrackingAnimates(this TNode node, AacAv3.Av3TrackingElement element) where TNode : AacAnimatorNode { var tracking = node.EnsureBehaviour(); SettingElementTo(tracking, element, VRC_AnimatorTrackingControl.TrackingType.Animation); @@ -212,7 +224,7 @@ namespace AnimatorAsCode.V1.VRC return node; } - public static TNode TrackingSets(this TNode node, TrackingElement element, VRC_AnimatorTrackingControl.TrackingType trackingType) where TNode : AacAnimatorNode + public static TNode TrackingSets(this TNode node, AacAv3.Av3TrackingElement element, VRC_AnimatorTrackingControl.TrackingType trackingType) where TNode : AacAnimatorNode { var tracking = node.EnsureBehaviour(); SettingElementTo(tracking, element, trackingType); @@ -220,38 +232,38 @@ namespace AnimatorAsCode.V1.VRC return node; } - private static void SettingElementTo(VRCAnimatorTrackingControl tracking, TrackingElement element, VRC_AnimatorTrackingControl.TrackingType target) + private static void SettingElementTo(VRCAnimatorTrackingControl tracking, AacAv3.Av3TrackingElement element, VRC_AnimatorTrackingControl.TrackingType target) { switch (element) { - case TrackingElement.Head: + case AacAv3.Av3TrackingElement.Head: tracking.trackingHead = target; break; - case TrackingElement.LeftHand: + case AacAv3.Av3TrackingElement.LeftHand: tracking.trackingLeftHand = target; break; - case TrackingElement.RightHand: + case AacAv3.Av3TrackingElement.RightHand: tracking.trackingRightHand = target; break; - case TrackingElement.Hip: + case AacAv3.Av3TrackingElement.Hip: tracking.trackingHip = target; break; - case TrackingElement.LeftFoot: + case AacAv3.Av3TrackingElement.LeftFoot: tracking.trackingLeftFoot = target; break; - case TrackingElement.RightFoot: + case AacAv3.Av3TrackingElement.RightFoot: tracking.trackingRightFoot = target; break; - case TrackingElement.LeftFingers: + case AacAv3.Av3TrackingElement.LeftFingers: tracking.trackingLeftFingers = target; break; - case TrackingElement.RightFingers: + case AacAv3.Av3TrackingElement.RightFingers: tracking.trackingRightFingers = target; break; - case TrackingElement.Eyes: + case AacAv3.Av3TrackingElement.Eyes: tracking.trackingEyes = target; break; - case TrackingElement.Mouth: + case AacAv3.Av3TrackingElement.Mouth: tracking.trackingMouth = target; break; default: @@ -335,4 +347,123 @@ namespace AnimatorAsCode.V1.VRC return node; } } + + public class AacAv3 + { + private readonly AacBackingAnimator _backingAnimator; + + internal AacAv3(AacBackingAnimator backingAnimator) + { + _backingAnimator = backingAnimator; + } + + // ReSharper disable InconsistentNaming + public AacFlBoolParameter IsLocal => _backingAnimator.BoolParameter("IsLocal"); + public AacFlEnumIntParameter Viseme => _backingAnimator.EnumParameter("Viseme"); + public AacFlEnumIntParameter GestureLeft => _backingAnimator.EnumParameter("GestureLeft"); + public AacFlEnumIntParameter GestureRight => _backingAnimator.EnumParameter("GestureRight"); + public AacFlFloatParameter GestureLeftWeight => _backingAnimator.FloatParameter("GestureLeftWeight"); + public AacFlFloatParameter GestureRightWeight => _backingAnimator.FloatParameter("GestureRightWeight"); + public AacFlFloatParameter AngularY => _backingAnimator.FloatParameter("AngularY"); + public AacFlFloatParameter VelocityX => _backingAnimator.FloatParameter("VelocityX"); + public AacFlFloatParameter VelocityY => _backingAnimator.FloatParameter("VelocityY"); + public AacFlFloatParameter VelocityZ => _backingAnimator.FloatParameter("VelocityZ"); + public AacFlFloatParameter Upright => _backingAnimator.FloatParameter("Upright"); + public AacFlBoolParameter Grounded => _backingAnimator.BoolParameter("Grounded"); + public AacFlBoolParameter Seated => _backingAnimator.BoolParameter("Seated"); + public AacFlBoolParameter AFK => _backingAnimator.BoolParameter("AFK"); + public AacFlIntParameter TrackingType => _backingAnimator.IntParameter("TrackingType"); + public AacFlIntParameter VRMode => _backingAnimator.IntParameter("VRMode"); + public AacFlBoolParameter MuteSelf => _backingAnimator.BoolParameter("MuteSelf"); + public AacFlBoolParameter InStation => _backingAnimator.BoolParameter("InStation"); + public AacFlFloatParameter Voice => _backingAnimator.FloatParameter("Voice"); + // ReSharper restore InconsistentNaming + + public IAacFlCondition ItIsRemote() => IsLocal.IsFalse(); + public IAacFlCondition ItIsLocal() => IsLocal.IsTrue(); + + public enum Av3TrackingElement + { + Head, + LeftHand, + RightHand, + Hip, + LeftFoot, + RightFoot, + LeftFingers, + RightFingers, + Eyes, + Mouth + } + + public enum Av3Gesture + { + // Specify all the values explicitly because they should be dictated by VRChat, not enumeration order. + Neutral = 0, + Fist = 1, + HandOpen = 2, + Fingerpoint = 3, + Victory = 4, + RockNRoll = 5, + HandGun = 6, + ThumbsUp = 7 + } + + public enum Av3Viseme + { + // Specify all the values explicitly because they should be dictated by VRChat, not enumeration order. + // ReSharper disable InconsistentNaming + sil = 0, + pp = 1, + ff = 2, + th = 3, + dd = 4, + kk = 5, + ch = 6, + ss = 7, + nn = 8, + rr = 9, + aa = 10, + e = 11, + ih = 12, + oh = 13, + ou = 14 + // ReSharper restore InconsistentNaming + } + } + + public class AacVrcAssetLibrary + { + public AvatarMask LeftHandAvatarMask() + { + return AssetDatabase.LoadAssetAtPath("Packages/com.vrchat.avatars/Samples/AV3 Demo Assets/Animation/Masks/vrc_Hand Left.mask"); + } + + public AvatarMask RightHandAvatarMask() + { + return AssetDatabase.LoadAssetAtPath("Packages/com.vrchat.avatars/Samples/AV3 Demo Assets/Animation/Masks/vrc_Hand Right.mask"); + } + + public AnimationClip ProxyForGesture(AacAv3.Av3Gesture gesture, bool masculine) + { + return AssetDatabase.LoadAssetAtPath("Packages/com.vrchat.avatars/Samples/AV3 Demo Assets/Animation/ProxyAnim/" + ResolveProxyFilename(gesture, masculine)); + } + + private static string ResolveProxyFilename(AacAv3.Av3Gesture gesture, bool masculine) + { + switch (gesture) + { + case AacAv3.Av3Gesture.Neutral: return masculine ? "proxy_hands_idle.anim" : "proxy_hands_idle2.anim"; + case AacAv3.Av3Gesture.Fist: return "proxy_hands_fist.anim"; + case AacAv3.Av3Gesture.HandOpen: return "proxy_hands_open.anim"; + case AacAv3.Av3Gesture.Fingerpoint: return "proxy_hands_point.anim"; + case AacAv3.Av3Gesture.Victory: return "proxy_hands_peace.anim"; + case AacAv3.Av3Gesture.RockNRoll: return "proxy_hands_rock.anim"; + case AacAv3.Av3Gesture.HandGun: return "proxy_hands_gun.anim"; + case AacAv3.Av3Gesture.ThumbsUp: return "proxy_hands_thumbs_up.anim"; + default: + throw new ArgumentOutOfRangeException(nameof(gesture), gesture, null); + } + } + } } \ No newline at end of file diff --git a/Framework/Editor/V1VRC/VRChatExtensions.cs.meta b/Framework/Editor/V1VRC/AacVRCExtensions.cs.meta similarity index 100% rename from Framework/Editor/V1VRC/VRChatExtensions.cs.meta rename to Framework/Editor/V1VRC/AacVRCExtensions.cs.meta diff --git a/Framework/Editor/V1VRC/TrackingElement.cs b/Framework/Editor/V1VRC/TrackingElement.cs deleted file mode 100644 index 5b2dcdf..0000000 --- a/Framework/Editor/V1VRC/TrackingElement.cs +++ /dev/null @@ -1,17 +0,0 @@ -// ReSharper disable once CheckNamespace -namespace AnimatorAsCode.V1.VRC -{ - public enum TrackingElement - { - Head, - LeftHand, - RightHand, - Hip, - LeftFoot, - RightFoot, - LeftFingers, - RightFingers, - Eyes, - Mouth - } -} \ No newline at end of file diff --git a/Framework/Editor/V1VRC/TrackingElement.cs.meta b/Framework/Editor/V1VRC/TrackingElement.cs.meta deleted file mode 100644 index b12bcb3..0000000 --- a/Framework/Editor/V1VRC/TrackingElement.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 15a0b71b5f463174a894197698238912 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/MigratingFromV0ToV1.md b/MigratingFromV0ToV1.md new file mode 100644 index 0000000..cb21266 --- /dev/null +++ b/MigratingFromV0ToV1.md @@ -0,0 +1,63 @@ +Migrating from V0 to V1 +====== + +AnimatorAsCode V1 introduces the following main breaking changes: +- VRChat Avatars is now an optional dependency. AnimatorAsCode can now be used in non-VRChat projects. + - All VRChat-related functions have been split between two classes of extension methods. +- You are now encouraged to use a non-destructive workflow by generating an animator controller asset without relying on an existing animator controller asset. + - VRChat methods that use a destructive workflow, such as `AacFlBase.CreateMainFxLayer()` are located on their own class of extension methods. + +## Assembly definition + +If you use assembly definitions, change the assembly reference from `AnimatorAsCodeFramework` to the following: +- `AnimatorAsCodeFramework.V1` in all cases. +- `AnimatorAsCodeFramework.V1.VRC` if you depend on VRChat. +- `AnimatorAsCodeFramework.V1.VRCDestructiveWorkflow` also if you need to edit the playable layers of the avatar directly. + - *Consider switching to a non-destructive workflow using VRCFury or Modular Avatar! See below.* + +## Code changes + +### Code + +- Change `AacV0` to `AacV1` +- Change `using AnimatorAsCode.V0;` to `using AnimatorAsCode.V1;` +- If your project depends on VRChat, you will need to use extension methods. + - Add `using AnimatorAsCode.V1.VRC;` in your class imports to use the VRChat extension methods. + - The extension methods are contained within the class `AnimatorAsCode.V1.VRC.AacVRCExtensions`. + - Add `using AnimatorAsCode.V1.VRC;` in your class imports to use the extension methods. + - The extension methods are contained within the class `AnimatorAsCode.V1.VRCDestructiveWorkflow.AacVRCDestructiveWorkflowExtensions` + +# TODO + +- TODO: Check TrackingElement being renamed to AacAv3.Av3TrackingElement + +### AacConfiguration + +Since `AacConfiguration` no longer contains the avatar descriptor, you will need to use the extension method `AacConfiguration.WithAvatarDescriptor(VRCAvatarDescriptor)` to define the avatar in the configuration. + +For example: + +```csharp +using AnimatorAsCode.V1; +using AnimatorAsCode.V1.VRCDestructiveWorkflow; +// ... + +AacV1.Create(new AacConfiguration +{ + SystemName = systemName, + AnimatorRoot = avatar.transform, + DefaultValueRoot = avatar.transform, + AssetContainer = assetContainer, + AssetKey = assetKey, + DefaultsProvider = new AacDefaultsProvider(writeDefaults: options.WriteDefaults) +}.WithAvatarDescriptor(avatar)); // The avatar descriptor is now defined by invoking an extension method. +``` + +# Non-destructive workflow + +Animator As Code V1 encourages the use of a non-destructive workflow. + +Here's a quick example: + + +Please open the file `Examples/GenExample4_NonDestructiveWorkflow.cs`. diff --git a/MigratingFromV0ToV1.md.meta b/MigratingFromV0ToV1.md.meta new file mode 100644 index 0000000..4456567 --- /dev/null +++ b/MigratingFromV0ToV1.md.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 7a4f3d8242e54ad1ac7571b9b0d92829 +timeCreated: 1693748560 \ No newline at end of file diff --git a/Tests/V1VRC/PlayMode/GenerationTests/AIACVRCExtensionsMiscGenerationTest.cs b/Tests/V1VRC/PlayMode/GenerationTests/AIACVRCExtensionsMiscGenerationTest.cs index 1b3e9e7..ece226c 100644 --- a/Tests/V1VRC/PlayMode/GenerationTests/AIACVRCExtensionsMiscGenerationTest.cs +++ b/Tests/V1VRC/PlayMode/GenerationTests/AIACVRCExtensionsMiscGenerationTest.cs @@ -16,7 +16,7 @@ namespace av3_animator_as_code.Tests.V1VRC.PlayMode.GenerationTests // Exercise var first = fx.NewState("First"); - var whichElement = TrackingElement.Head; + var whichElement = AacAv3.Av3TrackingElement.Head; first.TrackingTracks(whichElement); // Verify @@ -46,7 +46,7 @@ namespace av3_animator_as_code.Tests.V1VRC.PlayMode.GenerationTests // Exercise var first = fx.NewState("First"); - var whichElement = TrackingElement.Head; + var whichElement = AacAv3.Av3TrackingElement.Head; first.TrackingAnimates(whichElement); // Verify @@ -76,7 +76,7 @@ namespace av3_animator_as_code.Tests.V1VRC.PlayMode.GenerationTests // Exercise var first = fx.NewState("First"); - var whichElement = TrackingElement.Head; + var whichElement = AacAv3.Av3TrackingElement.Head; first.TrackingSets(whichElement, VRC_AnimatorTrackingControl.TrackingType.Tracking); // Verify @@ -106,7 +106,7 @@ namespace av3_animator_as_code.Tests.V1VRC.PlayMode.GenerationTests // Exercise var first = fx.NewState("First"); - var whichElement = TrackingElement.Head; + var whichElement = AacAv3.Av3TrackingElement.Head; first.TrackingSets(whichElement, VRC_AnimatorTrackingControl.TrackingType.Animation); // Verify @@ -136,7 +136,7 @@ namespace av3_animator_as_code.Tests.V1VRC.PlayMode.GenerationTests // Exercise var first = fx.NewState("First"); - var whichElement = TrackingElement.LeftHand; + var whichElement = AacAv3.Av3TrackingElement.LeftHand; first.TrackingSets(whichElement, VRC_AnimatorTrackingControl.TrackingType.Animation); // Verify @@ -166,7 +166,7 @@ namespace av3_animator_as_code.Tests.V1VRC.PlayMode.GenerationTests // Exercise var first = fx.NewState("First"); - var whichElement = TrackingElement.RightHand; + var whichElement = AacAv3.Av3TrackingElement.RightHand; first.TrackingSets(whichElement, VRC_AnimatorTrackingControl.TrackingType.Animation); // Verify @@ -196,7 +196,7 @@ namespace av3_animator_as_code.Tests.V1VRC.PlayMode.GenerationTests // Exercise var first = fx.NewState("First"); - var whichElement = TrackingElement.Hip; + var whichElement = AacAv3.Av3TrackingElement.Hip; first.TrackingSets(whichElement, VRC_AnimatorTrackingControl.TrackingType.Animation); // Verify @@ -226,7 +226,7 @@ namespace av3_animator_as_code.Tests.V1VRC.PlayMode.GenerationTests // Exercise var first = fx.NewState("First"); - var whichElement = TrackingElement.LeftFoot; + var whichElement = AacAv3.Av3TrackingElement.LeftFoot; first.TrackingSets(whichElement, VRC_AnimatorTrackingControl.TrackingType.Animation); // Verify @@ -256,7 +256,7 @@ namespace av3_animator_as_code.Tests.V1VRC.PlayMode.GenerationTests // Exercise var first = fx.NewState("First"); - var whichElement = TrackingElement.RightFoot; + var whichElement = AacAv3.Av3TrackingElement.RightFoot; first.TrackingSets(whichElement, VRC_AnimatorTrackingControl.TrackingType.Animation); // Verify @@ -286,7 +286,7 @@ namespace av3_animator_as_code.Tests.V1VRC.PlayMode.GenerationTests // Exercise var first = fx.NewState("First"); - var whichElement = TrackingElement.LeftFingers; + var whichElement = AacAv3.Av3TrackingElement.LeftFingers; first.TrackingSets(whichElement, VRC_AnimatorTrackingControl.TrackingType.Animation); // Verify @@ -316,7 +316,7 @@ namespace av3_animator_as_code.Tests.V1VRC.PlayMode.GenerationTests // Exercise var first = fx.NewState("First"); - var whichElement = TrackingElement.RightFingers; + var whichElement = AacAv3.Av3TrackingElement.RightFingers; first.TrackingSets(whichElement, VRC_AnimatorTrackingControl.TrackingType.Animation); // Verify @@ -346,7 +346,7 @@ namespace av3_animator_as_code.Tests.V1VRC.PlayMode.GenerationTests // Exercise var first = fx.NewState("First"); - var whichElement = TrackingElement.Eyes; + var whichElement = AacAv3.Av3TrackingElement.Eyes; first.TrackingSets(whichElement, VRC_AnimatorTrackingControl.TrackingType.Animation); // Verify @@ -376,7 +376,7 @@ namespace av3_animator_as_code.Tests.V1VRC.PlayMode.GenerationTests // Exercise var first = fx.NewState("First"); - var whichElement = TrackingElement.Mouth; + var whichElement = AacAv3.Av3TrackingElement.Mouth; first.TrackingSets(whichElement, VRC_AnimatorTrackingControl.TrackingType.Animation); // Verify @@ -406,9 +406,9 @@ namespace av3_animator_as_code.Tests.V1VRC.PlayMode.GenerationTests // Exercise var first = fx.NewState("First"); - first.TrackingSets(TrackingElement.Head, VRC_AnimatorTrackingControl.TrackingType.Animation); - first.TrackingSets(TrackingElement.LeftHand, VRC_AnimatorTrackingControl.TrackingType.Animation); - first.TrackingSets(TrackingElement.RightHand, VRC_AnimatorTrackingControl.TrackingType.Animation); + first.TrackingSets(AacAv3.Av3TrackingElement.Head, VRC_AnimatorTrackingControl.TrackingType.Animation); + first.TrackingSets(AacAv3.Av3TrackingElement.LeftHand, VRC_AnimatorTrackingControl.TrackingType.Animation); + first.TrackingSets(AacAv3.Av3TrackingElement.RightHand, VRC_AnimatorTrackingControl.TrackingType.Animation); // Verify var eState = controller.layers[0].stateMachine.states[0].state;