Files
av3-animation-as-crab/Framework/Editor/V0/Aac.cs
T
2022-02-27 20:16:34 +01:00

632 lines
28 KiB
C#

using System;
using System.Linq;
using UnityEditor;
using UnityEditor.Animations;
using UnityEngine;
using VRC.SDK3.Avatars.Components;
using Random = UnityEngine.Random;
// ReSharper disable once CheckNamespace
namespace AnimatorAsCode.V0
{
public static class AacV0
{
public static AacFlBase Create(AacConfiguration configuration)
{
return new AacFlBase(configuration);
}
internal static AnimatorController AnimatorOf(VRCAvatarDescriptor ad, VRCAvatarDescriptor.AnimLayerType animLayerType)
{
return (AnimatorController) ad.baseAnimationLayers.First(it => it.type == animLayerType).animatorController;
}
internal static AnimationClip NewClip(AacConfiguration component, string suffix)
{
return RegisterClip(component, suffix, new AnimationClip());
}
internal static AnimationClip RegisterClip(AacConfiguration component, string suffix, AnimationClip clip)
{
clip.name = "zAutogenerated__" + component.AssetKey + "__" + suffix + "_" + Random.Range(0, Int32.MaxValue); // FIXME animation name conflict
clip.hideFlags = HideFlags.None;
AssetDatabase.AddObjectToAsset(clip, component.AssetContainer);
return clip;
}
internal static BlendTree NewBlendTreeAsRaw(AacConfiguration component, string suffix)
{
var clip = new BlendTree();
clip.name = "zAutogenerated__" + component.AssetKey + "__" + suffix + "_" + Random.Range(0, Int32.MaxValue); // FIXME animation name conflict
clip.hideFlags = HideFlags.None;
AssetDatabase.AddObjectToAsset(clip, component.AssetContainer);
return clip;
}
internal static EditorCurveBinding Binding(AacConfiguration component, Type type, Transform transform, string propertyName)
{
return new EditorCurveBinding
{
path = ResolveRelativePath(component.AnimatorRoot, transform),
type = type,
propertyName = propertyName
};
}
internal static AnimationCurve OneFrame(float desiredValue)
{
return AnimationCurve.Constant(0f, 1 / 60f, desiredValue);
}
internal static AnimationCurve ConstantSeconds(float seconds, float desiredValue)
{
return AnimationCurve.Constant(0f, seconds, desiredValue);
}
internal static string ResolveRelativePath(Transform avatar, Transform item)
{
if (item.parent != avatar && item.parent != null)
{
return ResolveRelativePath(avatar, item.parent) + "/" + item.name;
}
return item.name;
}
internal static EditorCurveBinding ToSubBinding(EditorCurveBinding binding, string suffix)
{
return new EditorCurveBinding {path = binding.path, type = binding.type, propertyName = binding.propertyName + "." + suffix};
}
}
public struct AacConfiguration
{
public string SystemName;
public VRCAvatarDescriptor AvatarDescriptor;
public Transform AnimatorRoot;
public Transform DefaultValueRoot;
public AnimatorController AssetContainer;
public string AssetKey;
public IAacDefaultsProvider DefaultsProvider;
}
public struct AacFlLayer
{
private readonly AnimatorController _animatorController;
private readonly AacConfiguration _configuration;
private readonly string _fullLayerName;
private readonly AacStateMachine _stateMachine;
internal AacFlLayer(AnimatorController animatorController, AacConfiguration configuration, AacStateMachine stateMachine, string fullLayerName)
{
_animatorController = animatorController;
_configuration = configuration;
_fullLayerName = fullLayerName;
_stateMachine = stateMachine;
}
public AacFlState NewState(string name)
{
var lastState = _stateMachine.LastStatePosition();
var state = _stateMachine.NewState(name, 0, 0).Shift(lastState, 0, 1);
return state;
}
public AacFlState NewState(string name, int x, int y)
{
return _stateMachine.NewState(name, x, y);
}
public AacFlTransition AnyTransitionsTo(AacFlState destination)
{
return _stateMachine.AnyTransitionsTo(destination);
}
public AacFlEntryTransition EntryTransitionsTo(AacFlState destination)
{
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 void OverrideValue(AacFlBoolParameter toBeForced, bool value)
{
var parameters = _animatorController.parameters;
foreach (var param in parameters)
{
if (param.name == toBeForced.Name)
{
param.defaultBool = value;
}
}
_animatorController.parameters = parameters;
}
public void OverrideValue(AacFlFloatParameter toBeForced, float value)
{
var parameters = _animatorController.parameters;
foreach (var param in parameters)
{
if (param.name == toBeForced.Name)
{
param.defaultFloat = value;
}
}
_animatorController.parameters = parameters;
}
public void OverrideValue(AacFlIntParameter toBeForced, int value)
{
var parameters = _animatorController.parameters;
foreach (var param in parameters)
{
if (param.name == toBeForced.Name)
{
param.defaultInt = value;
}
}
_animatorController.parameters = parameters;
}
public AacFlLayer WithAvatarMask(AvatarMask avatarMask)
{
var finalFullLayerName = _fullLayerName;
_animatorController.layers = _animatorController.layers
.Select(layer =>
{
if (layer.name == finalFullLayerName)
{
layer.avatarMask = avatarMask;
}
return layer;
})
.ToArray();
return this;
}
public void WithAvatarMaskNoTransforms()
{
ResolveAvatarMask(new Transform[0]);
}
public void ResolveAvatarMask(Transform[] paths)
{
// FIXME: Fragile
var avatarMask = new AvatarMask();
avatarMask.name = "zAutogenerated__" + _configuration.AssetKey + "_" + _fullLayerName + "__AvatarMask";
avatarMask.hideFlags = HideFlags.None;
if (paths.Length == 0)
{
avatarMask.transformCount = 1;
avatarMask.SetTransformActive(0, false);
avatarMask.SetTransformPath(0, "_ignored");
}
else
{
avatarMask.transformCount = paths.Length;
for (var index = 0; index < paths.Length; index++)
{
var transform = paths[index];
avatarMask.SetTransformActive(index, true);
avatarMask.SetTransformPath(index, AacV0.ResolveRelativePath(_configuration.AnimatorRoot, transform));
}
}
for (int i = 0; i < (int) AvatarMaskBodyPart.LastBodyPart; i++)
{
avatarMask.SetHumanoidBodyPartActive((AvatarMaskBodyPart) i, false);
}
AssetDatabase.AddObjectToAsset(avatarMask, _animatorController);
WithAvatarMask(avatarMask);
}
}
public class AacFlBase
{
private readonly AacConfiguration _configuration;
internal AacFlBase(AacConfiguration configuration)
{
_configuration = configuration;
}
public AacFlClip NewClip()
{
var clip = AacV0.NewClip(_configuration, Guid.NewGuid().ToString());
return new AacFlClip(_configuration, clip);
}
public AacFlClip CopyClip(AnimationClip originalClip)
{
var newClip = UnityEngine.Object.Instantiate(originalClip);
var clip = AacV0.RegisterClip(_configuration, Guid.NewGuid().ToString(), newClip);
return new AacFlClip(_configuration, clip);
}
public BlendTree NewBlendTreeAsRaw()
{
return AacV0.NewBlendTreeAsRaw(_configuration, Guid.NewGuid().ToString());
}
public AacFlClip NewClip(string name)
{
var clip = AacV0.NewClip(_configuration, name);
return new AacFlClip(_configuration, clip);
}
public AacFlClip DummyClipLasting(float numberOf, AacFlUnit unit)
{
var dummyClip = AacV0.NewClip(_configuration, $"D({numberOf} {Enum.GetName(typeof(AacFlUnit), unit)})");
var duration = unit == AacFlUnit.Frames ? numberOf / 60f : numberOf;
return new AacFlClip(_configuration, dummyClip)
.Animating(clip => clip.Animates("_ignored", typeof(GameObject), "m_IsActive")
.WithUnit(unit, keyframes => keyframes.Constant(0, 0f).Constant(duration, 0f)));
}
public void RemoveAllMainLayers()
{
var layerName = _configuration.SystemName;
RemoveLayerOnAllControllers(_configuration.DefaultsProvider.ConvertLayerName(layerName));
}
public void RemoveAllSupportingLayers(string suffix)
{
var layerName = _configuration.SystemName;
RemoveLayerOnAllControllers(_configuration.DefaultsProvider.ConvertLayerNameWithSuffix(layerName, suffix));
}
private void RemoveLayerOnAllControllers(string layerName)
{
var layers = _configuration.AvatarDescriptor.baseAnimationLayers.Select(layer => layer.animatorController).Where(layer => layer != null).Distinct().ToList();
foreach (var customAnimLayer in layers)
{
new AacAnimatorRemoval((AnimatorController) customAnimLayer).RemoveLayer(_configuration.DefaultsProvider.ConvertLayerName(layerName));
}
}
public AacFlLayer CreateMainFxLayer() => DoCreateMainLayerOnController(VRCAvatarDescriptor.AnimLayerType.FX);
public AacFlLayer CreateMainGestureLayer() => DoCreateMainLayerOnController(VRCAvatarDescriptor.AnimLayerType.Gesture);
public AacFlLayer CreateMainActionLayer() => DoCreateMainLayerOnController(VRCAvatarDescriptor.AnimLayerType.Action);
public AacFlLayer CreateMainIdleLayer() => DoCreateMainLayerOnController(VRCAvatarDescriptor.AnimLayerType.Additive);
public AacFlLayer CreateMainLocomotionLayer() => DoCreateMainLayerOnController(VRCAvatarDescriptor.AnimLayerType.Base);
public AacFlLayer CreateMainAv3Layer(VRCAvatarDescriptor.AnimLayerType animLayerType) => DoCreateMainLayerOnController(animLayerType);
public AacFlLayer CreateSupportingFxLayer(string suffix) => DoCreateSupportingLayerOnController(VRCAvatarDescriptor.AnimLayerType.FX, suffix);
public AacFlLayer CreateSupportingGestureLayer(string suffix) => DoCreateSupportingLayerOnController(VRCAvatarDescriptor.AnimLayerType.Gesture, suffix);
public AacFlLayer CreateSupportingActionLayer(string suffix) => DoCreateSupportingLayerOnController(VRCAvatarDescriptor.AnimLayerType.Action, suffix);
public AacFlLayer CreateSupportingIdleLayer(string suffix) => DoCreateSupportingLayerOnController(VRCAvatarDescriptor.AnimLayerType.Additive, suffix);
public AacFlLayer CreateSupportingLocomotionLayer(string suffix) => DoCreateSupportingLayerOnController(VRCAvatarDescriptor.AnimLayerType.Base, suffix);
public AacFlLayer CreateSupportingAv3Layer(VRCAvatarDescriptor.AnimLayerType animLayerType, string suffix) => DoCreateSupportingLayerOnController(animLayerType, suffix);
public AacFlLayer CreateMainArbitraryControllerLayer(AnimatorController controller) => DoCreateLayer(controller, _configuration.DefaultsProvider.ConvertLayerName(_configuration.SystemName));
public AacFlLayer CreateSupportingArbitraryControllerLayer(AnimatorController controller, string suffix) => DoCreateLayer(controller, _configuration.DefaultsProvider.ConvertLayerNameWithSuffix(_configuration.SystemName, suffix));
public AacFlLayer CreateFirstArbitraryControllerLayer(AnimatorController controller) => DoCreateLayer(controller, controller.layers[0].name);
private AacFlLayer DoCreateMainLayerOnController(VRCAvatarDescriptor.AnimLayerType animType)
{
var animator = AacV0.AnimatorOf(_configuration.AvatarDescriptor, animType);
var layerName = _configuration.DefaultsProvider.ConvertLayerName(_configuration.SystemName);
return DoCreateLayer(animator, layerName);
}
private AacFlLayer DoCreateSupportingLayerOnController(VRCAvatarDescriptor.AnimLayerType animType, string suffix)
{
var animator = AacV0.AnimatorOf(_configuration.AvatarDescriptor, animType);
var layerName = _configuration.DefaultsProvider.ConvertLayerNameWithSuffix(_configuration.SystemName, suffix);
return DoCreateLayer(animator, layerName);
}
private AacFlLayer DoCreateLayer(AnimatorController animator, string layerName)
{
var ag = new AacAnimatorGenerator(animator, CreateEmptyClip().Clip, _configuration.DefaultsProvider);
var machine = ag.CreateOrClearLayerAtSameIndex(layerName, 1f);
return new AacFlLayer(animator, _configuration, machine, layerName);
}
private AacFlClip CreateEmptyClip()
{
var emptyClip = DummyClipLasting(1, AacFlUnit.Frames);
return emptyClip;
}
public AacVrcAssetLibrary VrcAssets()
{
return new AacVrcAssetLibrary();
}
public void ClearPreviousAssets()
{
var allSubAssets = AssetDatabase.LoadAllAssetsAtPath(AssetDatabase.GetAssetPath(_configuration.AssetContainer));
foreach (var subAsset in allSubAssets)
{
if (subAsset.name.StartsWith($"zAutogenerated__{_configuration.AssetKey}__")
&& (subAsset is AnimationClip || subAsset is BlendTree || subAsset is AvatarMask))
{
AssetDatabase.RemoveObjectFromAsset(subAsset);
}
}
}
}
public class AacAv3
{
private readonly AacBackingAnimator _backingAnimator;
internal AacAv3(AacBackingAnimator backingAnimator)
{
_backingAnimator = backingAnimator;
}
// ReSharper disable InconsistentNaming
public AacFlBoolParameter IsLocal => _backingAnimator.BoolParameter("IsLocal");
public AacFlEnumIntParameter<Av3Viseme> Viseme => _backingAnimator.EnumParameter<Av3Viseme>("Viseme");
public AacFlEnumIntParameter<Av3Gesture> GestureLeft => _backingAnimator.EnumParameter<Av3Gesture>("GestureLeft");
public AacFlEnumIntParameter<Av3Gesture> GestureRight => _backingAnimator.EnumParameter<Av3Gesture>("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
}
}
public class AacVrcAssetLibrary
{
public AvatarMask LeftHandAvatarMask()
{
return AssetDatabase.LoadAssetAtPath<AvatarMask>("Assets/VRCSDK/Examples3/Animation/Masks/vrc_Hand Left.mask");
}
public AvatarMask RightHandAvatarMask()
{
return AssetDatabase.LoadAssetAtPath<AvatarMask>("Assets/VRCSDK/Examples3/Animation/Masks/vrc_Hand Right.mask");
}
public AnimationClip ProxyForGesture(AacAv3.Av3Gesture gesture, bool masculine)
{
return AssetDatabase.LoadAssetAtPath<AnimationClip>("Assets/VRCSDK/Examples3/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);
}
}
}
public class AacAnimatorRemoval
{
private readonly AnimatorController _animatorController;
public AacAnimatorRemoval(AnimatorController animatorController)
{
_animatorController = animatorController;
}
public void RemoveLayer(string layerName)
{
var index = FindIndexOf(layerName);
if (index == -1) return;
_animatorController.RemoveLayer(index);
}
private int FindIndexOf(string layerName)
{
return _animatorController.layers.ToList().FindIndex(layer => layer.name == layerName);
}
}
public class AacAnimatorGenerator
{
private readonly AnimatorController _animatorController;
private readonly AnimationClip _emptyClip;
private readonly IAacDefaultsProvider _defaultsProvider;
internal AacAnimatorGenerator(AnimatorController animatorController, AnimationClip emptyClip, IAacDefaultsProvider defaultsProvider)
{
_animatorController = animatorController;
_emptyClip = emptyClip;
_defaultsProvider = defaultsProvider;
}
internal void CreateParamsAsNeeded(params AacFlParameter[] parameters)
{
foreach (var parameter in parameters)
{
switch (parameter)
{
case AacFlIntParameter _:
CreateParamIfNotExists(parameter.Name, AnimatorControllerParameterType.Int);
break;
case AacFlFloatParameter _:
CreateParamIfNotExists(parameter.Name, AnimatorControllerParameterType.Float);
break;
case AacFlBoolParameter _:
CreateParamIfNotExists(parameter.Name, AnimatorControllerParameterType.Bool);
break;
}
}
}
internal void CreateTriggerParamsAsNeeded(params AacFlBoolParameter[] parameters)
{
foreach (var parameter in parameters)
{
CreateParamIfNotExists(parameter.Name, AnimatorControllerParameterType.Trigger);
}
}
private void CreateParamIfNotExists(string paramName, AnimatorControllerParameterType type)
{
if (_animatorController.parameters.FirstOrDefault(param => param.name == paramName) == null)
{
_animatorController.AddParameter(paramName, type);
}
}
// DEPRECATED: This causes the editor window to glitch by deselecting, which is jarring for experimentation
internal AacStateMachine CreateOrRemakeLayerAtSameIndex(string layerName, float weightWhenCreating, AvatarMask maskWhenCreating = null)
{
var originalIndexToPreserveOrdering = FindIndexOf(layerName);
if (originalIndexToPreserveOrdering != -1)
{
_animatorController.RemoveLayer(originalIndexToPreserveOrdering);
}
AddLayerWithWeight(layerName, weightWhenCreating, maskWhenCreating);
if (originalIndexToPreserveOrdering != -1)
{
var items = _animatorController.layers.ToList();
var last = items[items.Count - 1];
items.RemoveAt(items.Count - 1);
items.Insert(originalIndexToPreserveOrdering, last);
_animatorController.layers = items.ToArray();
}
var layer = TryGetLayer(layerName);
var machinist = new AacStateMachine(layer.stateMachine, _emptyClip, new AacBackingAnimator(this), _defaultsProvider);
return machinist
.WithAnyStatePosition(0, 7)
.WithEntryPosition(0, -1)
.WithExitPosition(7, -1);
}
internal AacStateMachine CreateOrClearLayerAtSameIndex(string layerName, float weightWhenCreating, AvatarMask maskWhenCreating = null)
{
var originalIndexToPreserveOrdering = FindIndexOf(layerName);
if (originalIndexToPreserveOrdering != -1)
{
foreach (var childAnimatorStateMachine in _animatorController.layers[originalIndexToPreserveOrdering].stateMachine.stateMachines)
{
childAnimatorStateMachine.stateMachine.states = new ChildAnimatorState[0];
childAnimatorStateMachine.stateMachine.entryTransitions = new AnimatorTransition[0];
childAnimatorStateMachine.stateMachine.anyStateTransitions = new AnimatorStateTransition[0];
}
_animatorController.layers[originalIndexToPreserveOrdering].stateMachine.stateMachines = new ChildAnimatorStateMachine[0];
_animatorController.layers[originalIndexToPreserveOrdering].stateMachine.states = new ChildAnimatorState[0];
_animatorController.layers[originalIndexToPreserveOrdering].stateMachine.entryTransitions = new AnimatorTransition[0];
_animatorController.layers[originalIndexToPreserveOrdering].stateMachine.anyStateTransitions = new AnimatorStateTransition[0];
}
else
{
_animatorController.AddLayer(_animatorController.MakeUniqueLayerName(layerName));
originalIndexToPreserveOrdering = _animatorController.layers.Length - 1;
}
var layers = _animatorController.layers;
layers[originalIndexToPreserveOrdering].avatarMask = maskWhenCreating;
layers[originalIndexToPreserveOrdering].defaultWeight = weightWhenCreating;
_animatorController.layers = layers;
var layer = TryGetLayer(layerName);
var machinist = new AacStateMachine(layer.stateMachine, _emptyClip, new AacBackingAnimator(this), _defaultsProvider);
return machinist
.WithAnyStatePosition(0, 7)
.WithEntryPosition(0, -1)
.WithExitPosition(7, -1);
}
private int FindIndexOf(string layerName)
{
return _animatorController.layers.ToList().FindIndex(layer1 => layer1.name == layerName);
}
private AnimatorControllerLayer TryGetLayer(string layerName)
{
return _animatorController.layers.FirstOrDefault(it => it.name == layerName);
}
private void AddLayerWithWeight(string layerName, float weightWhenCreating, AvatarMask maskWhenCreating)
{
_animatorController.AddLayer(_animatorController.MakeUniqueLayerName(layerName));
var mutatedLayers = _animatorController.layers;
mutatedLayers[mutatedLayers.Length - 1].defaultWeight = weightWhenCreating;
mutatedLayers[mutatedLayers.Length - 1].avatarMask = maskWhenCreating;
_animatorController.layers = mutatedLayers;
}
}
}