(MIGRATION START) Move all of V0 to V1:

- This commit marks the start of breaking changes
This commit is contained in:
Haï~
2023-10-02 04:47:33 +02:00
parent b1fbb5f4d8
commit 3bfcb763a1
19 changed files with 11 additions and 11 deletions
+685
View File
@@ -0,0 +1,685 @@
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 AacFlStateMachine _stateMachine;
internal AacFlLayer(AnimatorController animatorController, AacConfiguration configuration, AacFlStateMachine stateMachine, string fullLayerName)
{
_animatorController = animatorController;
_configuration = configuration;
_fullLayerName = fullLayerName;
_stateMachine = stateMachine;
}
public AacFlState NewState(string name)
{
var lastState = _stateMachine.LastNodePosition();
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 AacFlStateMachine NewSubStateMachine(string name)
{
return _stateMachine.NewSubStateMachine(name);
}
public AacFlStateMachine NewSubStateMachine(string name, int x, int y)
{
return _stateMachine.NewSubStateMachine(name, x, y);
}
public AacFlTransition AnyTransitionsTo(AacFlState destination)
{
return _stateMachine.AnyTransitionsTo(destination);
}
public AacFlEntryTransition EntryTransitionsTo(AacFlState destination)
{
return _stateMachine.EntryTransitionsTo(destination);
}
public AacFlEntryTransition EntryTransitionsTo(AacFlStateMachine 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 AacFlLayer 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;
return this;
}
public AacFlLayer 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;
return this;
}
public AacFlLayer 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;
return this;
}
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 AacFlLayer WithAvatarMaskNoTransforms()
{
ResolveAvatarMask(new Transform[0]);
return this;
}
public AacFlLayer 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);
return this;
}
public AacFlLayer WithDefaultState(AacFlState newDefaultState)
{
_stateMachine.WithDefaultState(newDefaultState);
return this;
}
}
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)})");
return new AacFlClip(_configuration, dummyClip)
.Animating(clip => clip.Animates("_ignored", typeof(GameObject), "m_IsActive")
.WithUnit(unit, keyframes => keyframes.Constant(0, 0f).Constant(numberOf, 0f)));
}
// For backwards compatibility, generates an animation with 2 keyframes that are at a distance of 1 / 60 of 1 frame,
// that is 1 / 3600 seconds.
// This was due to DummyClipLasting returning a clip with unit conversion applied twice,
// resulting in an "undesired" animation which was functional anyways.
// Since this dummy clip is used internally on all uninitalized states,
// preserve this behaviour so that existing animators don't break due to this change.
protected AacFlClip AnomalousSingleKeyframeClip()
{
var numberOf = 1f;
var unit = AacFlUnit.Frames;
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 = AnomalousSingleKeyframeClip();
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>("Packages/com.vrchat.avatars/Samples/AV3 Demo Assets/Animation/Masks/vrc_Hand Left.mask");
}
public AvatarMask RightHandAvatarMask()
{
return AssetDatabase.LoadAssetAtPath<AvatarMask>("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<AnimationClip>("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);
}
}
}
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 AacFlStateMachine 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 AacFlStateMachine(layer.stateMachine, _emptyClip, new AacBackingAnimator(this), _defaultsProvider);
return machinist
.WithAnyStatePosition(0, 7)
.WithEntryPosition(0, -1)
.WithExitPosition(7, -1);
}
internal AacFlStateMachine CreateOrClearLayerAtSameIndex(string layerName, float weightWhenCreating, AvatarMask maskWhenCreating = null)
{
var originalIndexToPreserveOrdering = FindIndexOf(layerName);
if (originalIndexToPreserveOrdering != -1)
{
RecursivelyClearChildrenMachines(_animatorController.layers[originalIndexToPreserveOrdering].stateMachine);
_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 AacFlStateMachine(layer.stateMachine, _emptyClip, new AacBackingAnimator(this), _defaultsProvider);
_defaultsProvider.ConfigureStateMachine(layer.stateMachine);
return machinist;
}
private void RecursivelyClearChildrenMachines(AnimatorStateMachine parentMachine)
{
// TODO: RemoveStateMachine might already be recursive
foreach (var childStateMachineHolder in parentMachine.stateMachines)
{
RecursivelyClearChildrenMachines(childStateMachineHolder.stateMachine);
parentMachine.RemoveStateMachine(childStateMachineHolder.stateMachine);
}
}
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;
}
}
}
+11
View File
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 32d38102c095fd942b9ec14bb5f85bb8
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
+63
View File
@@ -0,0 +1,63 @@
using System;
using System.Collections.Generic;
using UnityEngine;
// ReSharper disable once CheckNamespace
namespace AnimatorAsCode.V0
{
public abstract class AacAnimatorNode
{
protected internal abstract Vector3 GetPosition();
protected internal abstract void SetPosition(Vector3 position);
}
public abstract class AacAnimatorNode<TNode> : AacAnimatorNode where TNode : AacAnimatorNode<TNode>
{
protected readonly AacFlStateMachine ParentMachine;
protected readonly IAacDefaultsProvider DefaultsProvider;
protected Dictionary<Type, object> behaviorCache = new Dictionary<Type, object>();
protected AacAnimatorNode(AacFlStateMachine parentMachine, IAacDefaultsProvider defaultsProvider)
{
ParentMachine = parentMachine;
DefaultsProvider = defaultsProvider;
}
public TNode LeftOf(AacAnimatorNode otherNode) => MoveNextTo(otherNode, -1, 0);
public TNode RightOf(AacAnimatorNode otherNode) => MoveNextTo(otherNode, 1, 0);
public TNode Over(AacAnimatorNode otherNode) => MoveNextTo(otherNode, 0, -1);
public TNode Under(AacAnimatorNode otherNode) => MoveNextTo(otherNode, 0, 1);
public TNode LeftOf() => MoveNextTo(null, -1, 0);
public TNode RightOf() => MoveNextTo(null, 1, 0);
public TNode Over() => MoveNextTo(null, 0, -1);
public TNode Under() => MoveNextTo(null, 0, 1);
public TNode Shift(AacAnimatorNode otherState, int shiftX, int shiftY) => MoveNextTo(otherState, shiftX, shiftY);
private TNode MoveNextTo(AacAnimatorNode otherStateOrSecondToLastWhenNull, int x, int y)
{
if (otherStateOrSecondToLastWhenNull == null)
{
var siblings = ParentMachine.GetChildNodes();
var other = siblings[siblings.Count - 2];
Shift(other.GetPosition(), x, y);
return (TNode) this;
}
Shift(otherStateOrSecondToLastWhenNull.GetPosition(), x, y);
return (TNode) this;
}
public TNode Shift(Vector3 otherPosition, int shiftX, int shiftY)
{
SetPosition(otherPosition + new Vector3(shiftX * DefaultsProvider.Grid().x, shiftY * DefaultsProvider.Grid().y, 0));
return (TNode) this;
}
public abstract TBehaviour EnsureBehaviour<TBehaviour>() where TBehaviour : StateMachineBehaviour;
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 4f18060d238ee5549aac66b09f36e9e7
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,68 @@
using UnityEditor.Animations;
using UnityEngine;
// ReSharper disable once CheckNamespace
namespace AnimatorAsCode.V0
{
public interface IAacDefaultsProvider
{
void ConfigureState(AnimatorState state, AnimationClip emptyClip);
void ConfigureTransition(AnimatorStateTransition transition);
string ConvertLayerName(string systemName);
string ConvertLayerNameWithSuffix(string systemName, string suffix);
Vector2 Grid();
void ConfigureStateMachine(AnimatorStateMachine stateMachine);
}
public class AacDefaultsProvider : IAacDefaultsProvider
{
private readonly bool _writeDefaults;
public AacDefaultsProvider(bool writeDefaults = false)
{
_writeDefaults = writeDefaults;
}
public virtual void ConfigureState(AnimatorState state, AnimationClip emptyClip)
{
state.motion = emptyClip;
state.writeDefaultValues = _writeDefaults;
}
public virtual void ConfigureTransition(AnimatorStateTransition transition)
{
transition.duration = 0;
transition.hasExitTime = false;
transition.exitTime = 0;
transition.hasFixedDuration = true;
transition.offset = 0;
transition.interruptionSource = TransitionInterruptionSource.None;
transition.orderedInterruption = true;
transition.canTransitionToSelf = false;
}
public virtual string ConvertLayerName(string systemName)
{
return systemName;
}
public virtual string ConvertLayerNameWithSuffix(string systemName, string suffix)
{
return $"{systemName}__{suffix}";
}
public Vector2 Grid()
{
return new Vector2(250, 70);
}
public void ConfigureStateMachine(AnimatorStateMachine stateMachine)
{
var grid = Grid();
stateMachine.anyStatePosition = grid * new Vector2(0, 7);
stateMachine.entryPosition = grid * new Vector2(0, -1);
stateMachine.exitPosition = grid * new Vector2(7, -1);
stateMachine.parentStateMachinePosition = grid * new Vector2(3, -1);
}
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 50ded138f79d4ba4cacd0e924a60f40b
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
+467
View File
@@ -0,0 +1,467 @@
using System;
using System.Collections.Generic;
using System.Linq;
using UnityEditor;
using UnityEngine;
// ReSharper disable once CheckNamespace
namespace AnimatorAsCode.V0
{
public readonly struct AacFlClip
{
private readonly AacConfiguration _component;
public AnimationClip Clip { get; }
public AacFlClip(AacConfiguration component, AnimationClip clip)
{
_component = component;
Clip = clip;
}
public AacFlClip Looping()
{
var settings = AnimationUtility.GetAnimationClipSettings(Clip);
settings.loopTime = true;
AnimationUtility.SetAnimationClipSettings(Clip, settings);
return this;
}
public AacFlClip NonLooping()
{
var settings = AnimationUtility.GetAnimationClipSettings(Clip);
settings.loopTime = false;
AnimationUtility.SetAnimationClipSettings(Clip, settings);
return this;
}
public AacFlClip Animating(Action<AacFlEditClip> action)
{
action.Invoke(new AacFlEditClip(_component, Clip));
return this;
}
public AacFlClip Toggling(GameObject[] gameObjectsWithNulls, bool value)
{
var defensiveObjects = gameObjectsWithNulls.Where(o => o != null); // Allow users to remove an item in the middle of the array
foreach (var component in defensiveObjects)
{
var binding = AacV0.Binding(_component, typeof(GameObject), component.transform, "m_IsActive");
AnimationUtility.SetEditorCurve(Clip, binding, AacV0.OneFrame(value ? 1f : 0f));
}
return this;
}
public AacFlClip BlendShape(SkinnedMeshRenderer renderer, string blendShapeName, float value)
{
var binding = AacV0.Binding(_component, typeof(SkinnedMeshRenderer), renderer.transform, $"blendShape.{blendShapeName}");
AnimationUtility.SetEditorCurve(Clip, binding, AacV0.OneFrame(value));
return this;
}
public AacFlClip BlendShape(SkinnedMeshRenderer[] rendererWithNulls, string blendShapeName, float value)
{
var defensiveObjects = rendererWithNulls.Where(o => o != null); // Allow users to remove an item in the middle of the array
foreach (var component in defensiveObjects)
{
var binding = AacV0.Binding(_component, typeof(SkinnedMeshRenderer), component.transform, $"blendShape.{blendShapeName}");
AnimationUtility.SetEditorCurve(Clip, binding, AacV0.OneFrame(value));
}
return this;
}
public AacFlClip Scaling(GameObject[] gameObjectsWithNulls, Vector3 scale)
{
var defensiveObjects = gameObjectsWithNulls.Where(o => o != null); // Allow users to remove an item in the middle of the array
foreach (var component in defensiveObjects)
{
AnimationUtility.SetEditorCurve(Clip, AacV0.Binding(_component, typeof(Transform), component.transform, "m_LocalScale.x"), AacV0.OneFrame(scale.x));
AnimationUtility.SetEditorCurve(Clip, AacV0.Binding(_component, typeof(Transform), component.transform, "m_LocalScale.y"), AacV0.OneFrame(scale.y));
AnimationUtility.SetEditorCurve(Clip, AacV0.Binding(_component, typeof(Transform), component.transform, "m_LocalScale.z"), AacV0.OneFrame(scale.z));
}
return this;
}
public AacFlClip Toggling(GameObject gameObject, bool value)
{
var binding = AacV0.Binding(_component, typeof(GameObject), gameObject.transform, "m_IsActive");
AnimationUtility.SetEditorCurve(Clip, binding, AacV0.OneFrame(value ? 1f : 0f));
return this;
}
public AacFlClip TogglingComponent(Component[] componentsWithNulls, bool value)
{
var defensiveComponents = componentsWithNulls.Where(o => o != null); // Allow users to remove an item in the middle of the array
foreach (var component in defensiveComponents)
{
var binding = AacV0.Binding(_component, component.GetType(), component.transform, "m_Enabled");
AnimationUtility.SetEditorCurve(Clip, binding, AacV0.OneFrame(value ? 1f : 0f));
}
return this;
}
public AacFlClip TogglingComponent(Component component, bool value)
{
var binding = AacV0.Binding(_component, component.GetType(), component.transform, "m_Enabled");
AnimationUtility.SetEditorCurve(Clip, binding, AacV0.OneFrame(value ? 1f : 0f));
return this;
}
public AacFlClip SwappingMaterial(Renderer renderer, int slot, Material material)
{
var binding = AacV0.Binding(_component, renderer.GetType(), renderer.transform, $"m_Materials.Array.data[{slot}]");
AnimationUtility.SetObjectReferenceCurve(Clip, binding, new[] {
new ObjectReferenceKeyframe { time = 0f, value = material },
new ObjectReferenceKeyframe { time = 1/60f, value = material }
});
return this;
}
public AacFlClip SwappingMaterial(ParticleSystem particleSystem, int slot, Material material)
{
var binding = AacV0.Binding(_component, typeof(ParticleSystemRenderer), particleSystem.transform, $"m_Materials.Array.data[{slot}]");
AnimationUtility.SetObjectReferenceCurve(Clip, binding, new[] {
new ObjectReferenceKeyframe { time = 0f, value = material },
new ObjectReferenceKeyframe { time = 1/60f, value = material }
});
return this;
}
}
public readonly struct AacFlEditClip
{
private readonly AacConfiguration _component;
public AnimationClip Clip { get; }
public AacFlEditClip(AacConfiguration component, AnimationClip clip)
{
_component = component;
Clip = clip;
}
public AacFlSettingCurve Animates(string path, Type type, string propertyName)
{
var binding = new EditorCurveBinding
{
path = path,
type = type,
propertyName = propertyName
};
return new AacFlSettingCurve(Clip, new[] {binding});
}
public AacFlSettingCurve Animates(Transform transform, Type type, string propertyName)
{
var binding = AacV0.Binding(_component, type, transform, propertyName);
return new AacFlSettingCurve(Clip, new[] {binding});
}
public AacFlSettingCurve Animates(GameObject gameObject)
{
var binding = AacV0.Binding(_component, typeof(GameObject), gameObject.transform, "m_IsActive");
return new AacFlSettingCurve(Clip, new[] {binding});
}
public AacFlSettingCurve Animates(Component anyComponent, string property)
{
var binding = Internal_BindingFromComponent(anyComponent, property);
return new AacFlSettingCurve(Clip, new[] {binding});
}
public AacFlSettingCurve Animates(Component[] anyComponents, string property)
{
var that = this;
var bindings = anyComponents
.Select(anyComponent => that.Internal_BindingFromComponent(anyComponent, property))
.ToArray();
return new AacFlSettingCurve(Clip, bindings);
}
public AacFlSettingCurve AnimatesAnimator(AacFlParameter floatParameter)
{
var binding = new EditorCurveBinding
{
path = "",
type = typeof(Animator),
propertyName = floatParameter.Name
};
return new AacFlSettingCurve(Clip, new[] {binding});
}
public AacFlSettingCurveColor AnimatesColor(Component anyComponent, string property)
{
var binding = Internal_BindingFromComponent(anyComponent, property);
return new AacFlSettingCurveColor(Clip, new[] {binding});
}
public AacFlSettingCurveColor AnimatesColor(Component[] anyComponents, string property)
{
var that = this;
var bindings = anyComponents
.Select(anyComponent => that.Internal_BindingFromComponent(anyComponent, property))
.ToArray();
return new AacFlSettingCurveColor(Clip, bindings);
}
public AacFlSettingCurveColor AnimatesHDRColor(Component anyComponent, string property)
{
var binding = Internal_BindingFromComponent(anyComponent, property);
return new AacFlSettingCurveColor(Clip, new[] {binding}, true);
}
public EditorCurveBinding BindingFromComponent(Component anyComponent, string propertyName)
{
return Internal_BindingFromComponent(anyComponent, propertyName);
}
private EditorCurveBinding Internal_BindingFromComponent(Component anyComponent, string propertyName)
{
return AacV0.Binding(_component, anyComponent.GetType(), anyComponent.transform, propertyName);
}
}
public class AacFlSettingCurve
{
private readonly AnimationClip _clip;
private readonly EditorCurveBinding[] _bindings;
public AacFlSettingCurve(AnimationClip clip, EditorCurveBinding[] bindings)
{
_clip = clip;
_bindings = bindings;
}
public void WithOneFrame(float desiredValue)
{
foreach (var binding in _bindings)
{
AnimationUtility.SetEditorCurve(_clip, binding, AacV0.OneFrame(desiredValue));
}
}
public void WithFixedSeconds(float seconds, float desiredValue)
{
foreach (var binding in _bindings)
{
AnimationUtility.SetEditorCurve(_clip, binding, AacV0.ConstantSeconds(seconds, desiredValue));
}
}
public void WithSecondsUnit(Action<AacFlSettingKeyframes> action)
{
InternalWithUnit(AacFlUnit.Seconds, action);
}
public void WithFrameCountUnit(Action<AacFlSettingKeyframes> action)
{
InternalWithUnit(AacFlUnit.Frames, action);
}
public void WithUnit(AacFlUnit unit, Action<AacFlSettingKeyframes> action)
{
InternalWithUnit(unit, action);
}
private void InternalWithUnit(AacFlUnit unit, Action<AacFlSettingKeyframes> action)
{
var mutatedKeyframes = new List<Keyframe>();
var builder = new AacFlSettingKeyframes(unit, mutatedKeyframes);
action.Invoke(builder);
foreach (var binding in _bindings)
{
AnimationUtility.SetEditorCurve(_clip, binding, new AnimationCurve(mutatedKeyframes.ToArray()));
}
}
public void WithAnimationCurve(AnimationCurve animationCurve)
{
foreach (var binding in _bindings)
{
AnimationUtility.SetEditorCurve(_clip, binding, animationCurve);
}
}
}
public class AacFlSettingCurveColor
{
private readonly AnimationClip _clip;
private readonly EditorCurveBinding[] _bindings;
private readonly bool _hdr;
public AacFlSettingCurveColor(AnimationClip clip, EditorCurveBinding[] bindings, bool hdr = false)
{
_clip = clip;
_bindings = bindings;
_hdr = hdr;
}
public void WithOneFrame(Color desiredValue)
{
foreach (var binding in _bindings)
{
AnimationUtility.SetEditorCurve(_clip, AacV0.ToSubBinding(binding, _hdr ? "x" : "r"), AacV0.OneFrame(desiredValue.r));
AnimationUtility.SetEditorCurve(_clip, AacV0.ToSubBinding(binding, _hdr ? "y" : "g"), AacV0.OneFrame(desiredValue.g));
AnimationUtility.SetEditorCurve(_clip, AacV0.ToSubBinding(binding, _hdr ? "z" : "b"), AacV0.OneFrame(desiredValue.b));
AnimationUtility.SetEditorCurve(_clip, AacV0.ToSubBinding(binding, _hdr ? "w" : "a"), AacV0.OneFrame(desiredValue.a));
}
}
public void WithKeyframes(AacFlUnit unit, Action<AacFlSettingKeyframesColor> action)
{
var mutatedKeyframesR = new List<Keyframe>();
var mutatedKeyframesG = new List<Keyframe>();
var mutatedKeyframesB = new List<Keyframe>();
var mutatedKeyframesA = new List<Keyframe>();
var builder = new AacFlSettingKeyframesColor(unit, mutatedKeyframesR, mutatedKeyframesG, mutatedKeyframesB, mutatedKeyframesA);
action.Invoke(builder);
foreach (var binding in _bindings)
{
AnimationUtility.SetEditorCurve(_clip, AacV0.ToSubBinding(binding, _hdr ? "x" : "r"), new AnimationCurve(mutatedKeyframesR.ToArray()));
AnimationUtility.SetEditorCurve(_clip, AacV0.ToSubBinding(binding, _hdr ? "y" : "g"), new AnimationCurve(mutatedKeyframesG.ToArray()));
AnimationUtility.SetEditorCurve(_clip, AacV0.ToSubBinding(binding, _hdr ? "z" : "b"), new AnimationCurve(mutatedKeyframesB.ToArray()));
AnimationUtility.SetEditorCurve(_clip, AacV0.ToSubBinding(binding, _hdr ? "w" : "a"), new AnimationCurve(mutatedKeyframesA.ToArray()));
}
}
}
public class AacFlSettingKeyframes
{
private readonly AacFlUnit _unit;
private readonly List<Keyframe> _mutatedKeyframes;
public AacFlSettingKeyframes(AacFlUnit unit, List<Keyframe> mutatedKeyframes)
{
_unit = unit;
_mutatedKeyframes = mutatedKeyframes;
}
public AacFlSettingKeyframes Easing(float timeInUnit, float value)
{
_mutatedKeyframes.Add(new Keyframe(AsSeconds(timeInUnit), value, 0, 0));
return this;
}
public AacFlSettingKeyframes Constant(float timeInUnit, float value)
{
_mutatedKeyframes.Add(new Keyframe(AsSeconds(timeInUnit), value, 0, float.PositiveInfinity));
return this;
}
public AacFlSettingKeyframes Linear(float timeInUnit, float value)
{
float valueEnd = value;
float valueStart = _mutatedKeyframes.Count == 0 ? value : _mutatedKeyframes.Last().value;
float timeEnd = AsSeconds(timeInUnit);
float timeStart = _mutatedKeyframes.Count == 0 ? value : _mutatedKeyframes.Last().time;
float num = (float) (((double) valueEnd - (double) valueStart) / ((double) timeEnd - (double) timeStart));
// FIXME: This can cause NaN tangents which messes everything
// return new AnimationCurve(new Keyframe[2]
// {
// new Keyframe(timeStart, valueStart, 0.0f, num),
// new Keyframe(timeEnd, valueEnd, num, 0.0f)
// });
if (_mutatedKeyframes.Count > 0)
{
var lastKeyframe = _mutatedKeyframes.Last();
lastKeyframe.outTangent = num;
_mutatedKeyframes[_mutatedKeyframes.Count - 1] = lastKeyframe;
}
_mutatedKeyframes.Add(new Keyframe(AsSeconds(timeInUnit), value, num, 0.0f));
return this;
}
private float AsSeconds(float timeInUnit)
{
switch (_unit)
{
case AacFlUnit.Frames:
return timeInUnit / 60f;
case AacFlUnit.Seconds:
return timeInUnit;
default:
throw new ArgumentOutOfRangeException();
}
}
}
public class AacFlSettingKeyframesColor
{
private AacFlSettingKeyframes _r;
private AacFlSettingKeyframes _g;
private AacFlSettingKeyframes _b;
private AacFlSettingKeyframes _a;
public AacFlSettingKeyframesColor(AacFlUnit unit, List<Keyframe> mutatedKeyframesR, List<Keyframe> mutatedKeyframesG, List<Keyframe> mutatedKeyframesB, List<Keyframe> mutatedKeyframesA)
{
_r = new AacFlSettingKeyframes(unit, mutatedKeyframesR);
_g = new AacFlSettingKeyframes(unit, mutatedKeyframesG);
_b = new AacFlSettingKeyframes(unit, mutatedKeyframesB);
_a = new AacFlSettingKeyframes(unit, mutatedKeyframesA);
}
public AacFlSettingKeyframesColor Easing(int frame, Color value)
{
_r.Easing(frame, value.r);
_g.Easing(frame, value.g);
_b.Easing(frame, value.b);
_a.Easing(frame, value.a);
return this;
}
public AacFlSettingKeyframesColor Linear(float frame, Color value)
{
_r.Linear(frame, value.r);
_g.Linear(frame, value.g);
_b.Linear(frame, value.b);
_a.Linear(frame, value.a);
return this;
}
public AacFlSettingKeyframesColor Constant(int frame, Color value)
{
_r.Constant(frame, value.r);
_g.Constant(frame, value.g);
_b.Constant(frame, value.b);
_a.Constant(frame, value.a);
return this;
}
}
public enum AacFlUnit
{
Frames, Seconds
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 3422c7eab85fed543b3ccc3384e55679
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
+256
View File
@@ -0,0 +1,256 @@
using System;
using System.Collections.Generic;
using System.Linq;
using UnityEditor.Animations;
using static AnimatorAsCode.V0.AacFlConditionSimple;
using static UnityEditor.Animations.AnimatorConditionMode;
// ReSharper disable once CheckNamespace
namespace AnimatorAsCode.V0
{
class AacFlConditionSimple : IAacFlCondition
{
private readonly Action<AacFlCondition> _action;
public AacFlConditionSimple(Action<AacFlCondition> action)
{
_action = action;
}
public static AacFlConditionSimple Just(Action<AacFlCondition> action)
{
return new AacFlConditionSimple(action);
}
public static AacFlConditionSimple ForEach(string[] subjects, Action<string, AacFlCondition> action)
{
return new AacFlConditionSimple(condition =>
{
foreach (var subject in subjects)
{
action.Invoke(subject, condition);
}
});
}
public void ApplyTo(AacFlCondition appender)
{
_action.Invoke(appender);
}
}
public abstract class AacFlParameter
{
public string Name { get; }
protected AacFlParameter(string name)
{
Name = name;
}
}
public abstract class AacFlParameter<TParam> : AacFlParameter
{
protected AacFlParameter(string name) : base(name)
{
}
protected internal abstract float ValueToFloat(TParam value);
}
public abstract class AacFlNumericParameter<TParam> : AacFlParameter<TParam>
{
protected AacFlNumericParameter(string name) : base(name)
{
}
}
public class AacFlFloatParameter : AacFlNumericParameter<float>
{
internal static AacFlFloatParameter Internally(string name) => new AacFlFloatParameter(name);
protected AacFlFloatParameter(string name) : base(name) { }
public IAacFlCondition IsGreaterThan(float other) => Just(condition => condition.Add(Name, Greater, other));
public IAacFlCondition IsLessThan(float other) => Just(condition => condition.Add(Name, Less, other));
protected internal override float ValueToFloat(float value)
{
return value;
}
}
public class AacFlIntParameter : AacFlNumericParameter<int>
{
internal static AacFlIntParameter Internally(string name) => new AacFlIntParameter(name);
protected AacFlIntParameter(string name) : base(name) { }
public IAacFlCondition IsGreaterThan(int other) => Just(condition => condition.Add(Name, Greater, other));
public IAacFlCondition IsLessThan(int other) => Just(condition => condition.Add(Name, Less, other));
public IAacFlCondition IsEqualTo(int other) => Just(condition => condition.Add(Name, AnimatorConditionMode.Equals, other));
public IAacFlCondition IsNotEqualTo(int other) => Just(condition => condition.Add(Name, NotEqual, other));
protected internal override float ValueToFloat(int value)
{
return value;
}
}
public class AacFlEnumIntParameter<TEnum> : AacFlIntParameter where TEnum : Enum
{
internal static AacFlEnumIntParameter<TInEnum> Internally<TInEnum>(string name) where TInEnum : Enum => new AacFlEnumIntParameter<TInEnum>(name);
protected AacFlEnumIntParameter(string name) : base(name)
{
}
public IAacFlCondition IsEqualTo(TEnum other) => IsEqualTo((int)(object)other);
public IAacFlCondition IsNotEqualTo(TEnum other) => IsNotEqualTo((int)(object)other);
}
public class AacFlBoolParameter : AacFlParameter<bool>
{
internal static AacFlBoolParameter Internally(string name) => new AacFlBoolParameter(name);
protected AacFlBoolParameter(string name) : base(name) { }
public IAacFlCondition IsTrue() => Just(condition => condition.Add(Name, If, 0));
public IAacFlCondition IsFalse() => Just(condition => condition.Add(Name, IfNot, 0));
public IAacFlCondition IsEqualTo(bool other) => Just(condition => condition.Add(Name, other ? If : IfNot, 0));
public IAacFlCondition IsNotEqualTo(bool other) => Just(condition => condition.Add(Name, other ? IfNot : If, 0));
protected internal override float ValueToFloat(bool value)
{
return value ? 1f : 0f;
}
}
public class AacFlFloatParameterGroup
{
internal static AacFlFloatParameterGroup Internally(params string[] names) => new AacFlFloatParameterGroup(names);
private readonly string[] _names;
private AacFlFloatParameterGroup(params string[] names) { _names = names; }
public List<AacFlBoolParameter> ToList() => _names.Select(AacFlBoolParameter.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));
}
public class AacFlIntParameterGroup
{
internal static AacFlIntParameterGroup Internally(params string[] names) => new AacFlIntParameterGroup(names);
private readonly string[] _names;
private AacFlIntParameterGroup(params string[] names) { _names = names; }
public List<AacFlBoolParameter> ToList() => _names.Select(AacFlBoolParameter.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));
public IAacFlCondition AreEqualTo(float other) => ForEach(_names, (name, condition) => condition.Add(name, AnimatorConditionMode.Equals, other));
public IAacFlCondition AreNotEqualTo(float other) => ForEach(_names, (name, condition) => condition.Add(name, NotEqual, other));
}
public class AacFlBoolParameterGroup
{
internal static AacFlBoolParameterGroup Internally(params string[] names) => new AacFlBoolParameterGroup(names);
private readonly string[] _names;
private AacFlBoolParameterGroup(params string[] names) { _names = names; }
public List<AacFlBoolParameter> ToList() => _names.Select(AacFlBoolParameter.Internally).ToList();
public IAacFlCondition AreTrue() => ForEach(_names, (name, condition) => condition.Add(name, If, 0));
public IAacFlCondition AreFalse() => ForEach(_names, (name, condition) => condition.Add(name, IfNot, 0));
public IAacFlCondition AreEqualTo(bool other) => ForEach(_names, (name, condition) => condition.Add(name, other ? If : IfNot, 0));
/// is true when all of the following conditions are met:
/// <ul>
/// <li>all of the parameters in the group must be false except for the parameter defined in exceptThisMustBeTrue if it is present in the group.</li>
/// <li>the parameter defined in exceptThisMustBeTrue must be true.</li>
/// </ul>
public IAacFlCondition AreFalseExcept(AacFlBoolParameter exceptThisMustBeTrue)
{
var group = new AacFlBoolParameterGroup(exceptThisMustBeTrue.Name);
return AreFalseExcept(group);
}
public IAacFlCondition AreFalseExcept(params AacFlBoolParameter[] exceptTheseMustBeTrue)
{
var group = new AacFlBoolParameterGroup(exceptTheseMustBeTrue.Select(parameter => parameter.Name).ToArray());
return AreFalseExcept(group);
}
public IAacFlCondition AreFalseExcept(AacFlBoolParameterGroup exceptTheseMustBeTrue) => Just(condition =>
{
foreach (var name in _names.Where(name => !exceptTheseMustBeTrue._names.Contains(name)))
{
condition.Add(name, IfNot, 0);
}
foreach (var name in exceptTheseMustBeTrue._names)
{
condition.Add(name, If, 0);
}
});
public IAacFlCondition AreTrueExcept(AacFlBoolParameter exceptThisMustBeFalse)
{
var group = new AacFlBoolParameterGroup(exceptThisMustBeFalse.Name);
return AreTrueExcept(group);
}
public IAacFlCondition AreTrueExcept(params AacFlBoolParameter[] exceptTheseMustBeFalse)
{
var group = new AacFlBoolParameterGroup(exceptTheseMustBeFalse.Select(parameter => parameter.Name).ToArray());
return AreTrueExcept(group);
}
public IAacFlCondition AreTrueExcept(AacFlBoolParameterGroup exceptTheseMustBeFalse) => Just(condition =>
{
foreach (var name in _names.Where(name => !exceptTheseMustBeFalse._names.Contains(name)))
{
condition.Add(name, If, 0);
}
foreach (var name in exceptTheseMustBeFalse._names)
{
condition.Add(name, IfNot, 0);
}
});
public IAacFlOrCondition IsAnyTrue()
{
return IsAnyEqualTo(true);
}
public IAacFlOrCondition IsAnyFalse()
{
return IsAnyEqualTo(false);
}
private IAacFlOrCondition IsAnyEqualTo(bool value)
{
return new AacFlBoolParameterIsAnyOrCondition(_names, value);
}
}
internal class AacFlBoolParameterIsAnyOrCondition : IAacFlOrCondition
{
private readonly string[] _names;
private readonly bool _value;
public AacFlBoolParameterIsAnyOrCondition(string[] names, bool value)
{
_names = names;
_value = value;
}
public List<AacFlTransitionContinuation> ApplyTo(AacFlNewTransitionContinuation firstContinuation)
{
var pendingContinuations = new List<AacFlTransitionContinuation>();
var newContinuation = firstContinuation;
for (var index = 0; index < _names.Length; index++)
{
var name = _names[index];
var pendingContinuation = newContinuation.When(AacFlBoolParameter.Internally(name).IsEqualTo(_value));
pendingContinuations.Add(pendingContinuation);
if (index < _names.Length - 1)
{
newContinuation = pendingContinuation.Or();
}
}
return pendingContinuations;
}
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 13c07dbf6f2170f40ba96e7d47a7f706
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
+937
View File
@@ -0,0 +1,937 @@
using System;
using System.Collections.Generic;
using System.Linq;
using UnityEditor.Animations;
using UnityEngine;
// ReSharper disable once CheckNamespace
namespace AnimatorAsCode.V0
{
internal class AacBackingAnimator
{
private readonly AacAnimatorGenerator _generator;
public AacBackingAnimator(AacAnimatorGenerator animatorGenerator)
{
_generator = animatorGenerator;
}
public AacFlBoolParameter BoolParameter(string parameterName)
{
var result = AacFlBoolParameter.Internally(parameterName);
_generator.CreateParamsAsNeeded(result);
return result;
}
public AacFlBoolParameter TriggerParameter(string parameterName)
{
var result = AacFlBoolParameter.Internally(parameterName);
_generator.CreateTriggerParamsAsNeeded(result);
return result;
}
public AacFlFloatParameter FloatParameter(string parameterName)
{
var result = AacFlFloatParameter.Internally(parameterName);
_generator.CreateParamsAsNeeded(result);
return result;
}
public AacFlIntParameter IntParameter(string parameterName)
{
var result = AacFlIntParameter.Internally(parameterName);
_generator.CreateParamsAsNeeded(result);
return result;
}
public AacFlEnumIntParameter<TEnum> EnumParameter<TEnum>(string parameterName) where TEnum : Enum
{
var result = AacFlEnumIntParameter<TEnum>.Internally<TEnum>(parameterName);
_generator.CreateParamsAsNeeded(result);
return result;
}
public AacFlBoolParameterGroup BoolParameters(params string[] parameterNames)
{
var result = AacFlBoolParameterGroup.Internally(parameterNames);
_generator.CreateParamsAsNeeded(result.ToList().ToArray());
return result;
}
public AacFlBoolParameterGroup TriggerParameters(params string[] parameterNames)
{
var result = AacFlBoolParameterGroup.Internally(parameterNames);
_generator.CreateTriggerParamsAsNeeded(result.ToList().ToArray());
return result;
}
public AacFlFloatParameterGroup FloatParameters(params string[] parameterNames)
{
var result = AacFlFloatParameterGroup.Internally(parameterNames);
_generator.CreateParamsAsNeeded(result.ToList().ToArray());
return result;
}
public AacFlIntParameterGroup IntParameters(params string[] parameterNames)
{
var result = AacFlIntParameterGroup.Internally(parameterNames);
_generator.CreateParamsAsNeeded(result.ToList().ToArray());
return result;
}
public AacFlBoolParameterGroup BoolParameters(params AacFlBoolParameter[] parameters)
{
var result = AacFlBoolParameterGroup.Internally(parameters.Select(parameter => parameter.Name).ToArray());
_generator.CreateParamsAsNeeded(parameters);
return result;
}
public AacFlBoolParameterGroup TriggerParameters(params AacFlBoolParameter[] parameters)
{
var result = AacFlBoolParameterGroup.Internally(parameters.Select(parameter => parameter.Name).ToArray());
_generator.CreateTriggerParamsAsNeeded(parameters);
return result;
}
public AacFlFloatParameterGroup FloatParameters(params AacFlFloatParameter[] parameters)
{
var result = AacFlFloatParameterGroup.Internally(parameters.Select(parameter => parameter.Name).ToArray());
_generator.CreateParamsAsNeeded(parameters);
return result;
}
public AacFlIntParameterGroup IntParameters(params AacFlIntParameter[] parameters)
{
var result = AacFlIntParameterGroup.Internally(parameters.Select(parameter => parameter.Name).ToArray());
_generator.CreateParamsAsNeeded(parameters);
return result;
}
}
public class AacFlStateMachine : AacAnimatorNode<AacFlStateMachine>
{
public readonly AnimatorStateMachine Machine;
private readonly AnimationClip _emptyClip;
private readonly AacBackingAnimator _backingAnimator;
private readonly IAacDefaultsProvider _defaultsProvider;
private readonly float _gridShiftX;
private readonly float _gridShiftY;
private readonly List<AacAnimatorNode> _childNodes;
internal AacFlStateMachine(AnimatorStateMachine machine, AnimationClip emptyClip, AacBackingAnimator backingAnimator, IAacDefaultsProvider defaultsProvider, AacFlStateMachine parent = null)
: base(parent, defaultsProvider)
{
Machine = machine;
_emptyClip = emptyClip;
_backingAnimator = backingAnimator;
_defaultsProvider = defaultsProvider;
var grid = defaultsProvider.Grid();
_gridShiftX = grid.x;
_gridShiftY = grid.y;
_childNodes = new List<AacAnimatorNode>();
}
internal AacBackingAnimator BackingAnimator()
{
return _backingAnimator;
}
public AacFlStateMachine NewSubStateMachine(string name)
{
var lastState = LastNodePosition();
return NewSubStateMachine(name, 0, 0).Shift(lastState, 0, 1);
}
public AacFlStateMachine NewSubStateMachine(string name, int x, int y)
{
var stateMachine = Machine.AddStateMachine(name, GridPosition(x, y));
var aacMachine = new AacFlStateMachine(stateMachine, _emptyClip, _backingAnimator, DefaultsProvider, this);
_defaultsProvider.ConfigureStateMachine(stateMachine);
_childNodes.Add(aacMachine);
return aacMachine;
}
public AacFlStateMachine WithEntryPosition(int x, int y)
{
Machine.entryPosition = GridPosition(x, y);
return this;
}
public AacFlStateMachine WithExitPosition(int x, int y)
{
Machine.exitPosition = GridPosition(x, y);
return this;
}
public AacFlStateMachine WithAnyStatePosition(int x, int y)
{
Machine.anyStatePosition = GridPosition(x, y);
return this;
}
public AacFlStateMachine WithParentStateMachinePosition(int x, int y)
{
Machine.parentStateMachinePosition = GridPosition(x, y);
return this;
}
public AacFlState NewState(string name)
{
var lastState = LastNodePosition();
return NewState(name, 0, 0).Shift(lastState, 0, 1);
}
public AacFlState NewState(string name, int x, int y)
{
var state = Machine.AddState(name, GridPosition(x, y));
DefaultsProvider.ConfigureState(state, _emptyClip);
var aacState = new AacFlState(state, this, DefaultsProvider);
_childNodes.Add(aacState);
return aacState;
}
public AacFlTransition AnyTransitionsTo(AacFlState destination)
{
return AnyTransition(destination, Machine);
}
public AacFlEntryTransition EntryTransitionsTo(AacFlState destination)
{
return EntryTransition(destination, Machine);
}
public AacFlEntryTransition EntryTransitionsTo(AacFlStateMachine destination)
{
return EntryTransition(destination, Machine);
}
public AacFlEntryTransition TransitionsFromEntry()
{
return EntryTransition(this, ParentMachine.Machine);
}
public AacFlNewTransitionContinuation TransitionsTo(AacFlState destination)
{
return new AacFlNewTransitionContinuation(ParentMachine.Machine.AddStateMachineTransition(Machine, destination.State), ParentMachine.Machine, Machine, destination.State);
}
public AacFlNewTransitionContinuation TransitionsTo(AacFlStateMachine destination)
{
return new AacFlNewTransitionContinuation(ParentMachine.Machine.AddStateMachineTransition(Machine, destination.Machine), ParentMachine.Machine, Machine, destination.Machine);
}
public AacFlNewTransitionContinuation Restarts()
{
return new AacFlNewTransitionContinuation(ParentMachine.Machine.AddStateMachineTransition(Machine, Machine), ParentMachine.Machine, Machine, Machine);
}
public AacFlNewTransitionContinuation Exits()
{
return new AacFlNewTransitionContinuation(ParentMachine.Machine.AddStateMachineExitTransition(Machine), ParentMachine.Machine, Machine, null);
}
private AacFlTransition AnyTransition(AacFlState destination, AnimatorStateMachine animatorStateMachine)
{
return new AacFlTransition(ConfigureTransition(animatorStateMachine.AddAnyStateTransition(destination.State)), animatorStateMachine, null, destination.State);
}
private AnimatorStateTransition ConfigureTransition(AnimatorStateTransition transition)
{
DefaultsProvider.ConfigureTransition(transition);
return transition;
}
private AacFlEntryTransition EntryTransition(AacFlState destination, AnimatorStateMachine animatorStateMachine)
{
return new AacFlEntryTransition(animatorStateMachine.AddEntryTransition(destination.State), animatorStateMachine, null, destination.State);
}
private AacFlEntryTransition EntryTransition(AacFlStateMachine destination, AnimatorStateMachine animatorStateMachine)
{
return new AacFlEntryTransition(animatorStateMachine.AddEntryTransition(destination.Machine), animatorStateMachine, null, destination.Machine);
}
internal Vector3 LastNodePosition()
{
return _childNodes.LastOrDefault()?.GetPosition() ?? Vector3.right * _gridShiftX * 2;
}
private Vector3 GridPosition(int x, int y)
{
return new Vector3(x * _gridShiftX, y * _gridShiftY, 0);
}
internal IReadOnlyList<AacAnimatorNode> GetChildNodes()
{
return _childNodes;
}
protected internal override Vector3 GetPosition()
{
return ParentMachine.Machine.stateMachines.First(x => x.stateMachine == Machine).position;
}
protected internal override void SetPosition(Vector3 position)
{
var stateMachines = ParentMachine.Machine.stateMachines;
for (var i = 0; i < stateMachines.Length; i++)
{
var m = stateMachines[i];
if (m.stateMachine == Machine)
{
m.position = position;
stateMachines[i] = m;
break;
}
}
ParentMachine.Machine.stateMachines = stateMachines;
}
public AacFlStateMachine WithDefaultState(AacFlState newDefaultState)
{
Machine.defaultState = newDefaultState.State;
return this;
}
public override TBehaviour EnsureBehaviour<TBehaviour>()
{
if (behaviorCache.TryGetValue(typeof(TBehaviour), out var existingBehavior))
return (TBehaviour)existingBehavior;
foreach (var behaviour in Machine.behaviours)
if (behaviour is TBehaviour myBehaviour)
return myBehaviour;
return Machine.AddStateMachineBehaviour<TBehaviour>();
}
}
public class AacFlState : AacAnimatorNode<AacFlState>
{
public readonly AnimatorState State;
private readonly AnimatorStateMachine _machine;
public AacFlState(AnimatorState state, AacFlStateMachine parentMachine, IAacDefaultsProvider defaultsProvider) : base(parentMachine, defaultsProvider)
{
State = state;
_machine = parentMachine.Machine;
}
public AacFlState WithAnimation(Motion clip)
{
State.motion = clip;
return this;
}
public AacFlState WithAnimation(AacFlClip clip)
{
State.motion = clip.Clip;
return this;
}
public AacFlTransition TransitionsTo(AacFlState destination)
{
return new AacFlTransition(ConfigureTransition(State.AddTransition(destination.State)), _machine, State, destination.State);
}
public AacFlTransition TransitionsTo(AacFlStateMachine destination)
{
return new AacFlTransition(ConfigureTransition(State.AddTransition(destination.Machine)), _machine, State, destination.Machine);
}
public AacFlTransition TransitionsFromAny()
{
return new AacFlTransition(ConfigureTransition(_machine.AddAnyStateTransition(State)), _machine, null, State);
}
public AacFlEntryTransition TransitionsFromEntry()
{
return new AacFlEntryTransition(_machine.AddEntryTransition(State), _machine, null, State);
}
public AacFlState AutomaticallyMovesTo(AacFlState destination)
{
var transition = ConfigureTransition(State.AddTransition(destination.State));
transition.hasExitTime = true;
return this;
}
public AacFlState AutomaticallyMovesTo(AacFlStateMachine destination)
{
var transition = ConfigureTransition(State.AddTransition(destination.Machine));
transition.hasExitTime = true;
return this;
}
public AacFlTransition Exits()
{
return new AacFlTransition(ConfigureTransition(State.AddExitTransition()), _machine, State, null);
}
private AnimatorStateTransition ConfigureTransition(AnimatorStateTransition transition)
{
DefaultsProvider.ConfigureTransition(transition);
return transition;
}
public AacFlState WithWriteDefaultsSetTo(bool shouldWriteDefaults)
{
State.writeDefaultValues = shouldWriteDefaults;
return this;
}
public AacFlState MotionTime(AacFlFloatParameter floatParam)
{
State.timeParameterActive = true;
State.timeParameter = floatParam.Name;
return this;
}
public AacFlState WithCycleOffset(AacFlFloatParameter floatParam)
{
State.cycleOffsetParameterActive = false;
State.cycleOffsetParameter = floatParam.Name;
return this;
}
public AacFlState WithCycleOffsetSetTo(float cycleOffset)
{
State.cycleOffsetParameterActive = false;
State.cycleOffset = cycleOffset;
return this;
}
public AacFlState WithSpeed(AacFlFloatParameter parameter)
{
State.speedParameterActive = true;
State.speedParameter = parameter.Name;
return this;
}
public AacFlState WithSpeedSetTo(float speed)
{
State.speedParameterActive = false;
State.speed = speed;
return this;
}
protected internal override Vector3 GetPosition()
{
return _machine.states.First(x => x.state == State).position;
}
protected internal override void SetPosition(Vector3 position)
{
var states = _machine.states;
for (var i = 0; i < states.Length; i++)
{
var m = states[i];
if (m.state == State)
{
m.position = position;
states[i] = m;
break;
}
}
_machine.states = states;
}
public override TBehaviour EnsureBehaviour<TBehaviour>()
{
if (behaviorCache.TryGetValue(typeof(TBehaviour), out var existingBehavior))
return (TBehaviour)existingBehavior;
foreach (var behaviour in State.behaviours)
if (behaviour is TBehaviour myBehaviour)
return myBehaviour;
return State.AddStateMachineBehaviour<TBehaviour>();
}
}
public class AacFlTransition : AacFlNewTransitionContinuation
{
private readonly AnimatorStateTransition _transition;
public AacFlTransition(AnimatorStateTransition transition, AnimatorStateMachine machine, AacTransitionEndpoint sourceNullableIfAny, AacTransitionEndpoint destinationNullableIfExits) : base(transition, machine, sourceNullableIfAny, destinationNullableIfExits)
{
_transition = transition;
}
public AacFlTransition WithSourceInterruption()
{
_transition.interruptionSource = TransitionInterruptionSource.Source;
return this;
}
public AacFlTransition WithInterruption(TransitionInterruptionSource interruptionSource)
{
_transition.interruptionSource = interruptionSource;
return this;
}
public AacFlTransition WithTransitionDurationSeconds(float transitionDuration)
{
_transition.duration = transitionDuration;
return this;
}
public AacFlTransition WithOrderedInterruption()
{
_transition.orderedInterruption = true;
return this;
}
public AacFlTransition WithNoOrderedInterruption()
{
_transition.orderedInterruption = false;
return this;
}
public AacFlTransition WithTransitionToSelf()
{
_transition.canTransitionToSelf = true;
return this;
}
public AacFlTransition WithNoTransitionToSelf()
{
_transition.canTransitionToSelf = false;
return this;
}
public AacFlTransition AfterAnimationFinishes()
{
_transition.hasExitTime = true;
_transition.exitTime = 1;
return this;
}
public AacFlTransition Automatically()
{
_transition.hasExitTime = true;
_transition.exitTime = 0;
return this;
}
public AacFlTransition AfterAnimationIsAtLeastAtPercent(float exitTimeNormalized)
{
_transition.hasExitTime = true;
_transition.exitTime = exitTimeNormalized;
return this;
}
public AacFlTransition WithTransitionDurationPercent(float transitionDurationNormalized)
{
_transition.hasFixedDuration = false;
_transition.duration = transitionDurationNormalized;
return this;
}
}
public class AacFlEntryTransition : AacFlNewTransitionContinuation
{
public AacFlEntryTransition(AnimatorTransition transition, AnimatorStateMachine machine, AnimatorState sourceNullableIfAny, AacTransitionEndpoint destinationNullableIfExits) : base(transition, machine, sourceNullableIfAny, destinationNullableIfExits)
{
}
}
public interface IAacFlCondition
{
void ApplyTo(AacFlCondition appender);
}
public interface IAacFlOrCondition
{
List<AacFlTransitionContinuation> ApplyTo(AacFlNewTransitionContinuation firstContinuation);
}
public class AacFlCondition
{
private readonly AnimatorTransitionBase _transition;
public AacFlCondition(AnimatorTransitionBase transition)
{
_transition = transition;
}
public AacFlCondition Add(string parameter, AnimatorConditionMode mode, float threshold)
{
_transition.AddCondition(mode, threshold, parameter);
return this;
}
}
public class AacFlNewTransitionContinuation
{
public readonly AnimatorTransitionBase Transition;
private readonly AnimatorStateMachine _machine;
private readonly AacTransitionEndpoint _sourceNullableIfAny;
private readonly AacTransitionEndpoint _destinationNullableIfExits;
public AacFlNewTransitionContinuation(AnimatorTransitionBase transition, AnimatorStateMachine machine, AacTransitionEndpoint sourceNullableIfAny, AacTransitionEndpoint destinationNullableIfExits)
{
Transition = transition;
_machine = machine;
_sourceNullableIfAny = sourceNullableIfAny;
_destinationNullableIfExits = destinationNullableIfExits;
}
/// Adds a condition to the transition.
///
/// The settings of the transition can no longer be modified after this point.
/// <example>
/// <code>
/// .When(_aac.BoolParameter(my.myBoolParameterName).IsTrue())
/// .And(_aac.BoolParameter(my.myIntParameterName).IsGreaterThan(2))
/// .And(AacAv3.ItIsLocal())
/// .Or()
/// .When(_aac.BoolParameters(
/// my.myBoolParameterName,
/// my.myOtherBoolParameterName
/// ).AreTrue())
/// .And(AacAv3.ItIsRemote());
/// </code>
/// </example>
public AacFlTransitionContinuation When(IAacFlCondition action)
{
action.ApplyTo(new AacFlCondition(Transition));
return AsContinuationWithOr();
}
/// <summary>
/// Applies a series of conditions to this transition, but this series of conditions cannot include an Or operator.
/// </summary>
/// <param name="actionsWithoutOr"></param>
/// <returns></returns>
public AacFlTransitionContinuation When(Action<AacFlTransitionContinuationWithoutOr> actionsWithoutOr)
{
actionsWithoutOr(new AacFlTransitionContinuationWithoutOr(Transition));
return AsContinuationWithOr();
}
/// <summary>
/// Applies a series of conditions, and this series may contain Or operators. However, the result can not be followed by an And operator. It can only be an Or operator.
/// </summary>
/// <param name="actionsWithOr"></param>
/// <returns></returns>
public AacFlTransitionContinuationOnlyOr When(Action<AacFlNewTransitionContinuation> actionsWithOr)
{
actionsWithOr(this);
return AsContinuationOnlyOr();
}
/// <summary>
/// Applies a series of conditions, and this series may contain Or operators. All And operators that follow will apply to all the conditions generated by this series, until the next Or operator.
/// </summary>
/// <param name="actionsWithOr"></param>
/// <returns></returns>
public AacFlMultiTransitionContinuation When(IAacFlOrCondition actionsWithOr)
{
var pendingContinuations = actionsWithOr.ApplyTo(this);
return new AacFlMultiTransitionContinuation(Transition, _machine, _sourceNullableIfAny, _destinationNullableIfExits, pendingContinuations);
}
public AacFlTransitionContinuation WhenConditions()
{
return AsContinuationWithOr();
}
private AacFlTransitionContinuation AsContinuationWithOr()
{
return new AacFlTransitionContinuation(Transition, _machine, _sourceNullableIfAny, _destinationNullableIfExits);
}
private AacFlTransitionContinuationOnlyOr AsContinuationOnlyOr()
{
return new AacFlTransitionContinuationOnlyOr(Transition, _machine, _sourceNullableIfAny, _destinationNullableIfExits);
}
}
public class AacFlTransitionContinuation : AacFlTransitionContinuationAbstractWithOr
{
public AacFlTransitionContinuation(AnimatorTransitionBase transition, AnimatorStateMachine machine, AacTransitionEndpoint sourceNullableIfAny, AacTransitionEndpoint destinationNullableIfExits) : base(transition, machine, sourceNullableIfAny, destinationNullableIfExits)
{
}
/// Adds an additional condition to the transition that requires all preceding conditions to be true.
/// <example>
/// <code>
/// .When(_aac.BoolParameter(my.myBoolParameterName).IsTrue())
/// .And(_aac.BoolParameter(my.myIntParameterName).IsGreaterThan(2))
/// .And(AacAv3.ItIsLocal())
/// .Or()
/// .When(_aac.BoolParameters(
/// my.myBoolParameterName,
/// my.myOtherBoolParameterName
/// ).AreTrue())
/// .And(AacAv3.ItIsRemote());
/// </code>
/// </example>
public AacFlTransitionContinuation And(IAacFlCondition action)
{
action.ApplyTo(new AacFlCondition(Transition));
return this;
}
/// <summary>
/// Applies a series of conditions to this transition. The conditions cannot include an Or operator.
/// </summary>
/// <param name="actionsWithoutOr"></param>
/// <returns></returns>
public AacFlTransitionContinuation And(Action<AacFlTransitionContinuationWithoutOr> actionsWithoutOr)
{
actionsWithoutOr(new AacFlTransitionContinuationWithoutOr(Transition));
return this;
}
}
public class AacFlMultiTransitionContinuation : AacFlTransitionContinuationAbstractWithOr
{
private readonly List<AacFlTransitionContinuation> _pendingContinuations;
public AacFlMultiTransitionContinuation(AnimatorTransitionBase transition, AnimatorStateMachine machine, AacTransitionEndpoint sourceNullableIfAny, AacTransitionEndpoint destinationNullableIfExits, List<AacFlTransitionContinuation> pendingContinuations) : base(transition, machine, sourceNullableIfAny, destinationNullableIfExits)
{
_pendingContinuations = pendingContinuations;
}
/// Adds an additional condition to these transitions that requires all preceding conditions to be true.
/// <example>
/// <code>
/// .When(_aac.BoolParameter(my.myBoolParameterName).IsTrue())
/// .And(_aac.BoolParameter(my.myIntParameterName).IsGreaterThan(2))
/// .And(AacAv3.ItIsLocal())
/// .Or()
/// .When(_aac.BoolParameters(
/// my.myBoolParameterName,
/// my.myOtherBoolParameterName
/// ).AreTrue())
/// .And(AacAv3.ItIsRemote());
/// </code>
/// </example>
public AacFlMultiTransitionContinuation And(IAacFlCondition action)
{
foreach (var pendingContinuation in _pendingContinuations)
{
pendingContinuation.And(action);
}
return this;
}
/// <summary>
/// Applies a series of conditions to these transitions. The conditions cannot include an Or operator.
/// </summary>
/// <param name="actionsWithoutOr"></param>
/// <returns></returns>
public AacFlMultiTransitionContinuation And(Action<AacFlTransitionContinuationWithoutOr> actionsWithoutOr)
{
foreach (var pendingContinuation in _pendingContinuations)
{
pendingContinuation.And(actionsWithoutOr);
}
return this;
}
}
public class AacFlTransitionContinuationOnlyOr : AacFlTransitionContinuationAbstractWithOr
{
public AacFlTransitionContinuationOnlyOr(AnimatorTransitionBase transition, AnimatorStateMachine machine, AacTransitionEndpoint sourceNullableIfAny, AacTransitionEndpoint destinationNullableIfExits) : base(transition, machine, sourceNullableIfAny, destinationNullableIfExits)
{
}
}
public abstract class AacFlTransitionContinuationAbstractWithOr
{
protected readonly AnimatorTransitionBase Transition;
private readonly AnimatorStateMachine _machine;
private readonly AacTransitionEndpoint _sourceNullableIfAny;
private readonly AacTransitionEndpoint _destinationNullableIfExits;
public AacFlTransitionContinuationAbstractWithOr(AnimatorTransitionBase transition, AnimatorStateMachine machine, AacTransitionEndpoint sourceNullableIfAny, AacTransitionEndpoint destinationNullableIfExits)
{
Transition = transition;
_machine = machine;
_sourceNullableIfAny = sourceNullableIfAny;
_destinationNullableIfExits = destinationNullableIfExits;
}
/// <summary>
/// Creates a new transition with identical settings but having no conditions defined yet.
/// </summary>
/// <example>
/// <code>
/// .When(_aac.BoolParameter(my.myBoolParameterName).IsTrue())
/// .And(_aac.BoolParameter(my.myIntParameterName).IsGreaterThan(2))
/// .And(AacAv3.ItIsLocal())
/// .Or()
/// .When(_aac.BoolParameters(
/// my.myBoolParameterName,
/// my.myOtherBoolParameterName
/// ).AreTrue())
/// .And(AacAv3.ItIsRemote());
/// </code>
/// </example>
public AacFlNewTransitionContinuation Or()
{
return new AacFlNewTransitionContinuation(NewTransitionFromTemplate(), _machine, _sourceNullableIfAny, _destinationNullableIfExits);
}
private AnimatorTransitionBase NewTransitionFromTemplate()
{
AnimatorTransitionBase newTransition;
if (Transition is AnimatorStateTransition templateStateTransition)
{
var stateTransition = NewTransition();
stateTransition.duration = templateStateTransition.duration;
stateTransition.offset = templateStateTransition.offset;
stateTransition.interruptionSource = templateStateTransition.interruptionSource;
stateTransition.orderedInterruption = templateStateTransition.orderedInterruption;
stateTransition.exitTime = templateStateTransition.exitTime;
stateTransition.hasExitTime = templateStateTransition.hasExitTime;
stateTransition.hasFixedDuration = templateStateTransition.hasFixedDuration;
stateTransition.canTransitionToSelf = templateStateTransition.canTransitionToSelf;
newTransition = stateTransition;
}
else
{
if (_sourceNullableIfAny == null)
{
if (_destinationNullableIfExits.TryGetState(out var state))
newTransition = _machine.AddEntryTransition(state);
else if (_destinationNullableIfExits.TryGetStateMachine(out var stateMachine))
newTransition = _machine.AddEntryTransition(stateMachine);
else
throw new InvalidOperationException("_destinationNullableIfExits is not null but does not contain an AnimatorState or AnimatorStateMachine");
}
// source will never be a state if we're cloning an AnimatorTransition
else if (_sourceNullableIfAny.TryGetStateMachine(out var stateMachine))
{
if (_destinationNullableIfExits == null)
newTransition = _machine.AddStateMachineExitTransition(stateMachine);
else if (_destinationNullableIfExits.TryGetState(out var destinationState))
newTransition = _machine.AddStateMachineTransition(stateMachine, destinationState);
else if (_destinationNullableIfExits.TryGetStateMachine(out var destinationStateMachine))
newTransition = _machine.AddStateMachineTransition(stateMachine, destinationStateMachine);
else
throw new InvalidOperationException("_destinationNullableIfExits is not null but does not contain an AnimatorState or AnimatorStateMachine");
}
else
throw new InvalidOperationException("_sourceNullableIfAny is not null but does not contain an AnimatorStateMachine");
}
return newTransition;
}
private AnimatorStateTransition NewTransition()
{
AnimatorState state;
AnimatorStateMachine stateMachine;
if (_sourceNullableIfAny == null)
{
if (_destinationNullableIfExits.TryGetState(out state))
return _machine.AddAnyStateTransition(state);
if (_destinationNullableIfExits.TryGetStateMachine(out stateMachine))
return _machine.AddAnyStateTransition(stateMachine);
throw new InvalidOperationException("Transition has no source nor destination.");
}
// source will never be a state machine if we're cloning an AnimatorStateTransition
if (_sourceNullableIfAny.TryGetState(out var sourceState))
{
if (_destinationNullableIfExits == null)
{
return sourceState.AddExitTransition();
}
if (_destinationNullableIfExits.TryGetState(out state))
{
return sourceState.AddTransition(state);
}
if (_destinationNullableIfExits.TryGetStateMachine(out stateMachine))
return sourceState.AddTransition(stateMachine);
throw new InvalidOperationException("_destinationNullableIfExits is not null but does not contain an AnimatorState or AnimatorStateMachine");
}
throw new InvalidOperationException("_sourceNullableIfAny is not null but does not contain an AnimatorState");
}
}
public class AacFlTransitionContinuationWithoutOr
{
private readonly AnimatorTransitionBase _transition;
public AacFlTransitionContinuationWithoutOr(AnimatorTransitionBase transition)
{
_transition = transition;
}
public AacFlTransitionContinuationWithoutOr And(IAacFlCondition action)
{
action.ApplyTo(new AacFlCondition(_transition));
return this;
}
/// <summary>
/// Applies a series of conditions to this transition. The conditions cannot include an Or operator.
/// </summary>
/// <param name="action"></param>
/// <returns></returns>
public AacFlTransitionContinuationWithoutOr AndWhenever(Action<AacFlTransitionContinuationWithoutOr> action)
{
action(this);
return this;
}
}
public class AacTransitionEndpoint
{
private readonly AnimatorState _state;
private readonly AnimatorStateMachine _stateMachine;
public AacTransitionEndpoint(AnimatorState state)
{
_state = state;
}
public AacTransitionEndpoint(AnimatorStateMachine stateMachine)
{
_stateMachine = stateMachine;
}
public static implicit operator AacTransitionEndpoint(AnimatorState state)
{
return new AacTransitionEndpoint(state);
}
public static implicit operator AacTransitionEndpoint(AnimatorStateMachine stateMachine)
{
return new AacTransitionEndpoint(stateMachine);
}
public bool TryGetState(out AnimatorState state)
{
state = _state;
return _state != null;
}
public bool TryGetStateMachine(out AnimatorStateMachine stateMachine)
{
stateMachine = _stateMachine;
return _stateMachine != null;
}
}
}
+11
View File
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 783d30e64e795b14f899955b9535ecf3
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
+8
View File
@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: e74e8e407b5c59a4ab34d51e9135e598
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 4f15b08a8b9feec438a880160d34c332
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,16 @@
namespace AnimatorAsCode.V0.Extensions.VRChat
{
public enum TrackingElement
{
Head,
LeftHand,
RightHand,
Hip,
LeftFoot,
RightFoot,
LeftFingers,
RightFingers,
Eyes,
Mouth
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 15a0b71b5f463174a894197698238912
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,337 @@
using System;
using VRC.SDK3.Avatars.Components;
using VRC.SDKBase;
namespace AnimatorAsCode.V0.Extensions.VRChat
{
public static class VRChatExtensions
{
/// <summary>
/// Set <i>parameter</i> to a given <i>value</i>. For unsynced parameters, also see <i>DrivingLocally</i>.
/// </summary>
public static TNode Drives<TNode, TParam>(this TNode node, AacFlParameter<TParam> parameter, TParam value) where TNode : AacAnimatorNode<TNode>
{
var driver = node.EnsureBehaviour<VRCAvatarParameterDriver>();
driver.parameters.Add(new VRC_AvatarParameterDriver.Parameter
{
type = VRC_AvatarParameterDriver.ChangeType.Set,
name = parameter.Name, value = parameter.ValueToFloat(value)
});
return node;
}
/// <summary>
/// Set <i>parameter</i> by increasing its current value by <i>additiveValue</i>.
/// </summary>
public static TNode DrivingIncreases<TNode, TParam>(this TNode node, AacFlNumericParameter<TParam> parameter, TParam additiveValue) where TNode : AacAnimatorNode<TNode>
{
var driver = node.EnsureBehaviour<VRCAvatarParameterDriver>();
driver.parameters.Add(new VRC_AvatarParameterDriver.Parameter
{
type = VRC_AvatarParameterDriver.ChangeType.Add,
name = parameter.Name, value = parameter.ValueToFloat(additiveValue)
});
return node;
}
/// <summary>
/// Set <i>parameter</i> by decreasing its current value by <i>positiveValueToDecreaseBy</i>.
/// </summary>
public static TNode DrivingDecreases<TNode, TParam>(this TNode node, AacFlNumericParameter<TParam> parameter, TParam positiveValueToDecreaseBy) where TNode : AacAnimatorNode<TNode>
{
var driver = node.EnsureBehaviour<VRCAvatarParameterDriver>();
driver.parameters.Add(new VRC_AvatarParameterDriver.Parameter
{
type = VRC_AvatarParameterDriver.ChangeType.Add,
name = parameter.Name,
value = parameter.ValueToFloat(positiveValueToDecreaseBy) * -1
});
return node;
}
/// <summary>
/// Copies <i>sourceParameter</i> to <i>destParameter</i> with the given custom ranges.
/// https://docs.vrchat.com/docs/state-behaviors#copy
/// </summary>
public static TNode DrivingRemaps<TNode, TSource, TDest>(this TNode node, AacFlParameter<TSource> sourceParameter, TSource sourceMin, TSource sourceMax, AacFlParameter<TDest> destParameter, TDest destMin, TDest destMax) where TNode : AacAnimatorNode<TNode>
{
var driver = node.EnsureBehaviour<VRCAvatarParameterDriver>();
driver.EnsureParameter(new VRC_AvatarParameterDriver.Parameter
{
name = destParameter.Name,
type = VRC_AvatarParameterDriver.ChangeType.Copy,
source = sourceParameter.Name,
convertRange = true,
sourceMin = sourceParameter.ValueToFloat(sourceMin),
sourceMax = sourceParameter.ValueToFloat(sourceMax),
destMin = destParameter.ValueToFloat(destMin),
destMax = destParameter.ValueToFloat(destMax)
});
return node;
}
/// <summary>
/// Copies <i>sourceParameter</i> to <i>destParameter</i> with no custom ranges.
/// https://docs.vrchat.com/docs/state-behaviors#copy
/// </summary>
public static TNode DrivingCopies<TNode, TSource, TDest>(this TNode node, AacFlParameter<TSource> sourceParameter, AacFlParameter<TDest> destParameter) where TNode : AacAnimatorNode<TNode>
{
var driver = node.EnsureBehaviour<VRCAvatarParameterDriver>();
driver.EnsureParameter(new VRC_AvatarParameterDriver.Parameter
{
name = destParameter.Name,
type = VRC_AvatarParameterDriver.ChangeType.Copy,
source = sourceParameter.Name,
});
return node;
}
/// <summary>
/// Sets <i>parameter</i> to a random value between <i>min</i> and <i>max</i>.
/// This is only ran for the person wearing the avatar, and usually needs to be backed by a synced variable.
/// https://docs.vrchat.com/docs/state-behaviors#random
/// </summary>
public static TNode DrivingRandomizesLocally<TNode, TParam>(this TNode node, AacFlNumericParameter<TParam> parameter, TParam min, TParam max) where TNode : AacAnimatorNode<TNode>
{
var driver = node.EnsureBehaviour<VRCAvatarParameterDriver>();
driver.parameters.Add(new VRC_AvatarParameterDriver.Parameter
{
type = VRC_AvatarParameterDriver.ChangeType.Random,
name = parameter.Name, valueMin = parameter.ValueToFloat(min), valueMax = parameter.ValueToFloat(max)
});
driver.localOnly = true;
return node;
}
/// <summary>
/// Sets <i>parameter</i> to either true or false, with the given <i>chance</i>.
/// This is only ran for the person wearing the avatar, and usually needs to be backed by a synced variable.
/// https://docs.vrchat.com/docs/state-behaviors#random
/// </summary>
public static TNode DrivingRandomizesLocally<TNode>(this TNode node, AacFlBoolParameter parameter, float chance) where TNode : AacAnimatorNode<TNode>
{
var driver = node.EnsureBehaviour<VRCAvatarParameterDriver>();
driver.parameters.Add(new VRC_AvatarParameterDriver.Parameter
{
type = VRC_AvatarParameterDriver.ChangeType.Random,
name = parameter.Name, chance = chance
});
driver.localOnly = true;
return node;
}
/// <summary>
/// Sets <i>parameter</i> to a random value between <i>min</i> and <i>max</i>.
/// For use with unsynced parameters. <b>Warning: The resulting value will be different for everyone seeing your avatar.</b>
/// https://docs.vrchat.com/docs/state-behaviors#random
/// </summary>
public static TNode DrivingRandomizesUnsynced<TNode, TParam>(this TNode node, AacFlNumericParameter<TParam> parameter, TParam min, TParam max) where TNode : AacAnimatorNode<TNode>
{
var driver = node.EnsureBehaviour<VRCAvatarParameterDriver>();
driver.parameters.Add(new VRC_AvatarParameterDriver.Parameter
{
type = VRC_AvatarParameterDriver.ChangeType.Random,
name = parameter.Name, valueMin = parameter.ValueToFloat(min), valueMax = parameter.ValueToFloat(max)
});
return node;
}
/// <summary>
/// Sets <i>parameter</i> to either true or false, with the given <i>chance</i>.
/// For use with unsynced parameters. <b>Warning: The resulting value will be different for everyone seeing your avatar.</b>
/// https://docs.vrchat.com/docs/state-behaviors#random
/// </summary>
public static TNode DrivingRandomizesUnsynced<TNode>(this TNode node, AacFlBoolParameter parameter, float chance) where TNode : AacAnimatorNode<TNode>
{
var driver = node.EnsureBehaviour<VRCAvatarParameterDriver>();
driver.parameters.Add(new VRC_AvatarParameterDriver.Parameter
{
type = VRC_AvatarParameterDriver.ChangeType.Random,
name = parameter.Name, chance = chance
});
return node;
}
public static TNode Drives<TNode>(this TNode node,AacFlBoolParameterGroup parameters, bool value) where TNode : AacAnimatorNode<TNode>
{
var driver = node.EnsureBehaviour<VRCAvatarParameterDriver>();
foreach (var parameter in parameters.ToList())
{
driver.parameters.Add(new VRC_AvatarParameterDriver.Parameter
{
name = parameter.Name, value = value ? 1 : 0
});
}
return node;
}
/// <summary>
/// Only set this parameter for the person wearing the avatar (recommended for synced parameters).
/// </summary>
public static TNode DrivingLocally<TNode>(this TNode node) where TNode : AacAnimatorNode<TNode>
{
var driver = node.EnsureBehaviour<VRCAvatarParameterDriver>();
driver.localOnly = true;
return node;
}
private static void EnsureParameter(this VRC_AvatarParameterDriver driver, VRC_AvatarParameterDriver.Parameter p)
{
for (var i = 0; i < driver.parameters.Count; i++)
{
if (driver.parameters[i].name != p.name) continue;
driver.parameters[i] = p;
return;
}
driver.parameters.Add(p);
}
public static TNode PrintsToLogUsingTrackingBehaviour<TNode>(this TNode node, string value) where TNode : AacAnimatorNode<TNode>
{
var tracking = node.EnsureBehaviour<VRCAnimatorTrackingControl>();
tracking.debugString = value;
return node;
}
public static TNode TrackingTracks<TNode>(this TNode node, TrackingElement element) where TNode : AacAnimatorNode<TNode>
{
var tracking = node.EnsureBehaviour<VRCAnimatorTrackingControl>();
SettingElementTo(tracking, element, VRC_AnimatorTrackingControl.TrackingType.Tracking);
return node;
}
public static TNode TrackingAnimates<TNode>(this TNode node, TrackingElement element) where TNode : AacAnimatorNode<TNode>
{
var tracking = node.EnsureBehaviour<VRCAnimatorTrackingControl>();
SettingElementTo(tracking, element, VRC_AnimatorTrackingControl.TrackingType.Animation);
return node;
}
public static TNode TrackingSets<TNode>(this TNode node, TrackingElement element, VRC_AnimatorTrackingControl.TrackingType trackingType) where TNode : AacAnimatorNode<TNode>
{
var tracking = node.EnsureBehaviour<VRCAnimatorTrackingControl>();
SettingElementTo(tracking, element, trackingType);
return node;
}
private static void SettingElementTo(VRCAnimatorTrackingControl tracking, TrackingElement element, VRC_AnimatorTrackingControl.TrackingType target)
{
switch (element)
{
case TrackingElement.Head:
tracking.trackingHead = target;
break;
case TrackingElement.LeftHand:
tracking.trackingLeftHand = target;
break;
case TrackingElement.RightHand:
tracking.trackingRightHand = target;
break;
case TrackingElement.Hip:
tracking.trackingHip = target;
break;
case TrackingElement.LeftFoot:
tracking.trackingLeftFoot = target;
break;
case TrackingElement.RightFoot:
tracking.trackingRightFoot = target;
break;
case TrackingElement.LeftFingers:
tracking.trackingLeftFingers = target;
break;
case TrackingElement.RightFingers:
tracking.trackingRightFingers = target;
break;
case TrackingElement.Eyes:
tracking.trackingEyes = target;
break;
case TrackingElement.Mouth:
tracking.trackingMouth = target;
break;
default:
throw new ArgumentOutOfRangeException(nameof(element), element, null);
}
}
public static TNode LocomotionEnabled<TNode>(this TNode node) where TNode : AacAnimatorNode<TNode>
{
var locomotionControl = node.EnsureBehaviour<VRCAnimatorLocomotionControl>();
locomotionControl.disableLocomotion = false;
return node;
}
public static TNode LocomotionDisabled<TNode>(this TNode node) where TNode : AacAnimatorNode<TNode>
{
var locomotionControl = node.EnsureBehaviour<VRCAnimatorLocomotionControl>();
locomotionControl.disableLocomotion = true;
return node;
}
public static TNode PlayableEnables<TNode>(this TNode node, VRC_PlayableLayerControl.BlendableLayer blendable, float blendDurationSeconds = 0f) where TNode : AacAnimatorNode<TNode>
{
var playable = node.EnsureBehaviour<VRCPlayableLayerControl>();
PlayableSets(playable, blendable, blendDurationSeconds, 1.0f);
return node;
}
public static TNode PlayableDisables<TNode>(this TNode node, VRC_PlayableLayerControl.BlendableLayer blendable, float blendDurationSeconds = 0f) where TNode : AacAnimatorNode<TNode>
{
var playable = node.EnsureBehaviour<VRCPlayableLayerControl>();
PlayableSets(playable, blendable, blendDurationSeconds, 0.0f);
return node;
}
private static void PlayableSets(VRCPlayableLayerControl playable, VRC_PlayableLayerControl.BlendableLayer blendable, float blendDurationSeconds, float weight)
{
playable.layer = blendable;
playable.goalWeight = weight;
playable.blendDuration = blendDurationSeconds;
}
public static TNode PoseSpaceEntered<TNode>(this TNode node, float delaySeconds = 0f) where TNode : AacAnimatorNode<TNode>
{
var temporaryPoseSpace = node.EnsureBehaviour<VRCAnimatorTemporaryPoseSpace>();
temporaryPoseSpace.enterPoseSpace = true;
temporaryPoseSpace.fixedDelay = true;
temporaryPoseSpace.delayTime = delaySeconds;
return node;
}
public static TNode PoseSpaceExited<TNode>(this TNode node, float delaySeconds = 0f) where TNode : AacAnimatorNode<TNode>
{
var temporaryPoseSpace = node.EnsureBehaviour<VRCAnimatorTemporaryPoseSpace>();
temporaryPoseSpace.enterPoseSpace = false;
temporaryPoseSpace.fixedDelay = true;
temporaryPoseSpace.delayTime = delaySeconds;
return node;
}
public static TNode PoseSpaceEnteredPercent<TNode>(this TNode node, float delayNormalized) where TNode : AacAnimatorNode<TNode>
{
var temporaryPoseSpace = node.EnsureBehaviour<VRCAnimatorTemporaryPoseSpace>();
temporaryPoseSpace.enterPoseSpace = true;
temporaryPoseSpace.fixedDelay = false;
temporaryPoseSpace.delayTime = delayNormalized;
return node;
}
public static TNode PoseSpaceExitedPercent<TNode>(this TNode node, float delayNormalized) where TNode : AacAnimatorNode<TNode>
{
var temporaryPoseSpace = node.EnsureBehaviour<VRCAnimatorTemporaryPoseSpace>();
temporaryPoseSpace.enterPoseSpace = false;
temporaryPoseSpace.fixedDelay = false;
temporaryPoseSpace.delayTime = delayNormalized;
return node;
}
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 0e70a1df0e55dff4c8b415e82bff7a82
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant: