(PACKAGING) Change the folder structure for package format

This commit is contained in:
Haï~
2023-10-02 04:53:27 +02:00
parent 7ab6312160
commit c07e47ca48
60 changed files with 107 additions and 896 deletions
@@ -0,0 +1,34 @@
.idea
Library
UnityPackageManager
Temp
Logs
Packages
ProjectSettings
*.unitypackage
Assets/Plugins
Assets/Scenes
Assets/SerializedUdonPrograms
Assets/Udon
Assets/VRChat Examples
Assets/VRCSDK
Assets/Plugins.meta
Assets/Scenes.meta
Assets/SerializedUdonPrograms.meta
Assets/Udon.meta
Assets/VRChat Examples.meta
Assets/VRCSDK.meta
obj
cfe-project.sln
UnityEditorTests.csproj
VRC.Udon.csproj
VRC.Udon.Editor.csproj
VRC.Udon.Serialization.OdinSerializer.csproj
VRCSDK.ShaderStripping.csproj
Assembly-CSharp.csproj
Assembly-CSharp-Editor.csproj
cfe-project.sln.DotSettings.user
VRC.SDKBase.Editor.BuildPipeline.csproj
VRC.SDKBase.Editor.ShaderStripping.csproj
LICENSE.meta
README.md.meta
@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 539be11e3681218498838a8042383938
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 992235b871999e74492779c2bfe8f958
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,627 @@
using System;
using System.Collections.Generic;
using System.Linq;
using UnityEditor;
using UnityEditor.Animations;
using UnityEngine;
using Object = UnityEngine.Object;
// ReSharper disable once CheckNamespace
namespace AnimatorAsCode.V1
{
public static class AacV1
{
/// Create an Animator As Code (AAC) base.
public static AacFlBase Create(AacConfiguration configuration)
{
return new AacFlBase(configuration);
}
}
public struct AacConfiguration
{
public string SystemName;
// Please consult "https://docs.hai-vr.dev/docs/products/animator-as-code/migrating-v0-to-v1" on how to migrate this property
// public VRCAvatarDescriptor AvatarDescriptor;
public Transform AnimatorRoot;
public Transform DefaultValueRoot;
public AnimatorController AssetContainer;
public string AssetKey;
public IAacDefaultsProvider DefaultsProvider;
public Dictionary<Type, object> AdditionalData; // Nullable
public AacConfiguration WithAdditonalData(Type key, object value)
{
var conf = this;
if (AdditionalData == null) conf.AdditionalData = new Dictionary<Type, object>();
conf.AdditionalData[key] = value;
return conf;
}
public bool TryGetAdditionalData(Type key, out object value)
{
if (AdditionalData != null && AdditionalData.TryGetValue(key, out var result))
{
value = result;
return true;
}
value = null;
return false;
}
}
public class 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;
}
/// Create a new state, initially positioned below the last generated state of this layer.
public AacFlState NewState(string name)
{
var lastState = _stateMachine.LastNodePosition();
var state = _stateMachine.NewState(name, 0, 0).Shift(lastState, 0, 1);
return state;
}
/// Create a new state at a specific position x and y, in grid units. The grid size is defined in the DefaultsProvider of the AacConfiguration of AAC. x positive goes right, y positive goes down.
public AacFlState NewState(string name, int x, int y)
{
return _stateMachine.NewState(name, x, y);
}
/// Create a new SSM, initially positioned below the last generated state of this layer.
public AacFlStateMachine NewSubStateMachine(string name)
{
return _stateMachine.NewSubStateMachine(name);
}
/// Create a new SSM at a specific position `x` and `y`, in grid units. The grid size is defined in the DefaultsProvider of the AacConfiguration of AAC. `x` positive goes right, `y` positive goes down.
public AacFlStateMachine NewSubStateMachine(string name, int x, int y)
{
return _stateMachine.NewSubStateMachine(name, x, y);
}
/// Create a transition from Any to the `destination` state.
public AacFlTransition AnyTransitionsTo(AacFlState destination)
{
return _stateMachine.AnyTransitionsTo(destination);
}
/// Create a transition from Any to the `destination` SSM.
public AacFlTransition AnyTransitionsTo(AacFlStateMachine destination)
{
return _stateMachine.AnyTransitionsTo(destination);
}
// Create a transition from the Entry to the `destination` state.
public AacFlEntryTransition EntryTransitionsTo(AacFlState destination)
{
return _stateMachine.EntryTransitionsTo(destination);
}
// Create a transition from the Entry to the `destination` state machine.
public AacFlEntryTransition EntryTransitionsTo(AacFlStateMachine destination)
{
return _stateMachine.EntryTransitionsTo(destination);
}
/// Create a Bool parameter in the animator.
public AacFlBoolParameter BoolParameter(string parameterName) => _stateMachine.InternalBackingAnimator().BoolParameter(parameterName);
/// Create a Trigger parameter in the animator, but returns a Bool parameter for use in AAC.
public AacFlBoolParameter TriggerParameterAsBool(string parameterName) => _stateMachine.InternalBackingAnimator().TriggerParameter(parameterName);
/// Create a Float parameter in the animator.
public AacFlFloatParameter FloatParameter(string parameterName) => _stateMachine.InternalBackingAnimator().FloatParameter(parameterName);
/// Create an Int parameter in the animator.
public AacFlIntParameter IntParameter(string parameterName) => _stateMachine.InternalBackingAnimator().IntParameter(parameterName);
/// Create multiple Bool parameters in the animator, and returns a group of multiple Bools.
public AacFlBoolParameterGroup BoolParameters(params string[] parameterNames) => _stateMachine.InternalBackingAnimator().BoolParameters(parameterNames);
/// Create multiple Trigger parameters in the animator, but returns a group of multiple Bools for use in AAC.
public AacFlBoolParameterGroup TriggerParametersAsBools(params string[] parameterNames) => _stateMachine.InternalBackingAnimator().TriggerParameters(parameterNames);
/// Create multiple Float parameters in the animator, and returns a group of multiple Floats.
public AacFlFloatParameterGroup FloatParameters(params string[] parameterNames) => _stateMachine.InternalBackingAnimator().FloatParameters(parameterNames);
/// Create multiple Int parameters in the animator, and returns a group of multiple Ints.
public AacFlIntParameterGroup IntParameters(params string[] parameterNames) => _stateMachine.InternalBackingAnimator().IntParameters(parameterNames);
/// Combine multiple Bool parameters into a group.
public AacFlBoolParameterGroup BoolParameters(params AacFlBoolParameter[] parameters) => _stateMachine.InternalBackingAnimator().BoolParameters(parameters);
/// Combine multiple Bool parameters into a group. There is no difference with BoolParameters(...) and is provided only for semantic purposes.
public AacFlBoolParameterGroup TriggerParametersAsBools(params AacFlBoolParameter[] parameters) => _stateMachine.InternalBackingAnimator().TriggerParameters(parameters);
/// Combine multiple Float parameters into a group.
public AacFlFloatParameterGroup FloatParameters(params AacFlFloatParameter[] parameters) => _stateMachine.InternalBackingAnimator().FloatParameters(parameters);
/// Combine multiple Int parameters into a group.
public AacFlIntParameterGroup IntParameters(params AacFlIntParameter[] parameters) => _stateMachine.InternalBackingAnimator().IntParameters(parameters);
/// Set the Bool value of `toBeForced` parameter to `value` in the animator.
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;
}
/// Set the Float value of `toBeForced` parameter to `value` in the animator.
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;
}
/// Set the Int value of `toBeForced` parameter to `value` in the animator.
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;
}
/// Set the Avatar Mask of the layer.
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;
}
/// Set the Avatar Mask of the layer to be an Avatar Mask which denies all transforms. The asset is generated into the container.
public AacFlLayer WithAvatarMaskNoTransforms()
{
ResolveAvatarMask(new Transform[0]);
return this;
}
/// Set the Avatar Mask of the layer to be an Avatar Mask that allows the specified transforms. If `paths` is an empty array, all transforms are denied, which is effectively the same as calling `.WithAvatarMaskNoTransforms()`. The asset is generated into the container.
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, AacInternals.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;
}
/// Set the Default State of the layer.
public AacFlLayer WithDefaultState(AacFlState newDefaultState)
{
_stateMachine.WithDefaultState(newDefaultState);
return this;
}
/// NON-PUBLIC: Internal use only so that extensions can access this. Maybe this can be improved
public AacFlStateMachine InternalStateMachine()
{
return _stateMachine;
}
}
public class AacFlBase
{
private readonly AacConfiguration _configuration;
/// NON-PUBLIC: Internal use only so that destructive workflow can access this. Maybe this can be improved
public AacConfiguration InternalConfiguration()
{
return _configuration;
}
internal AacFlBase(AacConfiguration configuration)
{
_configuration = configuration;
}
/// Create a new clip. The asset is generated into the container.
public AacFlClip NewClip()
{
var clip = AacInternals.NewClip(_configuration, Guid.NewGuid().ToString());
return new AacFlClip(_configuration, clip);
}
/// Create a new clip that is a copy of `originalClip`. The asset is generated into the container.
public AacFlClip CopyClip(AnimationClip originalClip)
{
var newClip = UnityEngine.Object.Instantiate(originalClip);
var clip = AacInternals.RegisterClip(_configuration, Guid.NewGuid().ToString(), newClip);
return new AacFlClip(_configuration, clip);
}
/// Create a new BlendTree asset. The asset is generated into the container.
public AacFlNonInitializedBlendTree NewBlendTree()
{
return new AacFlNonInitializedBlendTree(AacInternals.NewBlendTreeAsRaw(_configuration, Guid.NewGuid().ToString()));
}
/// Create a new BlendTree asset and returns a native BlendTree object. The asset is generated into the container. You may use NewBlendTree() instead to obtain a fluent interface.
public BlendTree NewBlendTreeAsRaw()
{
return AacInternals.NewBlendTreeAsRaw(_configuration, Guid.NewGuid().ToString());
}
/// Create a new clip with a name. However, the name is only used as a suffix for the asset. The asset is generated into the container.
public AacFlClip NewClip(string name)
{
var clip = AacInternals.NewClip(_configuration, name);
return new AacFlClip(_configuration, clip);
}
/// Create a new clip which animates a dummy transform for a specific duration specified in an unit (Frames or Seconds).
public AacFlClip DummyClipLasting(float numberOf, AacFlUnit unit)
{
var dummyClip = AacInternals.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)));
}
/// Duplicate a new asset into the container and return it. For example, use this to create modified material variants. This asset will be removed the same way as other generated assets.
public T DuplicateAsset<T>(T assetToDuplicate) where T : Object
{
return AacInternals.DuplicateAssetIntoContainer(_configuration, assetToDuplicate);
}
// 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.
private AacFlClip AnomalousSingleKeyframeClip()
{
var numberOf = 1f;
var unit = AacFlUnit.Frames;
var dummyClip = AacInternals.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)));
}
/// Create a new animator controller. The asset is generated into the container.
public AacFlController NewAnimatorController()
{
var animatorController = AacInternals.NewAnimatorController(_configuration, Guid.NewGuid().ToString());
return new AacFlController(_configuration, animatorController, this);
}
/// Create a new animator controller with a name. However, the name is only used as a suffix for the asset. The asset is generated into the container.
public AacFlController NewAnimatorController(string name)
{
var animatorController = AacInternals.NewAnimatorController(_configuration, name);
return new AacFlController(_configuration, animatorController, this);
}
//---- ## Destructive workflow
/// Destructive workflow: Create a main layer for an arbitrary AnimatorController, clearing the previous one of the same system. You are not obligated to have a main layer.
public AacFlLayer CreateMainArbitraryControllerLayer(AnimatorController controller) => InternalDoCreateLayer(controller, _configuration.DefaultsProvider.ConvertLayerName(_configuration.SystemName));
/// Destructive workflow: Create a supporting layer for an arbitrary AnimatorController, clearing the previous one of the same system and suffix. You can create multiple supporting layers with different suffixes, and you are not obligated to have a main layer to create a supporting layer.
public AacFlLayer CreateSupportingArbitraryControllerLayer(AnimatorController controller, string suffix) => InternalDoCreateLayer(controller, _configuration.DefaultsProvider.ConvertLayerNameWithSuffix(_configuration.SystemName, suffix));
/// Destructive workflow: Clears the topmost layer of an arbitrary AnimatorController, and returns it.
public AacFlLayer CreateFirstArbitraryControllerLayer(AnimatorController controller) => InternalDoCreateLayer(controller, controller.layers[0].name);
/// NON-PUBLIC: Internal use only so that destructive workflow can access this. Maybe this can be improved
public AacFlLayer InternalDoCreateLayer(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);
}
internal AacFlLayer DoCreateLayerWithoutDeleting(AnimatorController animator, string layerName)
{
var ag = new AacAnimatorGenerator(animator, CreateEmptyClip().Clip, _configuration.DefaultsProvider);
var machine = ag.CreateOrClearLayerAtSameIndex(layerName, 1f, null, false);
return new AacFlLayer(animator, _configuration, machine, layerName);
}
private AacFlClip CreateEmptyClip()
{
var emptyClip = AnomalousSingleKeyframeClip();
return emptyClip;
}
/// Removes all assets from the asset container matching the specified asset key.
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);
}
}
}
/// If you are not creating an animator, this returns an object from which you can obtain animator parameter objects. You should use this class if you are creating BlendTree assets without any animator controllers to back it. Otherwise, it is strongly recommended to obtain animator parameter objects directly from the layer objects instead of using NoAnimator(), as the use of NoAnimator() will not result in the registration of any parameters inside the animator controller.
public AacFlNoAnimator NoAnimator()
{
return new AacFlNoAnimator();
}
}
public class AacFlNoAnimator
{
/// Create a Float parameter, for use without a backing animator.
public AacFlFloatParameter FloatParameter(string parameterName) => AacFlFloatParameter.Internally(parameterName);
/// Create a Int parameter, for use without a backing animator.
public AacFlIntParameter IntParameter(string parameterName) => AacFlIntParameter.Internally(parameterName);
/// Create a Bool parameter, for use without a backing animator.
public AacFlBoolParameter BoolParameter(string parameterName) => AacFlBoolParameter.Internally(parameterName);
}
public class AacFlController
{
public AnimatorController AnimatorController;
private readonly AacConfiguration _configuration;
private readonly AacFlBase _base;
public AacFlController(AacConfiguration configuration, AnimatorController animatorController, AacFlBase originalBase)
{
AnimatorController = animatorController;
_configuration = configuration;
_base = originalBase;
}
public AacFlLayer NewLayer(string suffix) => _base.DoCreateLayerWithoutDeleting(AnimatorController, _configuration.DefaultsProvider.ConvertLayerNameWithSuffix(_configuration.SystemName, suffix));
public AacFlLayer NewLayer() => _base.DoCreateLayerWithoutDeleting(AnimatorController, _configuration.SystemName);
}
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;
AacInternals.NoUndo(_animatorController, () => _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)
{
AacInternals.NoUndo(_animatorController, () => _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)
{
AacInternals.NoUndo(_animatorController, () => _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, bool allowDeletion = true)
{
var originalIndexToPreserveOrdering = FindIndexOf(layerName);
if (originalIndexToPreserveOrdering != -1)
{
if (!allowDeletion)
{
throw new InvalidOperationException($"Cannot create layer with name {layerName} as it already exists. When creating layers using NewAnimatorController, you may only use unique names.");
}
RecursivelyClearChildrenMachines(_animatorController.layers[originalIndexToPreserveOrdering].stateMachine);
_animatorController.layers[originalIndexToPreserveOrdering].stateMachine.stateMachines = new ChildAnimatorStateMachine[0];
_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
{
AacInternals.NoUndo(_animatorController, () => _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);
AacInternals.NoUndo(parentMachine, () => 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)
{
AacInternals.NoUndo(_animatorController, () => _animatorController.AddLayer(_animatorController.MakeUniqueLayerName(layerName)));
var mutatedLayers = _animatorController.layers;
mutatedLayers[mutatedLayers.Length - 1].defaultWeight = weightWhenCreating;
mutatedLayers[mutatedLayers.Length - 1].avatarMask = maskWhenCreating;
_animatorController.layers = mutatedLayers;
}
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 32d38102c095fd942b9ec14bb5f85bb8
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,59 @@
using UnityEngine;
// ReSharper disable once CheckNamespace
namespace AnimatorAsCode.V1
{
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 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.V1
{
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:
@@ -0,0 +1,498 @@
using System;
using System.Collections.Generic;
using System.Linq;
using UnityEditor;
using UnityEngine;
using Object = UnityEngine.Object;
// ReSharper disable once CheckNamespace
namespace AnimatorAsCode.V1
{
public class 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 = AacInternals.Binding(_component, typeof(GameObject), component.transform, "m_IsActive");
AacInternals.SetCurve(Clip, binding, AacInternals.OneFrame(value ? 1f : 0f));
}
return this;
}
public AacFlClip BlendShape(SkinnedMeshRenderer renderer, string blendShapeName, float value)
{
var binding = AacInternals.Binding(_component, typeof(SkinnedMeshRenderer), renderer.transform, $"blendShape.{blendShapeName}");
AacInternals.SetCurve(Clip, binding, AacInternals.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 = AacInternals.Binding(_component, typeof(SkinnedMeshRenderer), component.transform, $"blendShape.{blendShapeName}");
AacInternals.SetCurve(Clip, binding, AacInternals.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)
{
AacInternals.SetCurve(Clip, AacInternals.Binding(_component, typeof(Transform), component.transform, "m_LocalScale.x"), AacInternals.OneFrame(scale.x));
AacInternals.SetCurve(Clip, AacInternals.Binding(_component, typeof(Transform), component.transform, "m_LocalScale.y"), AacInternals.OneFrame(scale.y));
AacInternals.SetCurve(Clip, AacInternals.Binding(_component, typeof(Transform), component.transform, "m_LocalScale.z"), AacInternals.OneFrame(scale.z));
}
return this;
}
public AacFlClip Toggling(GameObject gameObject, bool value)
{
var binding = AacInternals.Binding(_component, typeof(GameObject), gameObject.transform, "m_IsActive");
AacInternals.SetCurve(Clip, binding, AacInternals.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 = AacInternals.Binding(_component, component.GetType(), component.transform, "m_Enabled");
AacInternals.SetCurve(Clip, binding, AacInternals.OneFrame(value ? 1f : 0f));
}
return this;
}
public AacFlClip TogglingComponent(Component component, bool value)
{
var binding = AacInternals.Binding(_component, component.GetType(), component.transform, "m_Enabled");
AacInternals.SetCurve(Clip, binding, AacInternals.OneFrame(value ? 1f : 0f));
return this;
}
public AacFlClip SwappingMaterial(Renderer renderer, int slot, Material material)
{
var binding = AacInternals.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 = AacInternals.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 class 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 = AacInternals.Binding(_component, type, transform, propertyName);
return new AacFlSettingCurve(Clip, new[] {binding});
}
public AacFlSettingCurve Animates(GameObject gameObject)
{
var binding = AacInternals.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 AacFlSettingCurveObjectReference AnimatesObjectReference(Component anyComponent, string property)
{
var binding = Internal_BindingFromComponent(anyComponent, property);
return new AacFlSettingCurveObjectReference(Clip, new[] {binding});
}
public EditorCurveBinding BindingFromComponent(Component anyComponent, string propertyName)
{
return Internal_BindingFromComponent(anyComponent, propertyName);
}
private EditorCurveBinding Internal_BindingFromComponent(Component anyComponent, string propertyName)
{
return AacInternals.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)
{
AacInternals.SetCurve(_clip, binding, AacInternals.OneFrame(desiredValue));
}
}
public void WithFixedSeconds(float seconds, float desiredValue)
{
foreach (var binding in _bindings)
{
AacInternals.SetCurve(_clip, binding, AacInternals.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)
{
AacInternals.SetCurve(_clip, binding, new AnimationCurve(mutatedKeyframes.ToArray()));
}
}
public void WithAnimationCurve(AnimationCurve animationCurve)
{
foreach (var binding in _bindings)
{
AacInternals.SetCurve(_clip, binding, animationCurve);
}
}
}
public class AacFlSettingCurveObjectReference
{
private readonly AnimationClip _clip;
private readonly EditorCurveBinding[] _bindings;
public AacFlSettingCurveObjectReference(AnimationClip clip, EditorCurveBinding[] bindings)
{
_clip = clip;
_bindings = bindings;
}
public void WithOneFrame(Object objectReference)
{
foreach (var binding in _bindings)
{
AnimationUtility.SetObjectReferenceCurve(_clip, binding, new[]
{
new ObjectReferenceKeyframe { time = 0f, value = objectReference },
new ObjectReferenceKeyframe { time = 1/60f, value = objectReference }
});
}
}
}
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)
{
AacInternals.SetCurve(_clip, AacInternals.ToSubBinding(binding, _hdr ? "x" : "r"), AacInternals.OneFrame(desiredValue.r));
AacInternals.SetCurve(_clip, AacInternals.ToSubBinding(binding, _hdr ? "y" : "g"), AacInternals.OneFrame(desiredValue.g));
AacInternals.SetCurve(_clip, AacInternals.ToSubBinding(binding, _hdr ? "z" : "b"), AacInternals.OneFrame(desiredValue.b));
AacInternals.SetCurve(_clip, AacInternals.ToSubBinding(binding, _hdr ? "w" : "a"), AacInternals.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)
{
AacInternals.SetCurve(_clip, AacInternals.ToSubBinding(binding, _hdr ? "x" : "r"), new AnimationCurve(mutatedKeyframesR.ToArray()));
AacInternals.SetCurve(_clip, AacInternals.ToSubBinding(binding, _hdr ? "y" : "g"), new AnimationCurve(mutatedKeyframesG.ToArray()));
AacInternals.SetCurve(_clip, AacInternals.ToSubBinding(binding, _hdr ? "z" : "b"), new AnimationCurve(mutatedKeyframesB.ToArray()));
AacInternals.SetCurve(_clip, AacInternals.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:
@@ -0,0 +1,239 @@
using System;
using System.Linq;
using UnityEditor.Animations;
using UnityEngine;
// ReSharper disable once CheckNamespace
namespace AnimatorAsCode.V1
{
public class AacFlBlendTree
{
protected AacFlBlendTree(BlendTree blendTree)
{
BlendTree = blendTree;
}
public BlendTree BlendTree { get; }
}
public class AacFlNonInitializedBlendTree : AacFlBlendTree
{
public AacFlNonInitializedBlendTree(BlendTree blendTree) : base(blendTree)
{
}
// Define this BlendTree as being FreeformCartesian2D.
public AacFlBlendTree2D FreeformCartesian2D(AacFlFloatParameter parameterX, AacFlFloatParameter parameterY)
{
return New2DBlendTree(parameterX, parameterY, BlendTreeType.FreeformCartesian2D);
}
// Define this BlendTree as being FreeformDirectional2D.
public AacFlBlendTree2D FreeformDirectional2D(AacFlFloatParameter parameterX, AacFlFloatParameter parameterY)
{
return New2DBlendTree(parameterX, parameterY, BlendTreeType.FreeformDirectional2D);
}
// Define this BlendTree as being SimpleDirectional2D.
public AacFlBlendTree2D SimpleDirectional2D(AacFlFloatParameter parameterX, AacFlFloatParameter parameterY)
{
return New2DBlendTree(parameterX, parameterY, BlendTreeType.SimpleDirectional2D);
}
// Define this BlendTree as being Simple1D.
public AacFlBlendTree1D Simple1D(AacFlFloatParameter parameter)
{
BlendTree.blendType = BlendTreeType.Simple1D;
BlendTree.blendParameter = parameter.Name;
BlendTree.useAutomaticThresholds = false;
return new AacFlBlendTree1D(BlendTree);
}
// Define this BlendTree as being Direct.
public AacFlBlendTreeDirect Direct()
{
BlendTree.blendType = BlendTreeType.Direct;
return new AacFlBlendTreeDirect(BlendTree);
}
private AacFlBlendTree2D New2DBlendTree(AacFlFloatParameter parameterX, AacFlFloatParameter parameterY, BlendTreeType blendTreeType)
{
BlendTree.blendType = blendTreeType;
BlendTree.blendParameter = parameterX.Name;
BlendTree.blendParameterY = parameterY.Name;
return new AacFlBlendTree2D(BlendTree);
}
}
public class AacFlBlendTree2D : AacFlBlendTree
{
public AacFlBlendTree2D(BlendTree blendTree) : base(blendTree)
{
}
// Add a BlendTree in the specified coordinates. The last parameter overload is optional: by default, the timeScale is 1, cycle offset is 0, mirror is false.
public AacFlBlendTree2D WithAnimation(AacFlBlendTree blendTree, Vector2 pos, Action<AacFlBlendTreeChildMotion> furtherDefiningChild = null)
{
return WithAnimation(blendTree.BlendTree, pos, furtherDefiningChild);
}
// Add a BlendTree in the specified `x` and `y` coordinates. The last parameter overload is optional: by default, the timeScale is 1, cycle offset is 0, mirror is false.
public AacFlBlendTree2D WithAnimation(AacFlBlendTree blendTree, float x, float y, Action<AacFlBlendTreeChildMotion> furtherDefiningChild = null)
{
return WithAnimation(blendTree.BlendTree, x, y, furtherDefiningChild);
}
// Add a Clip in the specified coordinates. The last parameter overload is optional: by default, the timeScale is 1, cycle offset is 0, mirror is false.
public AacFlBlendTree2D WithAnimation(AacFlClip clip, Vector2 pos, Action<AacFlBlendTreeChildMotion> furtherDefiningChild = null)
{
return WithAnimation(clip.Clip, pos, furtherDefiningChild);
}
// Add a Clip in the specified `x` and `y` coordinates. The last parameter overload is optional: by default, the timeScale is 1, cycle offset is 0, mirror is false.
public AacFlBlendTree2D WithAnimation(AacFlClip clip, float x, float y, Action<AacFlBlendTreeChildMotion> furtherDefiningChild = null)
{
return WithAnimation(clip.Clip, x, y, furtherDefiningChild);
}
// Add a raw motion in the specified coordinates. The last parameter overload is optional: by default, the timeScale is 1, cycle offset is 0, mirror is false.
public AacFlBlendTree2D WithAnimation(Motion motion, Vector2 pos, Action<AacFlBlendTreeChildMotion> furtherDefiningChild = null)
{
return WithAnimation(motion, pos.x, pos.y, furtherDefiningChild);
}
// Add a raw motion in the specified `x` and `y` coordinates. The last parameter overload is optional: by default, the timeScale is 1, cycle offset is 0, mirror is false.
public AacFlBlendTree2D WithAnimation(Motion motion, float x, float y, Action<AacFlBlendTreeChildMotion> furtherDefiningChild = null)
{
var children = BlendTree.children ?? new ChildMotion[0];
var childrenList = children.ToList();
var childMotionModifier = new AacFlBlendTreeChildMotion();
furtherDefiningChild?.Invoke(childMotionModifier);
var newChildMotion = new ChildMotion
{
motion = motion,
position = new Vector2(x, y),
timeScale = childMotionModifier.TimeScale,
mirror = childMotionModifier.Mirror,
cycleOffset = childMotionModifier.CycleOffset
};
childrenList.Add(newChildMotion);
BlendTree.children = childrenList.ToArray();
return this;
}
}
public class AacFlBlendTree1D : AacFlBlendTree
{
public AacFlBlendTree1D(BlendTree blendTree) : base(blendTree)
{
}
// Add a BlendTree in the specified threshold. The last parameter overload is optional: by default, the timeScale is 1, cycle offset is 0, mirror is false.
public AacFlBlendTree1D WithAnimation(AacFlBlendTree blendTree, float threshold, Action<AacFlBlendTreeChildMotion> furtherDefiningChild = null)
{
return WithAnimation(blendTree.BlendTree, threshold, furtherDefiningChild);
}
// Add a Clip in the specified threshold. The last parameter overload is optional: by default, the timeScale is 1, cycle offset is 0, mirror is false.
public AacFlBlendTree1D WithAnimation(AacFlClip clip, float threshold, Action<AacFlBlendTreeChildMotion> furtherDefiningChild = null)
{
return WithAnimation(clip.Clip, threshold, furtherDefiningChild);
}
// Add a raw motion in the specified threshold. The last parameter overload is optional: by default, the timeScale is 1, cycle offset is 0, mirror is false.
public AacFlBlendTree1D WithAnimation(Motion motion, float threshold, Action<AacFlBlendTreeChildMotion> furtherDefiningChild = null)
{
var children = BlendTree.children ?? new ChildMotion[0];
var childrenList = children.ToList();
var childMotionModifier = new AacFlBlendTreeChildMotion();
furtherDefiningChild?.Invoke(childMotionModifier);
childrenList.Add(new ChildMotion
{
motion = motion,
threshold = threshold,
timeScale = childMotionModifier.TimeScale,
mirror = childMotionModifier.Mirror,
cycleOffset = childMotionModifier.CycleOffset
});
BlendTree.children = childrenList.ToArray();
return this;
}
}
public class AacFlBlendTreeDirect : AacFlBlendTree
{
public AacFlBlendTreeDirect(BlendTree blendTree) : base(blendTree)
{
}
// Add a BlendTree driven by the specified parameter. The last parameter overload is optional: by default, the timeScale is 1, cycle offset is 0, mirror is false.
public AacFlBlendTreeDirect WithAnimation(AacFlBlendTree blendTree, AacFlFloatParameter parameter, Action<AacFlBlendTreeChildMotion> furtherDefiningChild = null)
{
return WithAnimation(blendTree.BlendTree, parameter, furtherDefiningChild);
}
// Add a Clip driven by the specified parameter. The last parameter overload is optional: by default, the timeScale is 1, cycle offset is 0, mirror is false.
public AacFlBlendTreeDirect WithAnimation(AacFlClip clip, AacFlFloatParameter parameter, Action<AacFlBlendTreeChildMotion> furtherDefiningChild = null)
{
return WithAnimation(clip.Clip, parameter, furtherDefiningChild);
}
// Add a raw motion driven by the specified parameter. The last parameter overload is optional: by default, the timeScale is 1, cycle offset is 0, mirror is false.
public AacFlBlendTreeDirect WithAnimation(Motion motion, AacFlFloatParameter parameter, Action<AacFlBlendTreeChildMotion> furtherDefiningChild = null)
{
var children = BlendTree.children ?? new ChildMotion[0];
var childrenList = children.ToList();
var childMotionModifier = new AacFlBlendTreeChildMotion();
furtherDefiningChild?.Invoke(childMotionModifier);
childrenList.Add(new ChildMotion
{
motion = motion,
directBlendParameter = parameter.Name,
timeScale = childMotionModifier.TimeScale,
mirror = childMotionModifier.Mirror,
cycleOffset = childMotionModifier.CycleOffset
});
BlendTree.children = childrenList.ToArray();
return this;
}
}
public class AacFlBlendTreeChildMotion
{
internal float TimeScale { get; set; } = 1f;
internal bool Mirror { get; set; }
internal float CycleOffset { get; set; }
/// Set the time scale. The time scale value is 1 by default.
public AacFlBlendTreeChildMotion WithTimeScaleSetTo(float timeScale)
{
TimeScale = timeScale;
return this;
}
/// Set the mirror option. The mirror option value is false by default.
public AacFlBlendTreeChildMotion WithMirrorSetTo(bool mirror)
{
Mirror = mirror;
return this;
}
/// Set the cycle offset. The cycle offset value is 0 by default.
public AacFlBlendTreeChildMotion WithCycleOffsetSetTo(float cycleOffset)
{
CycleOffset = cycleOffset;
return this;
}
}
}
@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 80c6ca79d93446f088d6e7b1bfee5daa
timeCreated: 1694177157
@@ -0,0 +1,256 @@
using System;
using System.Collections.Generic;
using System.Linq;
using UnityEditor.Animations;
using static AnimatorAsCode.V1.AacFlConditionSimple;
using static UnityEditor.Animations.AnimatorConditionMode;
// ReSharper disable once CheckNamespace
namespace AnimatorAsCode.V1
{
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)
{
}
public 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));
public 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));
public 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));
public 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<AacFlFloatParameter> ToList() => _names.Select(AacFlFloatParameter.Internally).ToList();
public IAacFlCondition AreGreaterThan(float other) => ForEach(_names, (name, condition) => condition.Add(name, Greater, other));
public IAacFlCondition AreLessThan(float other) => ForEach(_names, (name, condition) => condition.Add(name, Less, other));
}
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<AacFlIntParameter> ToList() => _names.Select(AacFlIntParameter.Internally).ToList();
public IAacFlCondition AreGreaterThan(float other) => ForEach(_names, (name, condition) => condition.Add(name, Greater, other));
public IAacFlCondition AreLessThan(float other) => ForEach(_names, (name, condition) => condition.Add(name, Less, other));
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:
@@ -0,0 +1,950 @@
using System;
using System.Collections.Generic;
using System.Linq;
using UnityEditor.Animations;
using UnityEngine;
// ReSharper disable once CheckNamespace
namespace AnimatorAsCode.V1
{
public 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>();
}
public AacBackingAnimator InternalBackingAnimator()
{
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 = AacInternals.NoUndo(Machine, () => 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 = AacInternals.NoUndo(Machine, () => 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 AacFlTransition AnyTransitionsTo(AacFlStateMachine 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(AacInternals.NoUndo(ParentMachine.Machine, () => ParentMachine.Machine.AddStateMachineTransition(Machine, destination.State)), ParentMachine.Machine, Machine, destination.State);
}
public AacFlNewTransitionContinuation TransitionsTo(AacFlStateMachine destination)
{
return new AacFlNewTransitionContinuation(AacInternals.NoUndo(ParentMachine.Machine, () => ParentMachine.Machine.AddStateMachineTransition(Machine, destination.Machine)), ParentMachine.Machine, Machine, destination.Machine);
}
public AacFlNewTransitionContinuation Restarts()
{
return new AacFlNewTransitionContinuation(AacInternals.NoUndo(ParentMachine.Machine, () => ParentMachine.Machine.AddStateMachineTransition(Machine, Machine)), ParentMachine.Machine, Machine, Machine);
}
public AacFlNewTransitionContinuation Exits()
{
return new AacFlNewTransitionContinuation(AacInternals.NoUndo(ParentMachine.Machine, () => ParentMachine.Machine.AddStateMachineExitTransition(Machine)), ParentMachine.Machine, Machine, null);
}
private AacFlTransition AnyTransition(AacFlState destination, AnimatorStateMachine animatorStateMachine)
{
return new AacFlTransition(ConfigureTransition(AacInternals.NoUndo(animatorStateMachine, () => animatorStateMachine.AddAnyStateTransition(destination.State))), animatorStateMachine, null, destination.State);
}
private AacFlTransition AnyTransition(AacFlStateMachine destination, AnimatorStateMachine animatorStateMachine)
{
return new AacFlTransition(ConfigureTransition(AacInternals.NoUndo(animatorStateMachine, () => animatorStateMachine.AddAnyStateTransition(destination.Machine))), animatorStateMachine, null, destination.Machine);
}
private AnimatorStateTransition ConfigureTransition(AnimatorStateTransition transition)
{
DefaultsProvider.ConfigureTransition(transition);
return transition;
}
private AacFlEntryTransition EntryTransition(AacFlState destination, AnimatorStateMachine animatorStateMachine)
{
return new AacFlEntryTransition(AacInternals.NoUndo(animatorStateMachine, () => animatorStateMachine.AddEntryTransition(destination.State)), animatorStateMachine, null, destination.State);
}
private AacFlEntryTransition EntryTransition(AacFlStateMachine destination, AnimatorStateMachine animatorStateMachine)
{
return new AacFlEntryTransition(AacInternals.NoUndo(animatorStateMachine, () => 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>()
{
foreach (var behaviour in Machine.behaviours)
if (behaviour is TBehaviour myBehaviour)
return myBehaviour;
return AacInternals.NoUndo(Machine, () => 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 AacFlState WithAnimation(AacFlBlendTree blendTree)
{
State.motion = blendTree.BlendTree;
return this;
}
public AacFlTransition TransitionsTo(AacFlState destination)
{
return new AacFlTransition(ConfigureTransition(AacInternals.NoUndo(State, () => State.AddTransition(destination.State))), _machine, State, destination.State);
}
public AacFlTransition TransitionsTo(AacFlStateMachine destination)
{
return new AacFlTransition(ConfigureTransition(AacInternals.NoUndo(State, () => State.AddTransition(destination.Machine))), _machine, State, destination.Machine);
}
public AacFlTransition TransitionsFromAny()
{
return new AacFlTransition(ConfigureTransition(AacInternals.NoUndo(State, () => _machine.AddAnyStateTransition(State))), _machine, null, State);
}
public AacFlEntryTransition TransitionsFromEntry()
{
return new AacFlEntryTransition(AacInternals.NoUndo(State, () => _machine.AddEntryTransition(State)), _machine, null, State);
}
public AacFlState AutomaticallyMovesTo(AacFlState destination)
{
var transition = ConfigureTransition(AacInternals.NoUndo(State, () => State.AddTransition(destination.State)));
transition.hasExitTime = true;
return this;
}
public AacFlState AutomaticallyMovesTo(AacFlStateMachine destination)
{
var transition = ConfigureTransition(AacInternals.NoUndo(State, () => State.AddTransition(destination.Machine)));
transition.hasExitTime = true;
return this;
}
public AacFlTransition Exits()
{
return new AacFlTransition(ConfigureTransition(AacInternals.NoUndo(State, () => 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>()
{
foreach (var behaviour in State.behaviours)
if (behaviour is TBehaviour myBehaviour)
return myBehaviour;
return AacInternals.NoUndo(State, () => 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)
{
AacInternals.NoUndo(_transition, () => _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 = AacInternals.NoUndo(_machine, () => _machine.AddEntryTransition(state));
else if (_destinationNullableIfExits.TryGetStateMachine(out var stateMachine))
newTransition = AacInternals.NoUndo(_machine, () => _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 = AacInternals.NoUndo(_machine, () => _machine.AddStateMachineExitTransition(stateMachine));
else if (_destinationNullableIfExits.TryGetState(out var destinationState))
newTransition = AacInternals.NoUndo(_machine, () => _machine.AddStateMachineTransition(stateMachine, destinationState));
else if (_destinationNullableIfExits.TryGetStateMachine(out var destinationStateMachine))
newTransition = AacInternals.NoUndo(_machine, () => _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 AacInternals.NoUndo(_machine, () => _machine.AddAnyStateTransition(state));
if (_destinationNullableIfExits.TryGetStateMachine(out stateMachine))
return AacInternals.NoUndo(_machine, () => _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 AacInternals.NoUndo(sourceState, () => sourceState.AddExitTransition());
}
if (_destinationNullableIfExits.TryGetState(out state))
{
return AacInternals.NoUndo(sourceState, () => sourceState.AddTransition(state));
}
if (_destinationNullableIfExits.TryGetStateMachine(out stateMachine))
{
return AacInternals.NoUndo(sourceState, () => 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;
}
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 783d30e64e795b14f899955b9535ecf3
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,141 @@
using System;
using System.Reflection;
using UnityEditor;
using UnityEditor.Animations;
using UnityEngine;
using Object = UnityEngine.Object;
using Random = UnityEngine.Random;
// ReSharper disable once CheckNamespace
namespace AnimatorAsCode.V1
{
internal static class AacInternals
{
internal static AnimatorController NewAnimatorController(AacConfiguration component, string suffix)
{
var animatorController = new AnimatorController();
animatorController.name = "zAutogenerated__" + component.AssetKey + "__" + suffix + "_" + Random.Range(0, Int32.MaxValue); // FIXME animation name conflict
animatorController.hideFlags = HideFlags.None;
if (component.AssetContainer != null) AssetDatabase.AddObjectToAsset(animatorController, component.AssetContainer);
return 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;
if (component.AssetContainer != null) 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;
if (component.AssetContainer != null) AssetDatabase.AddObjectToAsset(clip, component.AssetContainer);
return clip;
}
internal static T DuplicateAssetIntoContainer<T>(AacConfiguration component, T assetToDuplicate) where T : Object
{
var duplicated = (T)Object.Instantiate(assetToDuplicate);
duplicated.name = "zAutogenerated__" + component.AssetKey + "__" + assetToDuplicate.name + "_" + Random.Range(0, Int32.MaxValue); // FIXME animation name conflict
duplicated.hideFlags = HideFlags.None;
if (component.AssetContainer != null) AssetDatabase.AddObjectToAsset(duplicated, component.AssetContainer);
return duplicated;
}
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 void SetCurve(AnimationClip clip, EditorCurveBinding binding, AnimationCurve curve)
{
// https://forum.unity.com/threads/new-animationclip-property-names.367288/#post-2384172
clip.SetCurve(binding.path, binding.type, binding.propertyName, curve);
}
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 (avatar == item)
{
// TODO: Is this correct??
return "";
}
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};
}
internal static void NoUndo<T>(T obj, Action action)
{
try
{
UndoDisable(obj);
action.Invoke();
}
finally
{
UndoEnable(obj);
}
}
internal static TResult NoUndo<T, TResult>(T obj, Func<TResult> action)
{
try
{
UndoDisable(obj);
return action.Invoke();
}
finally
{
UndoEnable(obj);
}
}
private static void UndoDisable<T>(T state)
{
typeof(T)
.GetProperty("pushUndo", BindingFlags.Instance | BindingFlags.NonPublic)
.SetValue(state, false);
}
private static void UndoEnable<T>(T state)
{
typeof(T)
.GetProperty("pushUndo", BindingFlags.Instance | BindingFlags.NonPublic)
.SetValue(state, true);
}
}
}
@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: fffa37ca11924062a8cf4a76d0f607ba
timeCreated: 1694285975
@@ -0,0 +1,15 @@
{
"name": "AnimatorAsCode.V1",
"references": [],
"includePlatforms": [
"Editor"
],
"excludePlatforms": [],
"allowUnsafeCode": false,
"overrideReferences": true,
"precompiledReferences": [],
"autoReferenced": true,
"defineConstraints": [],
"versionDefines": [],
"noEngineReferences": false
}
@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 7b32145194168e0409534fc5052b85ce
AssemblyDefinitionImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,12 @@
{
"name": "dev.hai-vr.animator-as-code.v1",
"displayName": "Animator As Code",
"version": "1.0.9906",
"unity": "2019.4",
"description": "Animator As Code",
"vrchatVersion" : "2022.1.1",
"author" : {
"name" : "Haï~"
},
"url" : "https://docs.hai-vr.dev/docs/products/animator-as-code/functions/vrchat"
}
@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: a9b555d14a3fa1f40ac2ff1a4f6fc407
PackageManifestImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant: