Add Animator As Code
This commit is contained in:
+34
@@ -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: dd0da3b061b24fdcaa56edcfe0ed41ae
|
||||||
|
folderAsset: yes
|
||||||
|
DefaultImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
@@ -0,0 +1,112 @@
|
|||||||
|
using System;
|
||||||
|
using AnimatorAsCode.V0;
|
||||||
|
using UnityEditor;
|
||||||
|
using UnityEngine;
|
||||||
|
using VRC.SDK3.Avatars.Components;
|
||||||
|
using AnimatorController = UnityEditor.Animations.AnimatorController;
|
||||||
|
|
||||||
|
namespace AnimatorAsCodeFramework.Examples
|
||||||
|
{
|
||||||
|
public static class AacExample
|
||||||
|
{
|
||||||
|
public static TemplateGenOptions Options()
|
||||||
|
{
|
||||||
|
return TemplateGenOptions.Defaults();
|
||||||
|
}
|
||||||
|
|
||||||
|
public struct TemplateGenOptions
|
||||||
|
{
|
||||||
|
public static TemplateGenOptions Defaults()
|
||||||
|
{
|
||||||
|
return new TemplateGenOptions()
|
||||||
|
{
|
||||||
|
WriteDefaults = false
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public TemplateGenOptions WriteDefaultsOff()
|
||||||
|
{
|
||||||
|
WriteDefaults = false;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public TemplateGenOptions WriteDefaultsOn()
|
||||||
|
{
|
||||||
|
WriteDefaults = true;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool WriteDefaults;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void InspectorTemplate(Editor editor, SerializedObject serializedObj, string propName, Action createFn, Action removeFnOptional = null)
|
||||||
|
{
|
||||||
|
var prop = serializedObj.FindProperty(propName);
|
||||||
|
if (prop.stringValue.Trim() == "")
|
||||||
|
{
|
||||||
|
prop.stringValue = GUID.Generate().ToString();
|
||||||
|
serializedObj.ApplyModifiedProperties();
|
||||||
|
}
|
||||||
|
|
||||||
|
editor.DrawDefaultInspector();
|
||||||
|
|
||||||
|
if (GUILayout.Button("Create"))
|
||||||
|
{
|
||||||
|
createFn.Invoke();
|
||||||
|
}
|
||||||
|
if (removeFnOptional != null && GUILayout.Button("Remove"))
|
||||||
|
{
|
||||||
|
removeFnOptional.Invoke();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates an AAC base with default options (write defaults OFF). This function is provided as an example on how to invoke AAC internals.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="systemName">Prefix for layer names</param>
|
||||||
|
/// <param name="avatar">Playable layers of this avatar to modify</param>
|
||||||
|
/// <param name="assetContainer">Animation assets will be generated as sub-assets of that asset container</param>
|
||||||
|
/// <param name="assetKey">Animation assets will be generated with this name in order to clean up previously generated assets of the same system</param>
|
||||||
|
/// <param name="options">Some options, such as whether Write Defaults is ON or OFF</param>
|
||||||
|
/// <returns>The AAC base.</returns>
|
||||||
|
public static AacFlBase AnimatorAsCode(string systemName, VRCAvatarDescriptor avatar, AnimatorController assetContainer, string assetKey)
|
||||||
|
{
|
||||||
|
return AnimatorAsCode(systemName, avatar, assetContainer, assetKey, TemplateGenOptions.Defaults());
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates an AAC base. This function is provided as an example on how to invoke AAC internals.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="systemName">Prefix for layer names</param>
|
||||||
|
/// <param name="avatar">Playable layers of this avatar to modify</param>
|
||||||
|
/// <param name="assetContainer">Animation assets will be generated as sub-assets of that asset container</param>
|
||||||
|
/// <param name="assetKey">Animation assets will be generated with this name in order to clean up previously generated assets of the same system</param>
|
||||||
|
/// <param name="options">Some options, such as whether Write Defaults is ON or OFF</param>
|
||||||
|
/// <returns>The AAC base.</returns>
|
||||||
|
public static AacFlBase AnimatorAsCode(string systemName, VRCAvatarDescriptor avatar, AnimatorController assetContainer, string assetKey, TemplateGenOptions options)
|
||||||
|
{
|
||||||
|
var aac = AacV0.Create(new AacConfiguration
|
||||||
|
{
|
||||||
|
SystemName = systemName,
|
||||||
|
// In the examples, we consider the avatar to be also the animator root.
|
||||||
|
AvatarDescriptor = avatar,
|
||||||
|
// You can set the animator root to be different than the avatar descriptor,
|
||||||
|
// if you want to apply an animator to a different avatar without redefining
|
||||||
|
// all of the game object references which were relative to the original avatar.
|
||||||
|
AnimatorRoot = avatar.transform,
|
||||||
|
// DefaultValueRoot is currently unused in AAC. It is added here preemptively
|
||||||
|
// in order to define an avatar root to sample default values from.
|
||||||
|
// The intent is to allow animators to be created with Write Defaults OFF,
|
||||||
|
// but mimicking the behaviour of Write Defaults ON by automatically
|
||||||
|
// sampling the default value from the scene relative to the transform
|
||||||
|
// defined in DefaultValueRoot.
|
||||||
|
DefaultValueRoot = avatar.transform,
|
||||||
|
AssetContainer = assetContainer,
|
||||||
|
AssetKey = assetKey,
|
||||||
|
DefaultsProvider = new AacDefaultsProvider(writeDefaults: options.WriteDefaults)
|
||||||
|
});
|
||||||
|
aac.ClearPreviousAssets();
|
||||||
|
return aac;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: b6c6740568e64846b6b18720f7315ca4
|
||||||
|
timeCreated: 1645751901
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,8 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: bbcd8ae9108f27f44aacfe48a78785d4
|
||||||
|
NativeFormatImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
mainObjectFileID: 9100000
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
Binary file not shown.
@@ -0,0 +1,92 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: e5874b9d3baa9584c88aae7527592af0
|
||||||
|
TextureImporter:
|
||||||
|
internalIDToNameTable: []
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 11
|
||||||
|
mipmaps:
|
||||||
|
mipMapMode: 0
|
||||||
|
enableMipMap: 1
|
||||||
|
sRGBTexture: 1
|
||||||
|
linearTexture: 0
|
||||||
|
fadeOut: 0
|
||||||
|
borderMipMap: 0
|
||||||
|
mipMapsPreserveCoverage: 0
|
||||||
|
alphaTestReferenceValue: 0.5
|
||||||
|
mipMapFadeDistanceStart: 1
|
||||||
|
mipMapFadeDistanceEnd: 3
|
||||||
|
bumpmap:
|
||||||
|
convertToNormalMap: 0
|
||||||
|
externalNormalMap: 0
|
||||||
|
heightScale: 0.25
|
||||||
|
normalMapFilter: 0
|
||||||
|
isReadable: 0
|
||||||
|
streamingMipmaps: 0
|
||||||
|
streamingMipmapsPriority: 0
|
||||||
|
grayScaleToAlpha: 0
|
||||||
|
generateCubemap: 6
|
||||||
|
cubemapConvolution: 1
|
||||||
|
seamlessCubemap: 1
|
||||||
|
textureFormat: 1
|
||||||
|
maxTextureSize: 2048
|
||||||
|
textureSettings:
|
||||||
|
serializedVersion: 2
|
||||||
|
filterMode: 2
|
||||||
|
aniso: 0
|
||||||
|
mipBias: 0
|
||||||
|
wrapU: 1
|
||||||
|
wrapV: 1
|
||||||
|
wrapW: 1
|
||||||
|
nPOTScale: 1
|
||||||
|
lightmap: 0
|
||||||
|
compressionQuality: 50
|
||||||
|
spriteMode: 0
|
||||||
|
spriteExtrude: 1
|
||||||
|
spriteMeshType: 1
|
||||||
|
alignment: 0
|
||||||
|
spritePivot: {x: 0.5, y: 0.5}
|
||||||
|
spritePixelsToUnits: 100
|
||||||
|
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
|
||||||
|
spriteGenerateFallbackPhysicsShape: 1
|
||||||
|
alphaUsage: 1
|
||||||
|
alphaIsTransparency: 0
|
||||||
|
spriteTessellationDetail: -1
|
||||||
|
textureType: 0
|
||||||
|
textureShape: 2
|
||||||
|
singleChannelComponent: 0
|
||||||
|
maxTextureSizeSet: 0
|
||||||
|
compressionQualitySet: 0
|
||||||
|
textureFormatSet: 0
|
||||||
|
applyGammaDecoding: 0
|
||||||
|
platformSettings:
|
||||||
|
- serializedVersion: 3
|
||||||
|
buildTarget: DefaultTexturePlatform
|
||||||
|
maxTextureSize: 2048
|
||||||
|
resizeAlgorithm: 0
|
||||||
|
textureFormat: -1
|
||||||
|
textureCompression: 1
|
||||||
|
compressionQuality: 100
|
||||||
|
crunchedCompression: 0
|
||||||
|
allowsAlphaSplitting: 0
|
||||||
|
overridden: 0
|
||||||
|
androidETC2FallbackOverride: 0
|
||||||
|
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||||
|
spriteSheet:
|
||||||
|
serializedVersion: 2
|
||||||
|
sprites: []
|
||||||
|
outline: []
|
||||||
|
physicsShape: []
|
||||||
|
bones: []
|
||||||
|
spriteID:
|
||||||
|
internalID: 0
|
||||||
|
vertices: []
|
||||||
|
indices:
|
||||||
|
edges: []
|
||||||
|
weights: []
|
||||||
|
secondaryTextures: []
|
||||||
|
spritePackingTag:
|
||||||
|
pSDRemoveMatte: 0
|
||||||
|
pSDShowRemoveMatteOption: 0
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,8 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 3aab8cb479c1da147b4fec0a8fe34236
|
||||||
|
NativeFormatImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
mainObjectFileID: 9100000
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
@@ -0,0 +1,77 @@
|
|||||||
|
%YAML 1.1
|
||||||
|
%TAG !u! tag:unity3d.com,2011:
|
||||||
|
--- !u!21 &2100000
|
||||||
|
Material:
|
||||||
|
serializedVersion: 6
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
m_Name: AacExampleMaterial
|
||||||
|
m_Shader: {fileID: 46, guid: 0000000000000000f000000000000000, type: 0}
|
||||||
|
m_ShaderKeywords:
|
||||||
|
m_LightmapFlags: 4
|
||||||
|
m_EnableInstancingVariants: 0
|
||||||
|
m_DoubleSidedGI: 0
|
||||||
|
m_CustomRenderQueue: -1
|
||||||
|
stringTagMap: {}
|
||||||
|
disabledShaderPasses: []
|
||||||
|
m_SavedProperties:
|
||||||
|
serializedVersion: 3
|
||||||
|
m_TexEnvs:
|
||||||
|
- _BumpMap:
|
||||||
|
m_Texture: {fileID: 0}
|
||||||
|
m_Scale: {x: 1, y: 1}
|
||||||
|
m_Offset: {x: 0, y: 0}
|
||||||
|
- _DetailAlbedoMap:
|
||||||
|
m_Texture: {fileID: 0}
|
||||||
|
m_Scale: {x: 1, y: 1}
|
||||||
|
m_Offset: {x: 0, y: 0}
|
||||||
|
- _DetailMask:
|
||||||
|
m_Texture: {fileID: 0}
|
||||||
|
m_Scale: {x: 1, y: 1}
|
||||||
|
m_Offset: {x: 0, y: 0}
|
||||||
|
- _DetailNormalMap:
|
||||||
|
m_Texture: {fileID: 0}
|
||||||
|
m_Scale: {x: 1, y: 1}
|
||||||
|
m_Offset: {x: 0, y: 0}
|
||||||
|
- _EmissionMap:
|
||||||
|
m_Texture: {fileID: 0}
|
||||||
|
m_Scale: {x: 1, y: 1}
|
||||||
|
m_Offset: {x: 0, y: 0}
|
||||||
|
- _MainTex:
|
||||||
|
m_Texture: {fileID: 0}
|
||||||
|
m_Scale: {x: 1, y: 1}
|
||||||
|
m_Offset: {x: 0, y: 0}
|
||||||
|
- _MetallicGlossMap:
|
||||||
|
m_Texture: {fileID: 0}
|
||||||
|
m_Scale: {x: 1, y: 1}
|
||||||
|
m_Offset: {x: 0, y: 0}
|
||||||
|
- _OcclusionMap:
|
||||||
|
m_Texture: {fileID: 0}
|
||||||
|
m_Scale: {x: 1, y: 1}
|
||||||
|
m_Offset: {x: 0, y: 0}
|
||||||
|
- _ParallaxMap:
|
||||||
|
m_Texture: {fileID: 0}
|
||||||
|
m_Scale: {x: 1, y: 1}
|
||||||
|
m_Offset: {x: 0, y: 0}
|
||||||
|
m_Floats:
|
||||||
|
- _BumpScale: 1
|
||||||
|
- _Cutoff: 0.5
|
||||||
|
- _DetailNormalMapScale: 1
|
||||||
|
- _DstBlend: 0
|
||||||
|
- _GlossMapScale: 1
|
||||||
|
- _Glossiness: 0.698
|
||||||
|
- _GlossyReflections: 1
|
||||||
|
- _Metallic: 0
|
||||||
|
- _Mode: 0
|
||||||
|
- _OcclusionStrength: 1
|
||||||
|
- _Parallax: 0.02
|
||||||
|
- _SmoothnessTextureChannel: 0
|
||||||
|
- _SpecularHighlights: 1
|
||||||
|
- _SrcBlend: 1
|
||||||
|
- _UVSec: 0
|
||||||
|
- _ZWrite: 1
|
||||||
|
m_Colors:
|
||||||
|
- _Color: {r: 0.48689637, g: 0.11609437, b: 0.037962936, a: 1}
|
||||||
|
- _EmissionColor: {r: 0, g: 0, b: 0, a: 1}
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: c3542dfecd687604fb8d0b0e6a5a6318
|
||||||
|
NativeFormatImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
mainObjectFileID: 2100000
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
@@ -0,0 +1,56 @@
|
|||||||
|
%YAML 1.1
|
||||||
|
%TAG !u! tag:unity3d.com,2011:
|
||||||
|
--- !u!114 &11400000
|
||||||
|
MonoBehaviour:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 0}
|
||||||
|
m_Enabled: 1
|
||||||
|
m_EditorHideFlags: 0
|
||||||
|
m_Script: {fileID: -340790334, guid: 67cc4cb7839cd3741b63733d5adf0442, type: 3}
|
||||||
|
m_Name: AacExampleMenu
|
||||||
|
m_EditorClassIdentifier:
|
||||||
|
controls:
|
||||||
|
- name: Item
|
||||||
|
icon: {fileID: 0}
|
||||||
|
type: 102
|
||||||
|
parameter:
|
||||||
|
name: EnableItem
|
||||||
|
value: 1
|
||||||
|
style: 0
|
||||||
|
subMenu: {fileID: 0}
|
||||||
|
subParameters: []
|
||||||
|
labels: []
|
||||||
|
- name: Accesories
|
||||||
|
icon: {fileID: 0}
|
||||||
|
type: 102
|
||||||
|
parameter:
|
||||||
|
name: EnableAccessories
|
||||||
|
value: 1
|
||||||
|
style: 0
|
||||||
|
subMenu: {fileID: 0}
|
||||||
|
subParameters: []
|
||||||
|
labels: []
|
||||||
|
- name: Thing
|
||||||
|
icon: {fileID: 0}
|
||||||
|
type: 102
|
||||||
|
parameter:
|
||||||
|
name: AccessoryThing
|
||||||
|
value: 1
|
||||||
|
style: 0
|
||||||
|
subMenu: {fileID: 0}
|
||||||
|
subParameters: []
|
||||||
|
labels: []
|
||||||
|
- name: Wedge Amount
|
||||||
|
icon: {fileID: 0}
|
||||||
|
type: 203
|
||||||
|
parameter:
|
||||||
|
name:
|
||||||
|
value: 1
|
||||||
|
style: 0
|
||||||
|
subMenu: {fileID: 0}
|
||||||
|
subParameters:
|
||||||
|
- name: WedgeAmount
|
||||||
|
labels: []
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: cde459092e0783540b3837521d750413
|
||||||
|
NativeFormatImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
mainObjectFileID: 11400000
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
@@ -0,0 +1,31 @@
|
|||||||
|
%YAML 1.1
|
||||||
|
%TAG !u! tag:unity3d.com,2011:
|
||||||
|
--- !u!114 &11400000
|
||||||
|
MonoBehaviour:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 0}
|
||||||
|
m_Enabled: 1
|
||||||
|
m_EditorHideFlags: 0
|
||||||
|
m_Script: {fileID: -1506855854, guid: 67cc4cb7839cd3741b63733d5adf0442, type: 3}
|
||||||
|
m_Name: AacExampleParams
|
||||||
|
m_EditorClassIdentifier:
|
||||||
|
parameters:
|
||||||
|
- name: EnableItem
|
||||||
|
valueType: 2
|
||||||
|
saved: 1
|
||||||
|
defaultValue: 0
|
||||||
|
- name: EnableAccessories
|
||||||
|
valueType: 2
|
||||||
|
saved: 1
|
||||||
|
defaultValue: 0
|
||||||
|
- name: AccessoryThing
|
||||||
|
valueType: 2
|
||||||
|
saved: 1
|
||||||
|
defaultValue: 0
|
||||||
|
- name: WedgeAmount
|
||||||
|
valueType: 1
|
||||||
|
saved: 1
|
||||||
|
defaultValue: 0
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 599b4ef18dd7b2b41ae63050dc68cf49
|
||||||
|
NativeFormatImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
mainObjectFileID: 11400000
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
Binary file not shown.
@@ -0,0 +1,102 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 63527d990aefbfd4889bdd854f8389e2
|
||||||
|
ModelImporter:
|
||||||
|
serializedVersion: 19301
|
||||||
|
internalIDToNameTable: []
|
||||||
|
externalObjects:
|
||||||
|
- first:
|
||||||
|
type: UnityEngine:Material
|
||||||
|
assembly: UnityEngine.CoreModule
|
||||||
|
name: Material.001
|
||||||
|
second: {fileID: 2100000, guid: c3542dfecd687604fb8d0b0e6a5a6318, type: 2}
|
||||||
|
materials:
|
||||||
|
materialImportMode: 1
|
||||||
|
materialName: 0
|
||||||
|
materialSearch: 1
|
||||||
|
materialLocation: 1
|
||||||
|
animations:
|
||||||
|
legacyGenerateAnimations: 4
|
||||||
|
bakeSimulation: 0
|
||||||
|
resampleCurves: 1
|
||||||
|
optimizeGameObjects: 0
|
||||||
|
motionNodeName:
|
||||||
|
rigImportErrors:
|
||||||
|
rigImportWarnings:
|
||||||
|
animationImportErrors:
|
||||||
|
animationImportWarnings:
|
||||||
|
animationRetargetingWarnings:
|
||||||
|
animationDoRetargetingWarnings: 0
|
||||||
|
importAnimatedCustomProperties: 0
|
||||||
|
importConstraints: 0
|
||||||
|
animationCompression: 1
|
||||||
|
animationRotationError: 0.5
|
||||||
|
animationPositionError: 0.5
|
||||||
|
animationScaleError: 0.5
|
||||||
|
animationWrapMode: 0
|
||||||
|
extraExposedTransformPaths: []
|
||||||
|
extraUserProperties: []
|
||||||
|
clipAnimations: []
|
||||||
|
isReadable: 0
|
||||||
|
meshes:
|
||||||
|
lODScreenPercentages: []
|
||||||
|
globalScale: 1
|
||||||
|
meshCompression: 0
|
||||||
|
addColliders: 0
|
||||||
|
useSRGBMaterialColor: 1
|
||||||
|
sortHierarchyByName: 1
|
||||||
|
importVisibility: 1
|
||||||
|
importBlendShapes: 1
|
||||||
|
importCameras: 1
|
||||||
|
importLights: 1
|
||||||
|
fileIdsGeneration: 2
|
||||||
|
swapUVChannels: 0
|
||||||
|
generateSecondaryUV: 0
|
||||||
|
useFileUnits: 1
|
||||||
|
keepQuads: 0
|
||||||
|
weldVertices: 1
|
||||||
|
preserveHierarchy: 0
|
||||||
|
skinWeightsMode: 0
|
||||||
|
maxBonesPerVertex: 4
|
||||||
|
minBoneWeight: 0.001
|
||||||
|
meshOptimizationFlags: -1
|
||||||
|
indexFormat: 0
|
||||||
|
secondaryUVAngleDistortion: 8
|
||||||
|
secondaryUVAreaDistortion: 15.000001
|
||||||
|
secondaryUVHardAngle: 88
|
||||||
|
secondaryUVPackMargin: 4
|
||||||
|
useFileScale: 1
|
||||||
|
tangentSpace:
|
||||||
|
normalSmoothAngle: 60
|
||||||
|
normalImportMode: 0
|
||||||
|
tangentImportMode: 3
|
||||||
|
normalCalculationMode: 4
|
||||||
|
legacyComputeAllNormalsFromSmoothingGroupsWhenMeshHasBlendShapes: 0
|
||||||
|
blendShapeNormalImportMode: 1
|
||||||
|
normalSmoothingSource: 0
|
||||||
|
referencedClips: []
|
||||||
|
importAnimation: 1
|
||||||
|
humanDescription:
|
||||||
|
serializedVersion: 3
|
||||||
|
human: []
|
||||||
|
skeleton: []
|
||||||
|
armTwist: 0.5
|
||||||
|
foreArmTwist: 0.5
|
||||||
|
upperLegTwist: 0.5
|
||||||
|
legTwist: 0.5
|
||||||
|
armStretch: 0.05
|
||||||
|
legStretch: 0.05
|
||||||
|
feetSpacing: 0
|
||||||
|
globalScale: 1
|
||||||
|
rootMotionBoneName:
|
||||||
|
hasTranslationDoF: 0
|
||||||
|
hasExtraRoot: 0
|
||||||
|
skeletonHasParents: 1
|
||||||
|
lastHumanDescriptionAvatarSource: {instanceID: 0}
|
||||||
|
autoGenerateAvatarMappingIfUnspecified: 1
|
||||||
|
animationType: 2
|
||||||
|
humanoidOversampling: 1
|
||||||
|
avatarSetup: 0
|
||||||
|
additionalBone: 0
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,7 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 152a25406238928428795a65c5473ecb
|
||||||
|
DefaultImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
@@ -0,0 +1,68 @@
|
|||||||
|
using System.Linq;
|
||||||
|
using UnityEngine;
|
||||||
|
using VRC.SDK3.Avatars.Components;
|
||||||
|
using UnityEditor;
|
||||||
|
using UnityEditor.Animations;
|
||||||
|
|
||||||
|
namespace AnimatorAsCodeFramework.Examples
|
||||||
|
{
|
||||||
|
public class GenExample0_ToggleGo : MonoBehaviour
|
||||||
|
{
|
||||||
|
public VRCAvatarDescriptor avatar;
|
||||||
|
public AnimatorController assetContainer;
|
||||||
|
public string assetKey;
|
||||||
|
public GameObject item;
|
||||||
|
}
|
||||||
|
|
||||||
|
[CustomEditor(typeof(GenExample0_ToggleGo), true)]
|
||||||
|
public class GenExample0_ToggleGoEditor : Editor
|
||||||
|
{
|
||||||
|
private const string SystemName = "Example 0";
|
||||||
|
|
||||||
|
public override void OnInspectorGUI()
|
||||||
|
{
|
||||||
|
AacExample.InspectorTemplate(this, serializedObject, "assetKey", Create, Remove);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void Create()
|
||||||
|
{
|
||||||
|
var my = (GenExample0_ToggleGo) target;
|
||||||
|
// The avatar is used here:
|
||||||
|
// - to find the FX playable layer animator, where a new layer will be created.
|
||||||
|
// - to resolve the relative animation path to the item.
|
||||||
|
// The generated animation files are stored in the asset container.
|
||||||
|
var aac = AacExample.AnimatorAsCode(SystemName, my.avatar, my.assetContainer, my.assetKey, AacExample.Options().WriteDefaultsOff());
|
||||||
|
|
||||||
|
// Create a layer in the FX animator.
|
||||||
|
// Additional layers can be created in the FX animator (see later in the manual).
|
||||||
|
var fx = aac.CreateMainFxLayer();
|
||||||
|
|
||||||
|
// The first created state is the default one connected to the "Entry" node.
|
||||||
|
// States are automatically placed on the grid (see later in the manual).
|
||||||
|
var hidden = fx.NewState("Hidden")
|
||||||
|
// Animation assets are generated as sub-assets of the asset container.
|
||||||
|
// The animation path to my.skinnedMesh is relative to my.avatar
|
||||||
|
.WithAnimation(aac.NewClip().Toggling(my.item, false));
|
||||||
|
var shown = fx.NewState("Shown")
|
||||||
|
.WithAnimation(aac.NewClip().Toggling(my.item, true));
|
||||||
|
|
||||||
|
// Creates a Bool parameter in the FX layer.
|
||||||
|
// Parameters are added to the Animator if a parameter with the same name
|
||||||
|
// does not exist yet.
|
||||||
|
var itemParam = fx.BoolParameter("EnableItem");
|
||||||
|
|
||||||
|
// Transitions are created with a set of default values
|
||||||
|
// That can be changed in the Generator settings (see later in the manual).
|
||||||
|
hidden.TransitionsTo(shown).When(itemParam.IsTrue());
|
||||||
|
shown.TransitionsTo(hidden).When(itemParam.IsFalse());
|
||||||
|
}
|
||||||
|
|
||||||
|
private void Remove()
|
||||||
|
{
|
||||||
|
var my = (GenExample0_ToggleGo) target;
|
||||||
|
var aac = AacExample.AnimatorAsCode(SystemName, my.avatar, my.assetContainer, my.assetKey);
|
||||||
|
|
||||||
|
aac.RemoveAllMainLayers();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: be5bb2bad8914be8a6a86373d48e4574
|
||||||
|
timeCreated: 1645746140
|
||||||
@@ -0,0 +1,76 @@
|
|||||||
|
using System.Linq;
|
||||||
|
using UnityEngine;
|
||||||
|
using VRC.SDK3.Avatars.Components;
|
||||||
|
using UnityEditor;
|
||||||
|
using UnityEditor.Animations;
|
||||||
|
|
||||||
|
namespace AnimatorAsCodeFramework.Examples
|
||||||
|
{
|
||||||
|
public class GenExample1_ToggleSmr : MonoBehaviour
|
||||||
|
{
|
||||||
|
public VRCAvatarDescriptor avatar;
|
||||||
|
public AnimatorController assetContainer;
|
||||||
|
public string assetKey;
|
||||||
|
public SkinnedMeshRenderer skinnedMesh;
|
||||||
|
}
|
||||||
|
|
||||||
|
[CustomEditor(typeof(GenExample1_ToggleSmr), true)]
|
||||||
|
public class GenExample1_ToggleSmrEditor : Editor
|
||||||
|
{
|
||||||
|
private const string SystemName = "Example 1";
|
||||||
|
|
||||||
|
public override void OnInspectorGUI()
|
||||||
|
{
|
||||||
|
AacExample.InspectorTemplate(this, serializedObject, "assetKey", Create, Remove);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void Create()
|
||||||
|
{
|
||||||
|
var my = (GenExample1_ToggleSmr) target;
|
||||||
|
var aac = AacExample.AnimatorAsCode(SystemName, my.avatar, my.assetContainer, my.assetKey);
|
||||||
|
|
||||||
|
var fx = aac.CreateMainFxLayer();
|
||||||
|
var hidden = fx.NewState("Hidden")
|
||||||
|
// The runtime type of my.skinnedMesh is used within the animation.
|
||||||
|
// In this case, the "SkinnedMeshRenderer" component is disabled.
|
||||||
|
.WithAnimation(aac.NewClip().TogglingComponent(my.skinnedMesh, false));
|
||||||
|
var shown = fx.NewState("Shown")
|
||||||
|
.WithAnimation(aac.NewClip().TogglingComponent(my.skinnedMesh, true));
|
||||||
|
|
||||||
|
// This creates two Bool parameters in the animator.
|
||||||
|
// The resulting value can be used in conditions.
|
||||||
|
var accessoriesParams = fx.BoolParameters("EnableAccessories", "AccessoryThing");
|
||||||
|
|
||||||
|
// The following line creates one transition.
|
||||||
|
// The conditions are "EnableAccessories is true" and "AccessoryThing is true"
|
||||||
|
hidden.TransitionsTo(shown).When(accessoriesParams.AreTrue());
|
||||||
|
|
||||||
|
// The following line creates two transitions:
|
||||||
|
// - The first transition is "EnableAccessories is false"
|
||||||
|
// - The second transition is "AccessoryThing is false"
|
||||||
|
shown.TransitionsTo(hidden).When(accessoriesParams.IsAnyFalse());
|
||||||
|
|
||||||
|
if (false)
|
||||||
|
{
|
||||||
|
// Alternatively, you can use the long way:
|
||||||
|
var enableAccessoriesParam = fx.BoolParameter("EnableAccessories");
|
||||||
|
var thingParam = fx.BoolParameter("ThingParam");
|
||||||
|
|
||||||
|
hidden.TransitionsTo(shown).When(enableAccessoriesParam.IsTrue()).And(thingParam.IsTrue());
|
||||||
|
|
||||||
|
// - The first transition:
|
||||||
|
shown.TransitionsTo(hidden).When(enableAccessoriesParam.IsFalse())
|
||||||
|
// - The second transition:
|
||||||
|
.Or().When(thingParam.IsFalse());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void Remove()
|
||||||
|
{
|
||||||
|
var my = (GenExample1_ToggleSmr) target;
|
||||||
|
var aac = AacExample.AnimatorAsCode(SystemName, my.avatar, my.assetContainer, my.assetKey);
|
||||||
|
|
||||||
|
aac.RemoveAllMainLayers();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: ea8b0c32e2e54e4883f5b113609cb670
|
||||||
|
timeCreated: 1645744548
|
||||||
@@ -0,0 +1,55 @@
|
|||||||
|
using System.Linq;
|
||||||
|
using UnityEngine;
|
||||||
|
using VRC.SDK3.Avatars.Components;
|
||||||
|
using UnityEditor;
|
||||||
|
using UnityEditor.Animations;
|
||||||
|
|
||||||
|
namespace AnimatorAsCodeFramework.Examples
|
||||||
|
{
|
||||||
|
public class GenExample2_Animate : MonoBehaviour
|
||||||
|
{
|
||||||
|
public VRCAvatarDescriptor avatar;
|
||||||
|
public AnimatorController assetContainer;
|
||||||
|
public string assetKey;
|
||||||
|
public SkinnedMeshRenderer wedgeMesh;
|
||||||
|
}
|
||||||
|
|
||||||
|
[CustomEditor(typeof(GenExample2_Animate), true)]
|
||||||
|
public class GenExample1_BlushEditor : Editor
|
||||||
|
{
|
||||||
|
private const string SystemName = "Example 2";
|
||||||
|
|
||||||
|
public override void OnInspectorGUI()
|
||||||
|
{
|
||||||
|
AacExample.InspectorTemplate(this, serializedObject, "assetKey", Create, Remove);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void Create()
|
||||||
|
{
|
||||||
|
var my = (GenExample2_Animate) target;
|
||||||
|
var aac = AacExample.AnimatorAsCode(SystemName, my.avatar, my.assetContainer, my.assetKey);
|
||||||
|
|
||||||
|
var fx = aac.CreateMainFxLayer();
|
||||||
|
|
||||||
|
fx.NewState("Motion")
|
||||||
|
.WithAnimation(aac.NewClip().Animating(clip =>
|
||||||
|
{
|
||||||
|
clip.Animates(my.wedgeMesh, "blendShape.Wedge").WithFrameCountUnit(keyframes =>
|
||||||
|
keyframes.Easing(0, 100f).Easing(28, 0).Easing(29, 0).Easing(30, 0).Easing(31, 0).Easing(32, 0).Easing(60, 100f)
|
||||||
|
);
|
||||||
|
clip.Animates(my.wedgeMesh, "material._Metallic").WithFrameCountUnit(keyframes =>
|
||||||
|
keyframes.Constant(0, 1f).Constant(28, 0).Constant(60, 0)
|
||||||
|
);
|
||||||
|
}))
|
||||||
|
.MotionTime(fx.FloatParameter("WedgeAmount"));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void Remove()
|
||||||
|
{
|
||||||
|
var my = (GenExample2_Animate) target;
|
||||||
|
var aac = AacExample.AnimatorAsCode(SystemName, my.avatar, my.assetContainer, my.assetKey);
|
||||||
|
|
||||||
|
aac.RemoveAllMainLayers();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: b09d955c545f45428d3c5cfb9b214117
|
||||||
|
timeCreated: 1645746969
|
||||||
@@ -0,0 +1,148 @@
|
|||||||
|
using System.Linq;
|
||||||
|
using AnimatorAsCode.V0;
|
||||||
|
using UnityEngine;
|
||||||
|
using VRC.SDK3.Avatars.Components;
|
||||||
|
using UnityEditor;
|
||||||
|
using UnityEditor.Animations;
|
||||||
|
|
||||||
|
namespace AnimatorAsCodeFramework.Examples
|
||||||
|
{
|
||||||
|
public class GenExample3_Gesturing : MonoBehaviour
|
||||||
|
{
|
||||||
|
public VRCAvatarDescriptor avatar;
|
||||||
|
public AnimatorController assetContainer;
|
||||||
|
public string assetKey;
|
||||||
|
public SkinnedMeshRenderer iconMesh;
|
||||||
|
}
|
||||||
|
|
||||||
|
[CustomEditor(typeof(GenExample3_Gesturing), true)]
|
||||||
|
public class GenExample3_GesturingEditor : Editor
|
||||||
|
{
|
||||||
|
private const string SystemName = "Example 3";
|
||||||
|
|
||||||
|
private GenExample3_Gesturing my;
|
||||||
|
private AacFlBase aac;
|
||||||
|
|
||||||
|
private const string MaxBlendshape = "blendShape.KPIN_A_Major_Max";
|
||||||
|
private const string MinBlendshape = "blendShape.KPIN_A_Major_Min";
|
||||||
|
|
||||||
|
public override void OnInspectorGUI()
|
||||||
|
{
|
||||||
|
AacExample.InspectorTemplate(this, serializedObject, "assetKey", Create, Remove);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void Create()
|
||||||
|
{
|
||||||
|
my = (GenExample3_Gesturing) target;
|
||||||
|
aac = AacExample.AnimatorAsCode(SystemName, my.avatar, my.assetContainer, my.assetKey);
|
||||||
|
|
||||||
|
CreateMainLayer();
|
||||||
|
CreateSupportingLayer();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void Remove()
|
||||||
|
{
|
||||||
|
var my = (GenExample3_Gesturing) target;
|
||||||
|
var aac = AacExample.AnimatorAsCode(SystemName, my.avatar, my.assetContainer, my.assetKey);
|
||||||
|
|
||||||
|
aac.RemoveAllMainLayers();
|
||||||
|
aac.RemoveAllSupportingLayers("Detection");
|
||||||
|
}
|
||||||
|
|
||||||
|
private void CreateMainLayer()
|
||||||
|
{
|
||||||
|
var layer = aac.CreateMainFxLayer();
|
||||||
|
|
||||||
|
var dirtyCheckParameter = layer.BoolParameter("AAC_INTERNAL_GesturingIcon_DirtyCheck");
|
||||||
|
|
||||||
|
// ### Create states
|
||||||
|
var lackOfChangeDetected = layer.NewState("Animate To NoChange")
|
||||||
|
.WithAnimation(IconAppears());
|
||||||
|
|
||||||
|
// By default, states have an animation that animates a dummy object for 1 frame.
|
||||||
|
var noChange = layer.NewState("NoChange", 1, 0).RightOf();
|
||||||
|
|
||||||
|
var changeDetected = layer.NewState("Animate To Changing").Under()
|
||||||
|
.WithAnimation(IconDisappears());
|
||||||
|
|
||||||
|
// This creates a clip that animates a dummy object for 1.5f seconds.
|
||||||
|
var changing = layer.NewState("Changing", 0, 1).LeftOf()
|
||||||
|
.WithAnimation(aac.DummyClipLasting(1.5f, AacFlUnit.Seconds));
|
||||||
|
|
||||||
|
// When this state is entered, the parameter is driven to the value of false.
|
||||||
|
var stillChanging = layer.NewState("Still Changing", 0, 2).Under()
|
||||||
|
.Drives(dirtyCheckParameter, false);
|
||||||
|
|
||||||
|
// ------
|
||||||
|
|
||||||
|
// ### Create transitions
|
||||||
|
lackOfChangeDetected.TransitionsTo(changeDetected).AfterAnimationIsAtLeastAtPercent(0.7f).When(dirtyCheckParameter.IsTrue());
|
||||||
|
|
||||||
|
// The transition duration is 30% of the animation duration.
|
||||||
|
lackOfChangeDetected.TransitionsTo(noChange).AfterAnimationFinishes().WithTransitionDurationPercent(0.3f);
|
||||||
|
|
||||||
|
noChange.TransitionsTo(changeDetected).When(dirtyCheckParameter.IsTrue());
|
||||||
|
|
||||||
|
// By using AfterAnimationFinishes, the transition will trigger after the animation
|
||||||
|
// for the icon appearing finishes.
|
||||||
|
changeDetected.TransitionsTo(changing).AfterAnimationFinishes();
|
||||||
|
|
||||||
|
changing.TransitionsTo(stillChanging).When(dirtyCheckParameter.IsTrue());
|
||||||
|
// By using AfterAnimationFinishes, the transition will trigger after 1.5 seconds,
|
||||||
|
// which is the length of the animation in Changing.
|
||||||
|
changing.TransitionsTo(lackOfChangeDetected).AfterAnimationFinishes();
|
||||||
|
|
||||||
|
// The transition will immediately happen upon entering, by using Exit time set to 0.
|
||||||
|
stillChanging.AutomaticallyMovesTo(changing);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void CreateSupportingLayer()
|
||||||
|
{
|
||||||
|
// Create an additional FX layer.
|
||||||
|
var layer = aac.CreateSupportingFxLayer("Detection");
|
||||||
|
var reevaluating = layer.NewState("Reevaluating", -1, 0);
|
||||||
|
|
||||||
|
foreach (var left in Enumerable.Range(0, 8))
|
||||||
|
{
|
||||||
|
foreach (var right in Enumerable.Range(0, 8))
|
||||||
|
{
|
||||||
|
var state = layer.NewState($"Gesture {left} {right}", left, right)
|
||||||
|
// When this state is entered, the parameter is driven to the value of true.
|
||||||
|
.Drives(layer.BoolParameter("AAC_INTERNAL_GesturingIcon_DirtyCheck"), true);
|
||||||
|
|
||||||
|
reevaluating.TransitionsTo(state)
|
||||||
|
// Use ".Av3" to access VRChat standard parameters.
|
||||||
|
// Accessing these parameters will create the corresponding parameter in the animator.
|
||||||
|
.When(layer.Av3().GestureLeft.IsEqualTo(left))
|
||||||
|
.And(layer.Av3().GestureRight.IsEqualTo(right));
|
||||||
|
state.TransitionsTo(reevaluating)
|
||||||
|
.When(layer.Av3().GestureLeft.IsNotEqualTo(left))
|
||||||
|
.Or()
|
||||||
|
.When(layer.Av3().GestureRight.IsNotEqualTo(right));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private AacFlClip IconAppears()
|
||||||
|
{
|
||||||
|
return aac.NewClip().Animating(clip =>
|
||||||
|
{
|
||||||
|
clip.Animates(my.iconMesh, MaxBlendshape)
|
||||||
|
.WithFrameCountUnit(keyframes => keyframes.Easing(0, 1.001f).Easing(10, 0f));
|
||||||
|
clip.Animates(my.iconMesh, MinBlendshape)
|
||||||
|
.WithOneFrame(0f);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private AacFlClip IconDisappears()
|
||||||
|
{
|
||||||
|
return aac.NewClip().Animating(clip =>
|
||||||
|
{
|
||||||
|
clip.Animates(my.iconMesh, MaxBlendshape)
|
||||||
|
.WithFrameCountUnit(keyframes => keyframes.Easing(0, 0f).Easing(30, 0f));
|
||||||
|
clip.Animates(my.iconMesh, MinBlendshape)
|
||||||
|
.WithFrameCountUnit(keyframes => keyframes.Easing(0, 0f).Easing(10, 100f));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: a0bd105e311c440ca03e6f6c46f830fc
|
||||||
|
timeCreated: 1645755767
|
||||||
@@ -0,0 +1,52 @@
|
|||||||
|
using System.Linq;
|
||||||
|
using UnityEngine;
|
||||||
|
using VRC.SDK3.Avatars.Components;
|
||||||
|
using UnityEditor;
|
||||||
|
using UnityEditor.Animations;
|
||||||
|
|
||||||
|
namespace AnimatorAsCodeFramework.Examples
|
||||||
|
{
|
||||||
|
public class GenExampleManual_PlacingStates : MonoBehaviour
|
||||||
|
{
|
||||||
|
public VRCAvatarDescriptor avatar;
|
||||||
|
public AnimatorController assetContainer;
|
||||||
|
public string assetKey;
|
||||||
|
}
|
||||||
|
|
||||||
|
[CustomEditor(typeof(GenExampleManual_PlacingStates), true)]
|
||||||
|
public class GenExampleManual_PlacingStatesEditor : Editor
|
||||||
|
{
|
||||||
|
private const string SystemName = "Example Manual - Placing States";
|
||||||
|
|
||||||
|
public override void OnInspectorGUI()
|
||||||
|
{
|
||||||
|
AacExample.InspectorTemplate(this, serializedObject, "assetKey", Create, Remove);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void Create()
|
||||||
|
{
|
||||||
|
var my = (GenExampleManual_PlacingStates) target;
|
||||||
|
var aac = AacExample.AnimatorAsCode(SystemName, my.avatar, my.assetContainer, my.assetKey);
|
||||||
|
|
||||||
|
var fx = aac.CreateMainFxLayer();
|
||||||
|
|
||||||
|
var init = fx.NewState("Init"); // This is the first state. By default it is at (0, 0)
|
||||||
|
var a = fx.NewState("A"); // This will be placed under Init.
|
||||||
|
var b = fx.NewState("B"); // This will be placed under A.
|
||||||
|
var c = fx.NewState("C").RightOf(a); // This will be placed right of A.
|
||||||
|
var d = fx.NewState("D"); // This will be placed under C.
|
||||||
|
var alternate = fx.NewState("Alternate").Over(c); // This will be placed over C.
|
||||||
|
|
||||||
|
// This will be placed next to Alternate: 2 blocks over, and 1 to the right.
|
||||||
|
var reset = fx.NewState("Reset").Shift(alternate, 1, -2);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void Remove()
|
||||||
|
{
|
||||||
|
var my = (GenExampleManual_PlacingStates) target;
|
||||||
|
var aac = AacExample.AnimatorAsCode(SystemName, my.avatar, my.assetContainer, my.assetKey);
|
||||||
|
|
||||||
|
aac.RemoveAllMainLayers();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: f4c992e0dc0e4f74a36f386346991dbc
|
||||||
|
timeCreated: 1645800049
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 8743b020a8e44294871ab5782040e999
|
||||||
|
timeCreated: 1645907951
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
{
|
||||||
|
"name": "AnimatorAsCodeFramework"
|
||||||
|
}
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 21dee7794a6343ccbdcd48b92f941953
|
||||||
|
timeCreated: 1645911687
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 6084a9de238746a28ba45b77d85d0dc7
|
||||||
|
timeCreated: 1645908045
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 6ab1a9c322945d5449fea4130317f605
|
||||||
|
folderAsset: yes
|
||||||
|
DefaultImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
@@ -0,0 +1,632 @@
|
|||||||
|
using System;
|
||||||
|
using System.Linq;
|
||||||
|
using UnityEditor;
|
||||||
|
using UnityEditor.Animations;
|
||||||
|
using UnityEngine;
|
||||||
|
using VRC.SDK3.Avatars.Components;
|
||||||
|
using Random = UnityEngine.Random;
|
||||||
|
|
||||||
|
// ReSharper disable once CheckNamespace
|
||||||
|
namespace AnimatorAsCode.V0
|
||||||
|
{
|
||||||
|
public static class AacV0
|
||||||
|
{
|
||||||
|
public static AacFlBase Create(AacConfiguration configuration)
|
||||||
|
{
|
||||||
|
return new AacFlBase(configuration);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static AnimatorController AnimatorOf(VRCAvatarDescriptor ad, VRCAvatarDescriptor.AnimLayerType animLayerType)
|
||||||
|
{
|
||||||
|
return (AnimatorController) ad.baseAnimationLayers.First(it => it.type == animLayerType).animatorController;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static AnimationClip NewClip(AacConfiguration component, string suffix)
|
||||||
|
{
|
||||||
|
return RegisterClip(component, suffix, new AnimationClip());
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static AnimationClip RegisterClip(AacConfiguration component, string suffix, AnimationClip clip)
|
||||||
|
{
|
||||||
|
clip.name = "zAutogenerated__" + component.AssetKey + "__" + suffix + "_" + Random.Range(0, Int32.MaxValue); // FIXME animation name conflict
|
||||||
|
clip.hideFlags = HideFlags.None;
|
||||||
|
AssetDatabase.AddObjectToAsset(clip, component.AssetContainer);
|
||||||
|
return clip;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static BlendTree NewBlendTreeAsRaw(AacConfiguration component, string suffix)
|
||||||
|
{
|
||||||
|
var clip = new BlendTree();
|
||||||
|
clip.name = "zAutogenerated__" + component.AssetKey + "__" + suffix + "_" + Random.Range(0, Int32.MaxValue); // FIXME animation name conflict
|
||||||
|
clip.hideFlags = HideFlags.None;
|
||||||
|
AssetDatabase.AddObjectToAsset(clip, component.AssetContainer);
|
||||||
|
return clip;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static EditorCurveBinding Binding(AacConfiguration component, Type type, Transform transform, string propertyName)
|
||||||
|
{
|
||||||
|
return new EditorCurveBinding
|
||||||
|
{
|
||||||
|
path = ResolveRelativePath(component.AnimatorRoot, transform),
|
||||||
|
type = type,
|
||||||
|
propertyName = propertyName
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static AnimationCurve OneFrame(float desiredValue)
|
||||||
|
{
|
||||||
|
return AnimationCurve.Constant(0f, 1 / 60f, desiredValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static AnimationCurve ConstantSeconds(float seconds, float desiredValue)
|
||||||
|
{
|
||||||
|
return AnimationCurve.Constant(0f, seconds, desiredValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static string ResolveRelativePath(Transform avatar, Transform item)
|
||||||
|
{
|
||||||
|
if (item.parent != avatar && item.parent != null)
|
||||||
|
{
|
||||||
|
return ResolveRelativePath(avatar, item.parent) + "/" + item.name;
|
||||||
|
}
|
||||||
|
|
||||||
|
return item.name;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static EditorCurveBinding ToSubBinding(EditorCurveBinding binding, string suffix)
|
||||||
|
{
|
||||||
|
return new EditorCurveBinding {path = binding.path, type = binding.type, propertyName = binding.propertyName + "." + suffix};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public struct AacConfiguration
|
||||||
|
{
|
||||||
|
public string SystemName;
|
||||||
|
public VRCAvatarDescriptor AvatarDescriptor;
|
||||||
|
public Transform AnimatorRoot;
|
||||||
|
public Transform DefaultValueRoot;
|
||||||
|
public AnimatorController AssetContainer;
|
||||||
|
public string AssetKey;
|
||||||
|
public IAacDefaultsProvider DefaultsProvider;
|
||||||
|
}
|
||||||
|
|
||||||
|
public struct AacFlLayer
|
||||||
|
{
|
||||||
|
private readonly AnimatorController _animatorController;
|
||||||
|
private readonly AacConfiguration _configuration;
|
||||||
|
private readonly string _fullLayerName;
|
||||||
|
private readonly AacStateMachine _stateMachine;
|
||||||
|
|
||||||
|
internal AacFlLayer(AnimatorController animatorController, AacConfiguration configuration, AacStateMachine stateMachine, string fullLayerName)
|
||||||
|
{
|
||||||
|
_animatorController = animatorController;
|
||||||
|
_configuration = configuration;
|
||||||
|
_fullLayerName = fullLayerName;
|
||||||
|
_stateMachine = stateMachine;
|
||||||
|
}
|
||||||
|
|
||||||
|
public AacFlState NewState(string name)
|
||||||
|
{
|
||||||
|
var lastState = _stateMachine.LastStatePosition();
|
||||||
|
var state = _stateMachine.NewState(name, 0, 0).Shift(lastState, 0, 1);
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
|
||||||
|
public AacFlState NewState(string name, int x, int y)
|
||||||
|
{
|
||||||
|
return _stateMachine.NewState(name, x, y);
|
||||||
|
}
|
||||||
|
|
||||||
|
public AacFlTransition AnyTransitionsTo(AacFlState destination)
|
||||||
|
{
|
||||||
|
return _stateMachine.AnyTransitionsTo(destination);
|
||||||
|
}
|
||||||
|
|
||||||
|
public AacFlEntryTransition EntryTransitionsTo(AacFlState destination)
|
||||||
|
{
|
||||||
|
return _stateMachine.EntryTransitionsTo(destination);
|
||||||
|
}
|
||||||
|
|
||||||
|
public AacFlBoolParameter BoolParameter(string parameterName) => _stateMachine.BackingAnimator().BoolParameter(parameterName);
|
||||||
|
public AacFlBoolParameter TriggerParameterAsBool(string parameterName) => _stateMachine.BackingAnimator().TriggerParameter(parameterName);
|
||||||
|
public AacFlFloatParameter FloatParameter(string parameterName) => _stateMachine.BackingAnimator().FloatParameter(parameterName);
|
||||||
|
public AacFlIntParameter IntParameter(string parameterName) => _stateMachine.BackingAnimator().IntParameter(parameterName);
|
||||||
|
public AacFlBoolParameterGroup BoolParameters(params string[] parameterNames) => _stateMachine.BackingAnimator().BoolParameters(parameterNames);
|
||||||
|
public AacFlBoolParameterGroup TriggerParametersAsBools(params string[] parameterNames) => _stateMachine.BackingAnimator().TriggerParameters(parameterNames);
|
||||||
|
public AacFlFloatParameterGroup FloatParameters(params string[] parameterNames) => _stateMachine.BackingAnimator().FloatParameters(parameterNames);
|
||||||
|
public AacFlIntParameterGroup IntParameters(params string[] parameterNames) => _stateMachine.BackingAnimator().IntParameters(parameterNames);
|
||||||
|
public AacFlBoolParameterGroup BoolParameters(params AacFlBoolParameter[] parameters) => _stateMachine.BackingAnimator().BoolParameters(parameters);
|
||||||
|
public AacFlBoolParameterGroup TriggerParametersAsBools(params AacFlBoolParameter[] parameters) => _stateMachine.BackingAnimator().TriggerParameters(parameters);
|
||||||
|
public AacFlFloatParameterGroup FloatParameters(params AacFlFloatParameter[] parameters) => _stateMachine.BackingAnimator().FloatParameters(parameters);
|
||||||
|
public AacFlIntParameterGroup IntParameters(params AacFlIntParameter[] parameters) => _stateMachine.BackingAnimator().IntParameters(parameters);
|
||||||
|
public AacAv3 Av3() => new AacAv3(_stateMachine.BackingAnimator());
|
||||||
|
|
||||||
|
public void OverrideValue(AacFlBoolParameter toBeForced, bool value)
|
||||||
|
{
|
||||||
|
var parameters = _animatorController.parameters;
|
||||||
|
foreach (var param in parameters)
|
||||||
|
{
|
||||||
|
if (param.name == toBeForced.Name)
|
||||||
|
{
|
||||||
|
param.defaultBool = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_animatorController.parameters = parameters;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void OverrideValue(AacFlFloatParameter toBeForced, float value)
|
||||||
|
{
|
||||||
|
var parameters = _animatorController.parameters;
|
||||||
|
foreach (var param in parameters)
|
||||||
|
{
|
||||||
|
if (param.name == toBeForced.Name)
|
||||||
|
{
|
||||||
|
param.defaultFloat = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_animatorController.parameters = parameters;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void OverrideValue(AacFlIntParameter toBeForced, int value)
|
||||||
|
{
|
||||||
|
var parameters = _animatorController.parameters;
|
||||||
|
foreach (var param in parameters)
|
||||||
|
{
|
||||||
|
if (param.name == toBeForced.Name)
|
||||||
|
{
|
||||||
|
param.defaultInt = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_animatorController.parameters = parameters;
|
||||||
|
}
|
||||||
|
|
||||||
|
public AacFlLayer WithAvatarMask(AvatarMask avatarMask)
|
||||||
|
{
|
||||||
|
var finalFullLayerName = _fullLayerName;
|
||||||
|
_animatorController.layers = _animatorController.layers
|
||||||
|
.Select(layer =>
|
||||||
|
{
|
||||||
|
if (layer.name == finalFullLayerName)
|
||||||
|
{
|
||||||
|
layer.avatarMask = avatarMask;
|
||||||
|
}
|
||||||
|
|
||||||
|
return layer;
|
||||||
|
})
|
||||||
|
.ToArray();
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void WithAvatarMaskNoTransforms()
|
||||||
|
{
|
||||||
|
ResolveAvatarMask(new Transform[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ResolveAvatarMask(Transform[] paths)
|
||||||
|
{
|
||||||
|
// FIXME: Fragile
|
||||||
|
var avatarMask = new AvatarMask();
|
||||||
|
avatarMask.name = "zAutogenerated__" + _configuration.AssetKey + "_" + _fullLayerName + "__AvatarMask";
|
||||||
|
avatarMask.hideFlags = HideFlags.None;
|
||||||
|
|
||||||
|
if (paths.Length == 0)
|
||||||
|
{
|
||||||
|
avatarMask.transformCount = 1;
|
||||||
|
avatarMask.SetTransformActive(0, false);
|
||||||
|
avatarMask.SetTransformPath(0, "_ignored");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
avatarMask.transformCount = paths.Length;
|
||||||
|
for (var index = 0; index < paths.Length; index++)
|
||||||
|
{
|
||||||
|
var transform = paths[index];
|
||||||
|
avatarMask.SetTransformActive(index, true);
|
||||||
|
avatarMask.SetTransformPath(index, AacV0.ResolveRelativePath(_configuration.AnimatorRoot, transform));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < (int) AvatarMaskBodyPart.LastBodyPart; i++)
|
||||||
|
{
|
||||||
|
avatarMask.SetHumanoidBodyPartActive((AvatarMaskBodyPart) i, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
AssetDatabase.AddObjectToAsset(avatarMask, _animatorController);
|
||||||
|
|
||||||
|
WithAvatarMask(avatarMask);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class AacFlBase
|
||||||
|
{
|
||||||
|
private readonly AacConfiguration _configuration;
|
||||||
|
|
||||||
|
internal AacFlBase(AacConfiguration configuration)
|
||||||
|
{
|
||||||
|
_configuration = configuration;
|
||||||
|
}
|
||||||
|
|
||||||
|
public AacFlClip NewClip()
|
||||||
|
{
|
||||||
|
var clip = AacV0.NewClip(_configuration, Guid.NewGuid().ToString());
|
||||||
|
return new AacFlClip(_configuration, clip);
|
||||||
|
}
|
||||||
|
|
||||||
|
public AacFlClip CopyClip(AnimationClip originalClip)
|
||||||
|
{
|
||||||
|
var newClip = UnityEngine.Object.Instantiate(originalClip);
|
||||||
|
var clip = AacV0.RegisterClip(_configuration, Guid.NewGuid().ToString(), newClip);
|
||||||
|
return new AacFlClip(_configuration, clip);
|
||||||
|
}
|
||||||
|
|
||||||
|
public BlendTree NewBlendTreeAsRaw()
|
||||||
|
{
|
||||||
|
return AacV0.NewBlendTreeAsRaw(_configuration, Guid.NewGuid().ToString());
|
||||||
|
}
|
||||||
|
|
||||||
|
public AacFlClip NewClip(string name)
|
||||||
|
{
|
||||||
|
var clip = AacV0.NewClip(_configuration, name);
|
||||||
|
return new AacFlClip(_configuration, clip);
|
||||||
|
}
|
||||||
|
|
||||||
|
public AacFlClip DummyClipLasting(float numberOf, AacFlUnit unit)
|
||||||
|
{
|
||||||
|
var dummyClip = AacV0.NewClip(_configuration, $"D({numberOf} {Enum.GetName(typeof(AacFlUnit), unit)})");
|
||||||
|
|
||||||
|
var duration = unit == AacFlUnit.Frames ? numberOf / 60f : numberOf;
|
||||||
|
return new AacFlClip(_configuration, dummyClip)
|
||||||
|
.Animating(clip => clip.Animates("_ignored", typeof(GameObject), "m_IsActive")
|
||||||
|
.WithUnit(unit, keyframes => keyframes.Constant(0, 0f).Constant(duration, 0f)));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void RemoveAllMainLayers()
|
||||||
|
{
|
||||||
|
var layerName = _configuration.SystemName;
|
||||||
|
RemoveLayerOnAllControllers(_configuration.DefaultsProvider.ConvertLayerName(layerName));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void RemoveAllSupportingLayers(string suffix)
|
||||||
|
{
|
||||||
|
var layerName = _configuration.SystemName;
|
||||||
|
RemoveLayerOnAllControllers(_configuration.DefaultsProvider.ConvertLayerNameWithSuffix(layerName, suffix));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void RemoveLayerOnAllControllers(string layerName)
|
||||||
|
{
|
||||||
|
var layers = _configuration.AvatarDescriptor.baseAnimationLayers.Select(layer => layer.animatorController).Where(layer => layer != null).Distinct().ToList();
|
||||||
|
foreach (var customAnimLayer in layers)
|
||||||
|
{
|
||||||
|
new AacAnimatorRemoval((AnimatorController) customAnimLayer).RemoveLayer(_configuration.DefaultsProvider.ConvertLayerName(layerName));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public AacFlLayer CreateMainFxLayer() => DoCreateMainLayerOnController(VRCAvatarDescriptor.AnimLayerType.FX);
|
||||||
|
public AacFlLayer CreateMainGestureLayer() => DoCreateMainLayerOnController(VRCAvatarDescriptor.AnimLayerType.Gesture);
|
||||||
|
public AacFlLayer CreateMainActionLayer() => DoCreateMainLayerOnController(VRCAvatarDescriptor.AnimLayerType.Action);
|
||||||
|
public AacFlLayer CreateMainIdleLayer() => DoCreateMainLayerOnController(VRCAvatarDescriptor.AnimLayerType.Additive);
|
||||||
|
public AacFlLayer CreateMainLocomotionLayer() => DoCreateMainLayerOnController(VRCAvatarDescriptor.AnimLayerType.Base);
|
||||||
|
public AacFlLayer CreateMainAv3Layer(VRCAvatarDescriptor.AnimLayerType animLayerType) => DoCreateMainLayerOnController(animLayerType);
|
||||||
|
|
||||||
|
public AacFlLayer CreateSupportingFxLayer(string suffix) => DoCreateSupportingLayerOnController(VRCAvatarDescriptor.AnimLayerType.FX, suffix);
|
||||||
|
public AacFlLayer CreateSupportingGestureLayer(string suffix) => DoCreateSupportingLayerOnController(VRCAvatarDescriptor.AnimLayerType.Gesture, suffix);
|
||||||
|
public AacFlLayer CreateSupportingActionLayer(string suffix) => DoCreateSupportingLayerOnController(VRCAvatarDescriptor.AnimLayerType.Action, suffix);
|
||||||
|
public AacFlLayer CreateSupportingIdleLayer(string suffix) => DoCreateSupportingLayerOnController(VRCAvatarDescriptor.AnimLayerType.Additive, suffix);
|
||||||
|
public AacFlLayer CreateSupportingLocomotionLayer(string suffix) => DoCreateSupportingLayerOnController(VRCAvatarDescriptor.AnimLayerType.Base, suffix);
|
||||||
|
public AacFlLayer CreateSupportingAv3Layer(VRCAvatarDescriptor.AnimLayerType animLayerType, string suffix) => DoCreateSupportingLayerOnController(animLayerType, suffix);
|
||||||
|
|
||||||
|
public AacFlLayer CreateMainArbitraryControllerLayer(AnimatorController controller) => DoCreateLayer(controller, _configuration.DefaultsProvider.ConvertLayerName(_configuration.SystemName));
|
||||||
|
public AacFlLayer CreateSupportingArbitraryControllerLayer(AnimatorController controller, string suffix) => DoCreateLayer(controller, _configuration.DefaultsProvider.ConvertLayerNameWithSuffix(_configuration.SystemName, suffix));
|
||||||
|
public AacFlLayer CreateFirstArbitraryControllerLayer(AnimatorController controller) => DoCreateLayer(controller, controller.layers[0].name);
|
||||||
|
|
||||||
|
private AacFlLayer DoCreateMainLayerOnController(VRCAvatarDescriptor.AnimLayerType animType)
|
||||||
|
{
|
||||||
|
var animator = AacV0.AnimatorOf(_configuration.AvatarDescriptor, animType);
|
||||||
|
var layerName = _configuration.DefaultsProvider.ConvertLayerName(_configuration.SystemName);
|
||||||
|
|
||||||
|
return DoCreateLayer(animator, layerName);
|
||||||
|
}
|
||||||
|
|
||||||
|
private AacFlLayer DoCreateSupportingLayerOnController(VRCAvatarDescriptor.AnimLayerType animType, string suffix)
|
||||||
|
{
|
||||||
|
var animator = AacV0.AnimatorOf(_configuration.AvatarDescriptor, animType);
|
||||||
|
var layerName = _configuration.DefaultsProvider.ConvertLayerNameWithSuffix(_configuration.SystemName, suffix);
|
||||||
|
|
||||||
|
return DoCreateLayer(animator, layerName);
|
||||||
|
}
|
||||||
|
|
||||||
|
private AacFlLayer DoCreateLayer(AnimatorController animator, string layerName)
|
||||||
|
{
|
||||||
|
var ag = new AacAnimatorGenerator(animator, CreateEmptyClip().Clip, _configuration.DefaultsProvider);
|
||||||
|
var machine = ag.CreateOrClearLayerAtSameIndex(layerName, 1f);
|
||||||
|
|
||||||
|
return new AacFlLayer(animator, _configuration, machine, layerName);
|
||||||
|
}
|
||||||
|
|
||||||
|
private AacFlClip CreateEmptyClip()
|
||||||
|
{
|
||||||
|
var emptyClip = DummyClipLasting(1, AacFlUnit.Frames);
|
||||||
|
return emptyClip;
|
||||||
|
}
|
||||||
|
|
||||||
|
public AacVrcAssetLibrary VrcAssets()
|
||||||
|
{
|
||||||
|
return new AacVrcAssetLibrary();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ClearPreviousAssets()
|
||||||
|
{
|
||||||
|
var allSubAssets = AssetDatabase.LoadAllAssetsAtPath(AssetDatabase.GetAssetPath(_configuration.AssetContainer));
|
||||||
|
foreach (var subAsset in allSubAssets)
|
||||||
|
{
|
||||||
|
if (subAsset.name.StartsWith($"zAutogenerated__{_configuration.AssetKey}__")
|
||||||
|
&& (subAsset is AnimationClip || subAsset is BlendTree || subAsset is AvatarMask))
|
||||||
|
{
|
||||||
|
AssetDatabase.RemoveObjectFromAsset(subAsset);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class AacAv3
|
||||||
|
{
|
||||||
|
private readonly AacBackingAnimator _backingAnimator;
|
||||||
|
|
||||||
|
internal AacAv3(AacBackingAnimator backingAnimator)
|
||||||
|
{
|
||||||
|
_backingAnimator = backingAnimator;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ReSharper disable InconsistentNaming
|
||||||
|
public AacFlBoolParameter IsLocal => _backingAnimator.BoolParameter("IsLocal");
|
||||||
|
public AacFlEnumIntParameter<Av3Viseme> Viseme => _backingAnimator.EnumParameter<Av3Viseme>("Viseme");
|
||||||
|
public AacFlEnumIntParameter<Av3Gesture> GestureLeft => _backingAnimator.EnumParameter<Av3Gesture>("GestureLeft");
|
||||||
|
public AacFlEnumIntParameter<Av3Gesture> GestureRight => _backingAnimator.EnumParameter<Av3Gesture>("GestureRight");
|
||||||
|
public AacFlFloatParameter GestureLeftWeight => _backingAnimator.FloatParameter("GestureLeftWeight");
|
||||||
|
public AacFlFloatParameter GestureRightWeight => _backingAnimator.FloatParameter("GestureRightWeight");
|
||||||
|
public AacFlFloatParameter AngularY => _backingAnimator.FloatParameter("AngularY");
|
||||||
|
public AacFlFloatParameter VelocityX => _backingAnimator.FloatParameter("VelocityX");
|
||||||
|
public AacFlFloatParameter VelocityY => _backingAnimator.FloatParameter("VelocityY");
|
||||||
|
public AacFlFloatParameter VelocityZ => _backingAnimator.FloatParameter("VelocityZ");
|
||||||
|
public AacFlFloatParameter Upright => _backingAnimator.FloatParameter("Upright");
|
||||||
|
public AacFlBoolParameter Grounded => _backingAnimator.BoolParameter("Grounded");
|
||||||
|
public AacFlBoolParameter Seated => _backingAnimator.BoolParameter("Seated");
|
||||||
|
public AacFlBoolParameter AFK => _backingAnimator.BoolParameter("AFK");
|
||||||
|
public AacFlIntParameter TrackingType => _backingAnimator.IntParameter("TrackingType");
|
||||||
|
public AacFlIntParameter VRMode => _backingAnimator.IntParameter("VRMode");
|
||||||
|
public AacFlBoolParameter MuteSelf => _backingAnimator.BoolParameter("MuteSelf");
|
||||||
|
public AacFlBoolParameter InStation => _backingAnimator.BoolParameter("InStation");
|
||||||
|
public AacFlFloatParameter Voice => _backingAnimator.FloatParameter("Voice");
|
||||||
|
// ReSharper restore InconsistentNaming
|
||||||
|
|
||||||
|
public IAacFlCondition ItIsRemote() => IsLocal.IsFalse();
|
||||||
|
public IAacFlCondition ItIsLocal() => IsLocal.IsTrue();
|
||||||
|
|
||||||
|
public enum Av3Gesture
|
||||||
|
{
|
||||||
|
// Specify all the values explicitly because they should be dictated by VRChat, not enumeration order.
|
||||||
|
Neutral = 0,
|
||||||
|
Fist = 1,
|
||||||
|
HandOpen = 2,
|
||||||
|
Fingerpoint = 3,
|
||||||
|
Victory = 4,
|
||||||
|
RockNRoll = 5,
|
||||||
|
HandGun = 6,
|
||||||
|
ThumbsUp = 7
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum Av3Viseme
|
||||||
|
{
|
||||||
|
// Specify all the values explicitly because they should be dictated by VRChat, not enumeration order.
|
||||||
|
// ReSharper disable InconsistentNaming
|
||||||
|
sil = 0,
|
||||||
|
pp = 1,
|
||||||
|
ff = 2,
|
||||||
|
th = 3,
|
||||||
|
dd = 4,
|
||||||
|
kk = 5,
|
||||||
|
ch = 6,
|
||||||
|
ss = 7,
|
||||||
|
nn = 8,
|
||||||
|
rr = 9,
|
||||||
|
aa = 10,
|
||||||
|
e = 11,
|
||||||
|
ih = 12,
|
||||||
|
oh = 13,
|
||||||
|
ou = 14
|
||||||
|
// ReSharper restore InconsistentNaming
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class AacVrcAssetLibrary
|
||||||
|
{
|
||||||
|
public AvatarMask LeftHandAvatarMask()
|
||||||
|
{
|
||||||
|
return AssetDatabase.LoadAssetAtPath<AvatarMask>("Assets/VRCSDK/Examples3/Animation/Masks/vrc_Hand Left.mask");
|
||||||
|
}
|
||||||
|
|
||||||
|
public AvatarMask RightHandAvatarMask()
|
||||||
|
{
|
||||||
|
return AssetDatabase.LoadAssetAtPath<AvatarMask>("Assets/VRCSDK/Examples3/Animation/Masks/vrc_Hand Right.mask");
|
||||||
|
}
|
||||||
|
|
||||||
|
public AnimationClip ProxyForGesture(AacAv3.Av3Gesture gesture, bool masculine)
|
||||||
|
{
|
||||||
|
return AssetDatabase.LoadAssetAtPath<AnimationClip>("Assets/VRCSDK/Examples3/Animation/ProxyAnim/" + ResolveProxyFilename(gesture, masculine));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string ResolveProxyFilename(AacAv3.Av3Gesture gesture, bool masculine)
|
||||||
|
{
|
||||||
|
switch (gesture)
|
||||||
|
{
|
||||||
|
case AacAv3.Av3Gesture.Neutral: return masculine ? "proxy_hands_idle.anim" : "proxy_hands_idle2.anim";
|
||||||
|
case AacAv3.Av3Gesture.Fist: return "proxy_hands_fist.anim";
|
||||||
|
case AacAv3.Av3Gesture.HandOpen: return "proxy_hands_open.anim";
|
||||||
|
case AacAv3.Av3Gesture.Fingerpoint: return "proxy_hands_point.anim";
|
||||||
|
case AacAv3.Av3Gesture.Victory: return "proxy_hands_peace.anim";
|
||||||
|
case AacAv3.Av3Gesture.RockNRoll: return "proxy_hands_rock.anim";
|
||||||
|
case AacAv3.Av3Gesture.HandGun: return "proxy_hands_gun.anim";
|
||||||
|
case AacAv3.Av3Gesture.ThumbsUp: return "proxy_hands_thumbs_up.anim";
|
||||||
|
default:
|
||||||
|
throw new ArgumentOutOfRangeException(nameof(gesture), gesture, null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class AacAnimatorRemoval
|
||||||
|
{
|
||||||
|
private readonly AnimatorController _animatorController;
|
||||||
|
|
||||||
|
public AacAnimatorRemoval(AnimatorController animatorController)
|
||||||
|
{
|
||||||
|
_animatorController = animatorController;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void RemoveLayer(string layerName)
|
||||||
|
{
|
||||||
|
var index = FindIndexOf(layerName);
|
||||||
|
if (index == -1) return;
|
||||||
|
|
||||||
|
_animatorController.RemoveLayer(index);
|
||||||
|
}
|
||||||
|
|
||||||
|
private int FindIndexOf(string layerName)
|
||||||
|
{
|
||||||
|
return _animatorController.layers.ToList().FindIndex(layer => layer.name == layerName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class AacAnimatorGenerator
|
||||||
|
{
|
||||||
|
private readonly AnimatorController _animatorController;
|
||||||
|
private readonly AnimationClip _emptyClip;
|
||||||
|
private readonly IAacDefaultsProvider _defaultsProvider;
|
||||||
|
|
||||||
|
internal AacAnimatorGenerator(AnimatorController animatorController, AnimationClip emptyClip, IAacDefaultsProvider defaultsProvider)
|
||||||
|
{
|
||||||
|
_animatorController = animatorController;
|
||||||
|
_emptyClip = emptyClip;
|
||||||
|
_defaultsProvider = defaultsProvider;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal void CreateParamsAsNeeded(params AacFlParameter[] parameters)
|
||||||
|
{
|
||||||
|
foreach (var parameter in parameters)
|
||||||
|
{
|
||||||
|
switch (parameter)
|
||||||
|
{
|
||||||
|
case AacFlIntParameter _:
|
||||||
|
CreateParamIfNotExists(parameter.Name, AnimatorControllerParameterType.Int);
|
||||||
|
break;
|
||||||
|
case AacFlFloatParameter _:
|
||||||
|
CreateParamIfNotExists(parameter.Name, AnimatorControllerParameterType.Float);
|
||||||
|
break;
|
||||||
|
case AacFlBoolParameter _:
|
||||||
|
CreateParamIfNotExists(parameter.Name, AnimatorControllerParameterType.Bool);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
internal void CreateTriggerParamsAsNeeded(params AacFlBoolParameter[] parameters)
|
||||||
|
{
|
||||||
|
foreach (var parameter in parameters)
|
||||||
|
{
|
||||||
|
CreateParamIfNotExists(parameter.Name, AnimatorControllerParameterType.Trigger);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void CreateParamIfNotExists(string paramName, AnimatorControllerParameterType type)
|
||||||
|
{
|
||||||
|
if (_animatorController.parameters.FirstOrDefault(param => param.name == paramName) == null)
|
||||||
|
{
|
||||||
|
_animatorController.AddParameter(paramName, type);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// DEPRECATED: This causes the editor window to glitch by deselecting, which is jarring for experimentation
|
||||||
|
internal AacStateMachine CreateOrRemakeLayerAtSameIndex(string layerName, float weightWhenCreating, AvatarMask maskWhenCreating = null)
|
||||||
|
{
|
||||||
|
var originalIndexToPreserveOrdering = FindIndexOf(layerName);
|
||||||
|
if (originalIndexToPreserveOrdering != -1)
|
||||||
|
{
|
||||||
|
_animatorController.RemoveLayer(originalIndexToPreserveOrdering);
|
||||||
|
}
|
||||||
|
|
||||||
|
AddLayerWithWeight(layerName, weightWhenCreating, maskWhenCreating);
|
||||||
|
if (originalIndexToPreserveOrdering != -1)
|
||||||
|
{
|
||||||
|
var items = _animatorController.layers.ToList();
|
||||||
|
var last = items[items.Count - 1];
|
||||||
|
items.RemoveAt(items.Count - 1);
|
||||||
|
items.Insert(originalIndexToPreserveOrdering, last);
|
||||||
|
_animatorController.layers = items.ToArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
var layer = TryGetLayer(layerName);
|
||||||
|
var machinist = new AacStateMachine(layer.stateMachine, _emptyClip, new AacBackingAnimator(this), _defaultsProvider);
|
||||||
|
return machinist
|
||||||
|
.WithAnyStatePosition(0, 7)
|
||||||
|
.WithEntryPosition(0, -1)
|
||||||
|
.WithExitPosition(7, -1);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal AacStateMachine CreateOrClearLayerAtSameIndex(string layerName, float weightWhenCreating, AvatarMask maskWhenCreating = null)
|
||||||
|
{
|
||||||
|
var originalIndexToPreserveOrdering = FindIndexOf(layerName);
|
||||||
|
if (originalIndexToPreserveOrdering != -1)
|
||||||
|
{
|
||||||
|
foreach (var childAnimatorStateMachine in _animatorController.layers[originalIndexToPreserveOrdering].stateMachine.stateMachines)
|
||||||
|
{
|
||||||
|
childAnimatorStateMachine.stateMachine.states = new ChildAnimatorState[0];
|
||||||
|
childAnimatorStateMachine.stateMachine.entryTransitions = new AnimatorTransition[0];
|
||||||
|
childAnimatorStateMachine.stateMachine.anyStateTransitions = new AnimatorStateTransition[0];
|
||||||
|
}
|
||||||
|
_animatorController.layers[originalIndexToPreserveOrdering].stateMachine.stateMachines = new ChildAnimatorStateMachine[0];
|
||||||
|
_animatorController.layers[originalIndexToPreserveOrdering].stateMachine.states = new ChildAnimatorState[0];
|
||||||
|
_animatorController.layers[originalIndexToPreserveOrdering].stateMachine.entryTransitions = new AnimatorTransition[0];
|
||||||
|
_animatorController.layers[originalIndexToPreserveOrdering].stateMachine.anyStateTransitions = new AnimatorStateTransition[0];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_animatorController.AddLayer(_animatorController.MakeUniqueLayerName(layerName));
|
||||||
|
originalIndexToPreserveOrdering = _animatorController.layers.Length - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
var layers = _animatorController.layers;
|
||||||
|
layers[originalIndexToPreserveOrdering].avatarMask = maskWhenCreating;
|
||||||
|
layers[originalIndexToPreserveOrdering].defaultWeight = weightWhenCreating;
|
||||||
|
_animatorController.layers = layers;
|
||||||
|
|
||||||
|
var layer = TryGetLayer(layerName);
|
||||||
|
var machinist = new AacStateMachine(layer.stateMachine, _emptyClip, new AacBackingAnimator(this), _defaultsProvider);
|
||||||
|
return machinist
|
||||||
|
.WithAnyStatePosition(0, 7)
|
||||||
|
.WithEntryPosition(0, -1)
|
||||||
|
.WithExitPosition(7, -1);
|
||||||
|
}
|
||||||
|
|
||||||
|
private int FindIndexOf(string layerName)
|
||||||
|
{
|
||||||
|
return _animatorController.layers.ToList().FindIndex(layer1 => layer1.name == layerName);
|
||||||
|
}
|
||||||
|
|
||||||
|
private AnimatorControllerLayer TryGetLayer(string layerName)
|
||||||
|
{
|
||||||
|
return _animatorController.layers.FirstOrDefault(it => it.name == layerName);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void AddLayerWithWeight(string layerName, float weightWhenCreating, AvatarMask maskWhenCreating)
|
||||||
|
{
|
||||||
|
_animatorController.AddLayer(_animatorController.MakeUniqueLayerName(layerName));
|
||||||
|
|
||||||
|
var mutatedLayers = _animatorController.layers;
|
||||||
|
mutatedLayers[mutatedLayers.Length - 1].defaultWeight = weightWhenCreating;
|
||||||
|
mutatedLayers[mutatedLayers.Length - 1].avatarMask = maskWhenCreating;
|
||||||
|
_animatorController.layers = mutatedLayers;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: cbedba2d4d2730b43b9063eccba33706
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
@@ -0,0 +1,58 @@
|
|||||||
|
using UnityEditor.Animations;
|
||||||
|
using UnityEngine;
|
||||||
|
|
||||||
|
// ReSharper disable once CheckNamespace
|
||||||
|
namespace AnimatorAsCode.V0
|
||||||
|
{
|
||||||
|
public interface IAacDefaultsProvider
|
||||||
|
{
|
||||||
|
void ConfigureState(AnimatorState state, AnimationClip emptyClip);
|
||||||
|
void ConfigureTransition(AnimatorStateTransition transition);
|
||||||
|
string ConvertLayerName(string systemName);
|
||||||
|
string ConvertLayerNameWithSuffix(string systemName, string suffix);
|
||||||
|
Vector2 Grid();
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: fe75277803d79b44091640b28b412243
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
@@ -0,0 +1,451 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using UnityEditor;
|
||||||
|
using UnityEngine;
|
||||||
|
|
||||||
|
// ReSharper disable once CheckNamespace
|
||||||
|
namespace AnimatorAsCode.V0
|
||||||
|
{
|
||||||
|
public readonly struct AacFlClip
|
||||||
|
{
|
||||||
|
private readonly AacConfiguration _component;
|
||||||
|
public AnimationClip Clip { get; }
|
||||||
|
|
||||||
|
public AacFlClip(AacConfiguration component, AnimationClip clip)
|
||||||
|
{
|
||||||
|
_component = component;
|
||||||
|
Clip = clip;
|
||||||
|
}
|
||||||
|
|
||||||
|
public AacFlClip Looping()
|
||||||
|
{
|
||||||
|
var settings = AnimationUtility.GetAnimationClipSettings(Clip);
|
||||||
|
settings.loopTime = true;
|
||||||
|
AnimationUtility.SetAnimationClipSettings(Clip, settings);
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public AacFlClip NonLooping()
|
||||||
|
{
|
||||||
|
var settings = AnimationUtility.GetAnimationClipSettings(Clip);
|
||||||
|
settings.loopTime = false;
|
||||||
|
AnimationUtility.SetAnimationClipSettings(Clip, settings);
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public AacFlClip Animating(Action<AacFlEditClip> action)
|
||||||
|
{
|
||||||
|
action.Invoke(new AacFlEditClip(_component, Clip));
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public AacFlClip Toggling(GameObject[] gameObjectsWithNulls, bool value)
|
||||||
|
{
|
||||||
|
var defensiveObjects = gameObjectsWithNulls.Where(o => o != null); // Allow users to remove an item in the middle of the array
|
||||||
|
foreach (var component in defensiveObjects)
|
||||||
|
{
|
||||||
|
var binding = AacV0.Binding(_component, typeof(GameObject), component.transform, "m_IsActive");
|
||||||
|
|
||||||
|
AnimationUtility.SetEditorCurve(Clip, binding, AacV0.OneFrame(value ? 1f : 0f));
|
||||||
|
}
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public AacFlClip BlendShape(SkinnedMeshRenderer renderer, string blendShapeName, float value)
|
||||||
|
{
|
||||||
|
var binding = AacV0.Binding(_component, typeof(SkinnedMeshRenderer), renderer.transform, $"blendShape.{blendShapeName}");
|
||||||
|
|
||||||
|
AnimationUtility.SetEditorCurve(Clip, binding, AacV0.OneFrame(value));
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public AacFlClip BlendShape(SkinnedMeshRenderer[] rendererWithNulls, string blendShapeName, float value)
|
||||||
|
{
|
||||||
|
var defensiveObjects = rendererWithNulls.Where(o => o != null); // Allow users to remove an item in the middle of the array
|
||||||
|
foreach (var component in defensiveObjects)
|
||||||
|
{
|
||||||
|
var binding = AacV0.Binding(_component, typeof(SkinnedMeshRenderer), component.transform, $"blendShape.{blendShapeName}");
|
||||||
|
|
||||||
|
AnimationUtility.SetEditorCurve(Clip, binding, AacV0.OneFrame(value));
|
||||||
|
}
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public AacFlClip Scaling(GameObject[] gameObjectsWithNulls, Vector3 scale)
|
||||||
|
{
|
||||||
|
var defensiveObjects = gameObjectsWithNulls.Where(o => o != null); // Allow users to remove an item in the middle of the array
|
||||||
|
foreach (var component in defensiveObjects)
|
||||||
|
{
|
||||||
|
AnimationUtility.SetEditorCurve(Clip, AacV0.Binding(_component, typeof(Transform), component.transform, "m_LocalScale.x"), AacV0.OneFrame(scale.x));
|
||||||
|
AnimationUtility.SetEditorCurve(Clip, AacV0.Binding(_component, typeof(Transform), component.transform, "m_LocalScale.y"), AacV0.OneFrame(scale.y));
|
||||||
|
AnimationUtility.SetEditorCurve(Clip, AacV0.Binding(_component, typeof(Transform), component.transform, "m_LocalScale.z"), AacV0.OneFrame(scale.z));
|
||||||
|
}
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public AacFlClip Toggling(GameObject gameObject, bool value)
|
||||||
|
{
|
||||||
|
var binding = AacV0.Binding(_component, typeof(GameObject), gameObject.transform, "m_IsActive");
|
||||||
|
|
||||||
|
AnimationUtility.SetEditorCurve(Clip, binding, AacV0.OneFrame(value ? 1f : 0f));
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public AacFlClip TogglingComponent(Component[] componentsWithNulls, bool value)
|
||||||
|
{
|
||||||
|
var defensiveComponents = componentsWithNulls.Where(o => o != null); // Allow users to remove an item in the middle of the array
|
||||||
|
foreach (var component in defensiveComponents)
|
||||||
|
{
|
||||||
|
var binding = AacV0.Binding(_component, component.GetType(), component.transform, "m_Enabled");
|
||||||
|
|
||||||
|
AnimationUtility.SetEditorCurve(Clip, binding, AacV0.OneFrame(value ? 1f : 0f));
|
||||||
|
}
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public AacFlClip TogglingComponent(Component component, bool value)
|
||||||
|
{
|
||||||
|
var binding = AacV0.Binding(_component, component.GetType(), component.transform, "m_Enabled");
|
||||||
|
|
||||||
|
AnimationUtility.SetEditorCurve(Clip, binding, AacV0.OneFrame(value ? 1f : 0f));
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public AacFlClip SwappingMaterial(Renderer renderer, int slot, Material material)
|
||||||
|
{
|
||||||
|
var binding = AacV0.Binding(_component, renderer.GetType(), renderer.transform, $"m_Materials.Array.data[{slot}]");
|
||||||
|
|
||||||
|
AnimationUtility.SetObjectReferenceCurve(Clip, binding, new[] {
|
||||||
|
new ObjectReferenceKeyframe { time = 0f, value = material },
|
||||||
|
new ObjectReferenceKeyframe { time = 1/60f, value = material }
|
||||||
|
});
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public AacFlClip SwappingMaterial(ParticleSystem particleSystem, int slot, Material material)
|
||||||
|
{
|
||||||
|
var binding = AacV0.Binding(_component, typeof(ParticleSystemRenderer), particleSystem.transform, $"m_Materials.Array.data[{slot}]");
|
||||||
|
|
||||||
|
AnimationUtility.SetObjectReferenceCurve(Clip, binding, new[] {
|
||||||
|
new ObjectReferenceKeyframe { time = 0f, value = material },
|
||||||
|
new ObjectReferenceKeyframe { time = 1/60f, value = material }
|
||||||
|
});
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public readonly struct AacFlEditClip
|
||||||
|
{
|
||||||
|
private readonly AacConfiguration _component;
|
||||||
|
public AnimationClip Clip { get; }
|
||||||
|
|
||||||
|
public AacFlEditClip(AacConfiguration component, AnimationClip clip)
|
||||||
|
{
|
||||||
|
_component = component;
|
||||||
|
Clip = clip;
|
||||||
|
}
|
||||||
|
|
||||||
|
public AacFlSettingCurve Animates(string path, Type type, string propertyName)
|
||||||
|
{
|
||||||
|
var binding = new EditorCurveBinding
|
||||||
|
{
|
||||||
|
path = path,
|
||||||
|
type = type,
|
||||||
|
propertyName = propertyName
|
||||||
|
};
|
||||||
|
return new AacFlSettingCurve(Clip, new[] {binding});
|
||||||
|
}
|
||||||
|
|
||||||
|
public AacFlSettingCurve Animates(Transform transform, Type type, string propertyName)
|
||||||
|
{
|
||||||
|
var binding = AacV0.Binding(_component, type, transform, propertyName);
|
||||||
|
|
||||||
|
return new AacFlSettingCurve(Clip, new[] {binding});
|
||||||
|
}
|
||||||
|
|
||||||
|
public AacFlSettingCurve Animates(GameObject gameObject)
|
||||||
|
{
|
||||||
|
var binding = AacV0.Binding(_component, typeof(GameObject), gameObject.transform, "m_IsActive");
|
||||||
|
|
||||||
|
return new AacFlSettingCurve(Clip, new[] {binding});
|
||||||
|
}
|
||||||
|
|
||||||
|
public AacFlSettingCurve Animates(Component anyComponent, string property)
|
||||||
|
{
|
||||||
|
var binding = Internal_BindingFromComponent(anyComponent, property);
|
||||||
|
|
||||||
|
return new AacFlSettingCurve(Clip, new[] {binding});
|
||||||
|
}
|
||||||
|
|
||||||
|
public AacFlSettingCurve Animates(Component[] anyComponents, string property)
|
||||||
|
{
|
||||||
|
var that = this;
|
||||||
|
var bindings = anyComponents
|
||||||
|
.Select(anyComponent => that.Internal_BindingFromComponent(anyComponent, property))
|
||||||
|
.ToArray();
|
||||||
|
|
||||||
|
return new AacFlSettingCurve(Clip, bindings);
|
||||||
|
}
|
||||||
|
|
||||||
|
public AacFlSettingCurve AnimatesAnimator(AacFlParameter floatParameter)
|
||||||
|
{
|
||||||
|
var binding = new EditorCurveBinding
|
||||||
|
{
|
||||||
|
path = "",
|
||||||
|
type = typeof(Animator),
|
||||||
|
propertyName = floatParameter.Name
|
||||||
|
};
|
||||||
|
return new AacFlSettingCurve(Clip, new[] {binding});
|
||||||
|
}
|
||||||
|
|
||||||
|
public AacFlSettingCurveColor AnimatesColor(Component anyComponent, string property)
|
||||||
|
{
|
||||||
|
var binding = Internal_BindingFromComponent(anyComponent, property);
|
||||||
|
return new AacFlSettingCurveColor(Clip, new[] {binding});
|
||||||
|
}
|
||||||
|
|
||||||
|
public AacFlSettingCurveColor AnimatesColor(Component[] anyComponents, string property)
|
||||||
|
{
|
||||||
|
var that = this;
|
||||||
|
var bindings = anyComponents
|
||||||
|
.Select(anyComponent => that.Internal_BindingFromComponent(anyComponent, property))
|
||||||
|
.ToArray();
|
||||||
|
|
||||||
|
return new AacFlSettingCurveColor(Clip, bindings);
|
||||||
|
}
|
||||||
|
|
||||||
|
public EditorCurveBinding BindingFromComponent(Component anyComponent, string propertyName)
|
||||||
|
{
|
||||||
|
return Internal_BindingFromComponent(anyComponent, propertyName);
|
||||||
|
}
|
||||||
|
|
||||||
|
private EditorCurveBinding Internal_BindingFromComponent(Component anyComponent, string propertyName)
|
||||||
|
{
|
||||||
|
return AacV0.Binding(_component, anyComponent.GetType(), anyComponent.transform, propertyName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class AacFlSettingCurve
|
||||||
|
{
|
||||||
|
private readonly AnimationClip _clip;
|
||||||
|
private readonly EditorCurveBinding[] _bindings;
|
||||||
|
|
||||||
|
public AacFlSettingCurve(AnimationClip clip, EditorCurveBinding[] bindings)
|
||||||
|
{
|
||||||
|
_clip = clip;
|
||||||
|
_bindings = bindings;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void WithOneFrame(float desiredValue)
|
||||||
|
{
|
||||||
|
foreach (var binding in _bindings)
|
||||||
|
{
|
||||||
|
AnimationUtility.SetEditorCurve(_clip, binding, AacV0.OneFrame(desiredValue));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void WithFixedSeconds(float seconds, float desiredValue)
|
||||||
|
{
|
||||||
|
foreach (var binding in _bindings)
|
||||||
|
{
|
||||||
|
AnimationUtility.SetEditorCurve(_clip, binding, AacV0.ConstantSeconds(seconds, desiredValue));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void WithSecondsUnit(Action<AacFlSettingKeyframes> action)
|
||||||
|
{
|
||||||
|
InternalWithUnit(AacFlUnit.Seconds, action);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void WithFrameCountUnit(Action<AacFlSettingKeyframes> action)
|
||||||
|
{
|
||||||
|
InternalWithUnit(AacFlUnit.Frames, action);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void WithUnit(AacFlUnit unit, Action<AacFlSettingKeyframes> action)
|
||||||
|
{
|
||||||
|
InternalWithUnit(unit, action);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void InternalWithUnit(AacFlUnit unit, Action<AacFlSettingKeyframes> action)
|
||||||
|
{
|
||||||
|
var mutatedKeyframes = new List<Keyframe>();
|
||||||
|
var builder = new AacFlSettingKeyframes(unit, mutatedKeyframes);
|
||||||
|
action.Invoke(builder);
|
||||||
|
|
||||||
|
foreach (var binding in _bindings)
|
||||||
|
{
|
||||||
|
AnimationUtility.SetEditorCurve(_clip, binding, new AnimationCurve(mutatedKeyframes.ToArray()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class AacFlSettingCurveColor
|
||||||
|
{
|
||||||
|
private readonly AnimationClip _clip;
|
||||||
|
private readonly EditorCurveBinding[] _bindings;
|
||||||
|
|
||||||
|
public AacFlSettingCurveColor(AnimationClip clip, EditorCurveBinding[] bindings)
|
||||||
|
{
|
||||||
|
_clip = clip;
|
||||||
|
_bindings = bindings;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void WithOneFrame(Color desiredValue)
|
||||||
|
{
|
||||||
|
foreach (var binding in _bindings)
|
||||||
|
{
|
||||||
|
AnimationUtility.SetEditorCurve(_clip, AacV0.ToSubBinding(binding, "r"), AacV0.OneFrame(desiredValue.r));
|
||||||
|
AnimationUtility.SetEditorCurve(_clip, AacV0.ToSubBinding(binding, "g"), AacV0.OneFrame(desiredValue.g));
|
||||||
|
AnimationUtility.SetEditorCurve(_clip, AacV0.ToSubBinding(binding, "b"), AacV0.OneFrame(desiredValue.b));
|
||||||
|
AnimationUtility.SetEditorCurve(_clip, AacV0.ToSubBinding(binding, "a"), AacV0.OneFrame(desiredValue.a));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void WithKeyframes(AacFlUnit unit, Action<AacFlSettingKeyframesColor> action)
|
||||||
|
{
|
||||||
|
var mutatedKeyframesR = new List<Keyframe>();
|
||||||
|
var mutatedKeyframesG = new List<Keyframe>();
|
||||||
|
var mutatedKeyframesB = new List<Keyframe>();
|
||||||
|
var mutatedKeyframesA = new List<Keyframe>();
|
||||||
|
var builder = new AacFlSettingKeyframesColor(unit, mutatedKeyframesR, mutatedKeyframesG, mutatedKeyframesB, mutatedKeyframesA);
|
||||||
|
action.Invoke(builder);
|
||||||
|
|
||||||
|
foreach (var binding in _bindings)
|
||||||
|
{
|
||||||
|
AnimationUtility.SetEditorCurve(_clip, AacV0.ToSubBinding(binding, "r"), new AnimationCurve(mutatedKeyframesR.ToArray()));
|
||||||
|
AnimationUtility.SetEditorCurve(_clip, AacV0.ToSubBinding(binding, "g"), new AnimationCurve(mutatedKeyframesG.ToArray()));
|
||||||
|
AnimationUtility.SetEditorCurve(_clip, AacV0.ToSubBinding(binding, "b"), new AnimationCurve(mutatedKeyframesB.ToArray()));
|
||||||
|
AnimationUtility.SetEditorCurve(_clip, AacV0.ToSubBinding(binding, "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: fec00a00ea40dce4eb7e0adf7a1696a4
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
@@ -0,0 +1,225 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using UnityEditor.Animations;
|
||||||
|
using static AnimatorAsCode.V0.AacFlConditionSimple;
|
||||||
|
using static UnityEditor.Animations.AnimatorConditionMode;
|
||||||
|
|
||||||
|
// ReSharper disable once CheckNamespace
|
||||||
|
namespace AnimatorAsCode.V0
|
||||||
|
{
|
||||||
|
class AacFlConditionSimple : IAacFlCondition
|
||||||
|
{
|
||||||
|
private readonly Action<AacFlCondition> _action;
|
||||||
|
|
||||||
|
public AacFlConditionSimple(Action<AacFlCondition> action)
|
||||||
|
{
|
||||||
|
_action = action;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static AacFlConditionSimple Just(Action<AacFlCondition> action)
|
||||||
|
{
|
||||||
|
return new AacFlConditionSimple(action);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static AacFlConditionSimple ForEach(string[] subjects, Action<string, AacFlCondition> action)
|
||||||
|
{
|
||||||
|
return new AacFlConditionSimple(condition =>
|
||||||
|
{
|
||||||
|
foreach (var subject in subjects)
|
||||||
|
{
|
||||||
|
action.Invoke(subject, condition);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ApplyTo(AacFlCondition appender)
|
||||||
|
{
|
||||||
|
_action.Invoke(appender);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract class AacFlParameter
|
||||||
|
{
|
||||||
|
public string Name { get; }
|
||||||
|
|
||||||
|
protected AacFlParameter(string name)
|
||||||
|
{
|
||||||
|
Name = name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class AacFlFloatParameter : AacFlParameter
|
||||||
|
{
|
||||||
|
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 class AacFlIntParameter : AacFlParameter
|
||||||
|
{
|
||||||
|
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 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
|
||||||
|
{
|
||||||
|
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 class AacFlFloatParameterGroup
|
||||||
|
{
|
||||||
|
internal static AacFlFloatParameterGroup Internally(params string[] names) => new AacFlFloatParameterGroup(names);
|
||||||
|
private readonly string[] _names;
|
||||||
|
private AacFlFloatParameterGroup(params string[] names) { _names = names; }
|
||||||
|
public List<AacFlBoolParameter> ToList() => _names.Select(AacFlBoolParameter.Internally).ToList();
|
||||||
|
|
||||||
|
public IAacFlCondition AreGreaterThan(float other) => ForEach(_names, (name, condition) => condition.Add(name, Greater, other));
|
||||||
|
public IAacFlCondition AreLesserThan(float other) => ForEach(_names, (name, condition) => condition.Add(name, Less, other));
|
||||||
|
}
|
||||||
|
|
||||||
|
public class AacFlIntParameterGroup
|
||||||
|
{
|
||||||
|
internal static AacFlIntParameterGroup Internally(params string[] names) => new AacFlIntParameterGroup(names);
|
||||||
|
private readonly string[] _names;
|
||||||
|
private AacFlIntParameterGroup(params string[] names) { _names = names; }
|
||||||
|
public List<AacFlBoolParameter> ToList() => _names.Select(AacFlBoolParameter.Internally).ToList();
|
||||||
|
|
||||||
|
public IAacFlCondition AreGreaterThan(float other) => ForEach(_names, (name, condition) => condition.Add(name, Greater, other));
|
||||||
|
public IAacFlCondition AreLesserThan(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: 3efdfabd1ad83ef48a287268320facf8
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
@@ -0,0 +1,939 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using UnityEditor.Animations;
|
||||||
|
using UnityEngine;
|
||||||
|
using VRC.SDK3.Avatars.Components;
|
||||||
|
using VRC.SDKBase;
|
||||||
|
|
||||||
|
// ReSharper disable once CheckNamespace
|
||||||
|
namespace AnimatorAsCode.V0
|
||||||
|
{
|
||||||
|
internal class AacBackingAnimator
|
||||||
|
{
|
||||||
|
private readonly AacAnimatorGenerator _generator;
|
||||||
|
|
||||||
|
public AacBackingAnimator(AacAnimatorGenerator animatorGenerator)
|
||||||
|
{
|
||||||
|
_generator = animatorGenerator;
|
||||||
|
}
|
||||||
|
|
||||||
|
public AacFlBoolParameter BoolParameter(string parameterName)
|
||||||
|
{
|
||||||
|
var result = AacFlBoolParameter.Internally(parameterName);
|
||||||
|
_generator.CreateParamsAsNeeded(result);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public AacFlBoolParameter TriggerParameter(string parameterName)
|
||||||
|
{
|
||||||
|
var result = AacFlBoolParameter.Internally(parameterName);
|
||||||
|
_generator.CreateTriggerParamsAsNeeded(result);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public AacFlFloatParameter FloatParameter(string parameterName)
|
||||||
|
{
|
||||||
|
var result = AacFlFloatParameter.Internally(parameterName);
|
||||||
|
_generator.CreateParamsAsNeeded(result);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public AacFlIntParameter IntParameter(string parameterName)
|
||||||
|
{
|
||||||
|
var result = AacFlIntParameter.Internally(parameterName);
|
||||||
|
_generator.CreateParamsAsNeeded(result);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public AacFlEnumIntParameter<TEnum> EnumParameter<TEnum>(string parameterName) where TEnum : Enum
|
||||||
|
{
|
||||||
|
var result = AacFlEnumIntParameter<TEnum>.Internally<TEnum>(parameterName);
|
||||||
|
_generator.CreateParamsAsNeeded(result);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public AacFlBoolParameterGroup BoolParameters(params string[] parameterNames)
|
||||||
|
{
|
||||||
|
var result = AacFlBoolParameterGroup.Internally(parameterNames);
|
||||||
|
_generator.CreateParamsAsNeeded(result.ToList().ToArray());
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public AacFlBoolParameterGroup TriggerParameters(params string[] parameterNames)
|
||||||
|
{
|
||||||
|
var result = AacFlBoolParameterGroup.Internally(parameterNames);
|
||||||
|
_generator.CreateTriggerParamsAsNeeded(result.ToList().ToArray());
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public AacFlFloatParameterGroup FloatParameters(params string[] parameterNames)
|
||||||
|
{
|
||||||
|
var result = AacFlFloatParameterGroup.Internally(parameterNames);
|
||||||
|
_generator.CreateParamsAsNeeded(result.ToList().ToArray());
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public AacFlIntParameterGroup IntParameters(params string[] parameterNames)
|
||||||
|
{
|
||||||
|
var result = AacFlIntParameterGroup.Internally(parameterNames);
|
||||||
|
_generator.CreateParamsAsNeeded(result.ToList().ToArray());
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public AacFlBoolParameterGroup BoolParameters(params AacFlBoolParameter[] parameters)
|
||||||
|
{
|
||||||
|
var result = AacFlBoolParameterGroup.Internally(parameters.Select(parameter => parameter.Name).ToArray());
|
||||||
|
_generator.CreateParamsAsNeeded(parameters);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public AacFlBoolParameterGroup TriggerParameters(params AacFlBoolParameter[] parameters)
|
||||||
|
{
|
||||||
|
var result = AacFlBoolParameterGroup.Internally(parameters.Select(parameter => parameter.Name).ToArray());
|
||||||
|
_generator.CreateTriggerParamsAsNeeded(parameters);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public AacFlFloatParameterGroup FloatParameters(params AacFlFloatParameter[] parameters)
|
||||||
|
{
|
||||||
|
var result = AacFlFloatParameterGroup.Internally(parameters.Select(parameter => parameter.Name).ToArray());
|
||||||
|
_generator.CreateParamsAsNeeded(parameters);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public AacFlIntParameterGroup IntParameters(params AacFlIntParameter[] parameters)
|
||||||
|
{
|
||||||
|
var result = AacFlIntParameterGroup.Internally(parameters.Select(parameter => parameter.Name).ToArray());
|
||||||
|
_generator.CreateParamsAsNeeded(parameters);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal class AacStateMachine
|
||||||
|
{
|
||||||
|
private readonly AnimatorStateMachine _machine;
|
||||||
|
private readonly AnimationClip _emptyClip;
|
||||||
|
private readonly AacBackingAnimator _backingAnimator;
|
||||||
|
private readonly IAacDefaultsProvider _defaultsProvider;
|
||||||
|
private readonly float _gridShiftX;
|
||||||
|
private readonly float _gridShiftY;
|
||||||
|
|
||||||
|
public AacStateMachine(AnimatorStateMachine machine, AnimationClip emptyClip, AacBackingAnimator backingAnimator, IAacDefaultsProvider defaultsProvider)
|
||||||
|
{
|
||||||
|
_machine = machine;
|
||||||
|
_emptyClip = emptyClip;
|
||||||
|
_backingAnimator = backingAnimator;
|
||||||
|
_defaultsProvider = defaultsProvider;
|
||||||
|
|
||||||
|
var grid = defaultsProvider.Grid();
|
||||||
|
_gridShiftX = grid.x;
|
||||||
|
_gridShiftY = grid.y;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal AacBackingAnimator BackingAnimator()
|
||||||
|
{
|
||||||
|
return _backingAnimator;
|
||||||
|
}
|
||||||
|
|
||||||
|
public AacStateMachine WithEntryPosition(int x, int y)
|
||||||
|
{
|
||||||
|
_machine.entryPosition = GridPosition(x, y);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public AacStateMachine WithExitPosition(int x, int y)
|
||||||
|
{
|
||||||
|
_machine.exitPosition = GridPosition(x, y);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public AacStateMachine WithAnyStatePosition(int x, int y)
|
||||||
|
{
|
||||||
|
_machine.anyStatePosition = GridPosition(x, y);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public AacFlState NewState(string name, int x, int y)
|
||||||
|
{
|
||||||
|
var state = _machine.AddState(name, GridPosition(x, y));
|
||||||
|
_defaultsProvider.ConfigureState(state, _emptyClip);
|
||||||
|
|
||||||
|
return new AacFlState(state, _machine, _defaultsProvider);
|
||||||
|
}
|
||||||
|
|
||||||
|
public AacFlTransition AnyTransitionsTo(AacFlState destination)
|
||||||
|
{
|
||||||
|
return AnyTransition(destination, _machine);
|
||||||
|
}
|
||||||
|
|
||||||
|
public AacFlEntryTransition EntryTransitionsTo(AacFlState destination)
|
||||||
|
{
|
||||||
|
return EntryTransition(destination, _machine);
|
||||||
|
}
|
||||||
|
|
||||||
|
private AacFlTransition AnyTransition(AacFlState destination, AnimatorStateMachine animatorStateMachine)
|
||||||
|
{
|
||||||
|
return new AacFlTransition(ConfigureTransition(animatorStateMachine.AddAnyStateTransition(destination.State)), animatorStateMachine, null, destination.State);
|
||||||
|
}
|
||||||
|
|
||||||
|
private AnimatorStateTransition ConfigureTransition(AnimatorStateTransition transition)
|
||||||
|
{
|
||||||
|
_defaultsProvider.ConfigureTransition(transition);
|
||||||
|
return transition;
|
||||||
|
}
|
||||||
|
|
||||||
|
private AacFlEntryTransition EntryTransition(AacFlState destination, AnimatorStateMachine animatorStateMachine)
|
||||||
|
{
|
||||||
|
return new AacFlEntryTransition(animatorStateMachine.AddEntryTransition(destination.State), animatorStateMachine, null, destination.State);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal Vector3 LastStatePosition()
|
||||||
|
{
|
||||||
|
return _machine.states.Length > 0 ? _machine.states.Last().position : Vector3.zero;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Vector3 GridPosition(int x, int y)
|
||||||
|
{
|
||||||
|
return new Vector3(x * _gridShiftX , y * _gridShiftY, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class AacFlState
|
||||||
|
{
|
||||||
|
public readonly AnimatorState State;
|
||||||
|
private readonly AnimatorStateMachine _machine;
|
||||||
|
private readonly IAacDefaultsProvider _defaultsProvider;
|
||||||
|
private readonly AacBackingAnimator _backingAnimator;
|
||||||
|
private VRCAvatarParameterDriver _driver;
|
||||||
|
private VRCAnimatorTrackingControl _tracking;
|
||||||
|
private VRCAnimatorLocomotionControl _locomotionControl;
|
||||||
|
|
||||||
|
public AacFlState(AnimatorState state, AnimatorStateMachine machine, IAacDefaultsProvider defaultsProvider)
|
||||||
|
{
|
||||||
|
State = state;
|
||||||
|
_machine = machine;
|
||||||
|
_defaultsProvider = defaultsProvider;
|
||||||
|
}
|
||||||
|
|
||||||
|
public AacFlState LeftOf(AacFlState otherState) => MoveNextTo(otherState, -1, 0);
|
||||||
|
public AacFlState RightOf(AacFlState otherState) => MoveNextTo(otherState, 1, 0);
|
||||||
|
public AacFlState Over(AacFlState otherState) => MoveNextTo(otherState, 0, -1);
|
||||||
|
public AacFlState Under(AacFlState otherState) => MoveNextTo(otherState, 0, 1);
|
||||||
|
|
||||||
|
public AacFlState LeftOf() => MoveNextTo(null, -1, 0);
|
||||||
|
public AacFlState RightOf() => MoveNextTo(null, 1, 0);
|
||||||
|
public AacFlState Over() => MoveNextTo(null, 0, -1);
|
||||||
|
public AacFlState Under() => MoveNextTo(null, 0, 1);
|
||||||
|
|
||||||
|
public AacFlState Shift(AacFlState otherState, int shiftX, int shiftY) => MoveNextTo(otherState, shiftX, shiftY);
|
||||||
|
|
||||||
|
private AacFlState MoveNextTo(AacFlState otherStateOrSecondToLastWhenNull, int x, int y)
|
||||||
|
{
|
||||||
|
if (otherStateOrSecondToLastWhenNull == null)
|
||||||
|
{
|
||||||
|
var other = _machine.states[_machine.states.Length - 2];
|
||||||
|
Shift(other.position, x, y);
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var other = _machine.states.First(animatorState => animatorState.state == otherStateOrSecondToLastWhenNull.State);
|
||||||
|
Shift(other.position, x, y);
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public AacFlState Shift(Vector3 otherPosition, int shiftX, int shiftY)
|
||||||
|
{
|
||||||
|
var states = _machine.states;
|
||||||
|
for (var index = 0; index < states.Length; index++)
|
||||||
|
{
|
||||||
|
var childAnimatorState = states[index];
|
||||||
|
if (childAnimatorState.state == State)
|
||||||
|
{
|
||||||
|
var cms = childAnimatorState;
|
||||||
|
cms.position = otherPosition + new Vector3(shiftX * _defaultsProvider.Grid().x, shiftY * _defaultsProvider.Grid().y, 0);
|
||||||
|
states[index] = cms;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_machine.states = states;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public AacFlState WithAnimation(Motion clip)
|
||||||
|
{
|
||||||
|
State.motion = clip;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public AacFlState WithAnimation(AacFlClip clip)
|
||||||
|
{
|
||||||
|
State.motion = clip.Clip;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public AacFlTransition TransitionsTo(AacFlState destination)
|
||||||
|
{
|
||||||
|
return new AacFlTransition(ConfigureTransition(State.AddTransition(destination.State)), _machine, State, destination.State);
|
||||||
|
}
|
||||||
|
|
||||||
|
public AacFlTransition TransitionsFromAny()
|
||||||
|
{
|
||||||
|
return new AacFlTransition(ConfigureTransition(_machine.AddAnyStateTransition(State)), _machine, null, State);
|
||||||
|
}
|
||||||
|
|
||||||
|
public AacFlEntryTransition TransitionsFromEntry()
|
||||||
|
{
|
||||||
|
return new AacFlEntryTransition(_machine.AddEntryTransition(State), _machine, null, State);
|
||||||
|
}
|
||||||
|
|
||||||
|
public AacFlState AutomaticallyMovesTo(AacFlState destination)
|
||||||
|
{
|
||||||
|
var transition = ConfigureTransition(State.AddTransition(destination.State));
|
||||||
|
transition.hasExitTime = true;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public AacFlTransition Exits()
|
||||||
|
{
|
||||||
|
return new AacFlTransition(ConfigureTransition(State.AddExitTransition()), _machine, State, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
private AnimatorStateTransition ConfigureTransition(AnimatorStateTransition transition)
|
||||||
|
{
|
||||||
|
_defaultsProvider.ConfigureTransition(transition);
|
||||||
|
return transition;
|
||||||
|
}
|
||||||
|
|
||||||
|
public AacFlState Drives(AacFlIntParameter parameter, int value)
|
||||||
|
{
|
||||||
|
CreateDriverBehaviorIfNotExists();
|
||||||
|
_driver.parameters.Add(new VRC_AvatarParameterDriver.Parameter
|
||||||
|
{
|
||||||
|
type = VRC_AvatarParameterDriver.ChangeType.Set,
|
||||||
|
name = parameter.Name, value = value
|
||||||
|
});
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public AacFlState Drives(AacFlFloatParameter parameter, float value)
|
||||||
|
{
|
||||||
|
CreateDriverBehaviorIfNotExists();
|
||||||
|
_driver.parameters.Add(new VRC_AvatarParameterDriver.Parameter
|
||||||
|
{
|
||||||
|
type = VRC_AvatarParameterDriver.ChangeType.Set,
|
||||||
|
name = parameter.Name, value = value
|
||||||
|
});
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public AacFlState DrivingIncreases(AacFlFloatParameter parameter, float additiveValue)
|
||||||
|
{
|
||||||
|
CreateDriverBehaviorIfNotExists();
|
||||||
|
_driver.parameters.Add(new VRC_AvatarParameterDriver.Parameter
|
||||||
|
{
|
||||||
|
type = VRC_AvatarParameterDriver.ChangeType.Add,
|
||||||
|
name = parameter.Name, value = additiveValue
|
||||||
|
});
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public AacFlState DrivingDecreases(AacFlFloatParameter parameter, float positiveValueToDecreaseBy)
|
||||||
|
{
|
||||||
|
CreateDriverBehaviorIfNotExists();
|
||||||
|
_driver.parameters.Add(new VRC_AvatarParameterDriver.Parameter
|
||||||
|
{
|
||||||
|
type = VRC_AvatarParameterDriver.ChangeType.Add,
|
||||||
|
name = parameter.Name, value = -positiveValueToDecreaseBy
|
||||||
|
});
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public AacFlState DrivingRandomizesLocally(AacFlFloatParameter parameter, float min, float max)
|
||||||
|
{
|
||||||
|
CreateDriverBehaviorIfNotExists();
|
||||||
|
_driver.parameters.Add(new VRC_AvatarParameterDriver.Parameter
|
||||||
|
{
|
||||||
|
type = VRC_AvatarParameterDriver.ChangeType.Random,
|
||||||
|
name = parameter.Name, valueMin = min, valueMax = max
|
||||||
|
});
|
||||||
|
_driver.localOnly = true;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public AacFlState DrivingRandomizesLocally(AacFlIntParameter parameter, int min, int max)
|
||||||
|
{
|
||||||
|
CreateDriverBehaviorIfNotExists();
|
||||||
|
_driver.parameters.Add(new VRC_AvatarParameterDriver.Parameter
|
||||||
|
{
|
||||||
|
type = VRC_AvatarParameterDriver.ChangeType.Random,
|
||||||
|
name = parameter.Name, valueMin = min, valueMax = max
|
||||||
|
});
|
||||||
|
_driver.localOnly = true;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public AacFlState Drives(AacFlBoolParameter parameter, bool value)
|
||||||
|
{
|
||||||
|
CreateDriverBehaviorIfNotExists();
|
||||||
|
_driver.parameters.Add(new VRC_AvatarParameterDriver.Parameter
|
||||||
|
{
|
||||||
|
name = parameter.Name, value = value ? 1 : 0
|
||||||
|
});
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public AacFlState Drives(AacFlBoolParameterGroup parameters, bool value)
|
||||||
|
{
|
||||||
|
CreateDriverBehaviorIfNotExists();
|
||||||
|
foreach (var parameter in parameters.ToList())
|
||||||
|
{
|
||||||
|
_driver.parameters.Add(new VRC_AvatarParameterDriver.Parameter
|
||||||
|
{
|
||||||
|
name = parameter.Name, value = value ? 1 : 0
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public AacFlState DrivingLocally()
|
||||||
|
{
|
||||||
|
CreateDriverBehaviorIfNotExists();
|
||||||
|
_driver.localOnly = true;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void CreateDriverBehaviorIfNotExists()
|
||||||
|
{
|
||||||
|
if (_driver != null) return;
|
||||||
|
_driver = State.AddStateMachineBehaviour<VRCAvatarParameterDriver>();
|
||||||
|
_driver.parameters = new List<VRC_AvatarParameterDriver.Parameter>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public AacFlState WithWriteDefaultsSetTo(bool shouldWriteDefaults)
|
||||||
|
{
|
||||||
|
State.writeDefaultValues = shouldWriteDefaults;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public AacFlState PrintsToLogUsingTrackingBehaviour(string value)
|
||||||
|
{
|
||||||
|
CreateTrackingBehaviorIfNotExists();
|
||||||
|
_tracking.debugString = value;
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public AacFlState TrackingTracks(TrackingElement element)
|
||||||
|
{
|
||||||
|
CreateTrackingBehaviorIfNotExists();
|
||||||
|
SettingElementTo(element, VRC_AnimatorTrackingControl.TrackingType.Tracking);
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public AacFlState TrackingAnimates(TrackingElement element)
|
||||||
|
{
|
||||||
|
CreateTrackingBehaviorIfNotExists();
|
||||||
|
SettingElementTo(element, VRC_AnimatorTrackingControl.TrackingType.Animation);
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public AacFlState TrackingSets(TrackingElement element, VRC_AnimatorTrackingControl.TrackingType trackingType)
|
||||||
|
{
|
||||||
|
CreateTrackingBehaviorIfNotExists();
|
||||||
|
SettingElementTo(element, trackingType);
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public AacFlState LocomotionEnabled()
|
||||||
|
{
|
||||||
|
CreateLocomotionBehaviorIfNotExists();
|
||||||
|
_locomotionControl.disableLocomotion = false;
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public AacFlState LocomotionDisabled()
|
||||||
|
{
|
||||||
|
CreateLocomotionBehaviorIfNotExists();
|
||||||
|
_locomotionControl.disableLocomotion = true;
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public AacFlState MotionTime(AacFlFloatParameter floatParam)
|
||||||
|
{
|
||||||
|
State.timeParameterActive = true;
|
||||||
|
State.timeParameter = floatParam.Name;
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void SettingElementTo(TrackingElement element, VRC_AnimatorTrackingControl.TrackingType target)
|
||||||
|
{
|
||||||
|
switch (element)
|
||||||
|
{
|
||||||
|
case TrackingElement.Head:
|
||||||
|
_tracking.trackingHead = target;
|
||||||
|
break;
|
||||||
|
case TrackingElement.LeftHand:
|
||||||
|
_tracking.trackingLeftHand = target;
|
||||||
|
break;
|
||||||
|
case TrackingElement.RightHand:
|
||||||
|
_tracking.trackingRightHand = target;
|
||||||
|
break;
|
||||||
|
case TrackingElement.Hip:
|
||||||
|
_tracking.trackingHip = target;
|
||||||
|
break;
|
||||||
|
case TrackingElement.LeftFoot:
|
||||||
|
_tracking.trackingLeftFoot = target;
|
||||||
|
break;
|
||||||
|
case TrackingElement.RightFoot:
|
||||||
|
_tracking.trackingRightFoot = target;
|
||||||
|
break;
|
||||||
|
case TrackingElement.LeftFingers:
|
||||||
|
_tracking.trackingLeftFingers = target;
|
||||||
|
break;
|
||||||
|
case TrackingElement.RightFingers:
|
||||||
|
_tracking.trackingRightFingers = target;
|
||||||
|
break;
|
||||||
|
case TrackingElement.Eyes:
|
||||||
|
_tracking.trackingEyes = target;
|
||||||
|
break;
|
||||||
|
case TrackingElement.Mouth:
|
||||||
|
_tracking.trackingMouth = target;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new ArgumentOutOfRangeException(nameof(element), element, null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void CreateTrackingBehaviorIfNotExists()
|
||||||
|
{
|
||||||
|
if (_tracking != null) return;
|
||||||
|
_tracking = State.AddStateMachineBehaviour<VRCAnimatorTrackingControl>();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private void CreateLocomotionBehaviorIfNotExists()
|
||||||
|
{
|
||||||
|
if (_locomotionControl != null) return;
|
||||||
|
_locomotionControl = State.AddStateMachineBehaviour<VRCAnimatorLocomotionControl>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum TrackingElement
|
||||||
|
{
|
||||||
|
Head,
|
||||||
|
LeftHand,
|
||||||
|
RightHand,
|
||||||
|
Hip,
|
||||||
|
LeftFoot,
|
||||||
|
RightFoot,
|
||||||
|
LeftFingers,
|
||||||
|
RightFingers,
|
||||||
|
Eyes,
|
||||||
|
Mouth
|
||||||
|
}
|
||||||
|
|
||||||
|
public AacFlState WithSpeed(AacFlFloatParameter parameter)
|
||||||
|
{
|
||||||
|
State.speedParameter = parameter.Name;
|
||||||
|
State.speedParameterActive = true;
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class AacFlTransition : AacFlNewTransitionContinuation
|
||||||
|
{
|
||||||
|
private readonly AnimatorStateTransition _transition;
|
||||||
|
|
||||||
|
public AacFlTransition(AnimatorStateTransition transition, AnimatorStateMachine machine, AnimatorState sourceNullableIfAny, AnimatorState destinationNullableIfExits) : base(transition, machine, sourceNullableIfAny, destinationNullableIfExits)
|
||||||
|
{
|
||||||
|
_transition = transition;
|
||||||
|
}
|
||||||
|
|
||||||
|
public AacFlTransition WithSourceInterruption()
|
||||||
|
{
|
||||||
|
_transition.interruptionSource = TransitionInterruptionSource.Source;
|
||||||
|
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 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, AnimatorState destinationNullableIfExits) : base(transition, machine, sourceNullableIfAny, destinationNullableIfExits)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public interface IAacFlCondition
|
||||||
|
{
|
||||||
|
void ApplyTo(AacFlCondition appender);
|
||||||
|
}
|
||||||
|
|
||||||
|
public interface IAacFlOrCondition
|
||||||
|
{
|
||||||
|
List<AacFlTransitionContinuation> ApplyTo(AacFlNewTransitionContinuation firstContinuation);
|
||||||
|
}
|
||||||
|
|
||||||
|
public class AacFlCondition
|
||||||
|
{
|
||||||
|
private readonly AnimatorTransitionBase _transition;
|
||||||
|
|
||||||
|
public AacFlCondition(AnimatorTransitionBase transition)
|
||||||
|
{
|
||||||
|
_transition = transition;
|
||||||
|
}
|
||||||
|
|
||||||
|
public AacFlCondition Add(string parameter, AnimatorConditionMode mode, float threshold)
|
||||||
|
{
|
||||||
|
_transition.AddCondition(mode, threshold, parameter);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class AacFlNewTransitionContinuation
|
||||||
|
{
|
||||||
|
public readonly AnimatorTransitionBase Transition;
|
||||||
|
private readonly AnimatorStateMachine _machine;
|
||||||
|
private readonly AnimatorState _sourceNullableIfAny;
|
||||||
|
private readonly AnimatorState _destinationNullableIfExits;
|
||||||
|
|
||||||
|
public AacFlNewTransitionContinuation(AnimatorTransitionBase transition, AnimatorStateMachine machine, AnimatorState sourceNullableIfAny, AnimatorState 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, AnimatorState sourceNullableIfAny, AnimatorState 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, AnimatorState sourceNullableIfAny, AnimatorState 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, AnimatorState sourceNullableIfAny, AnimatorState destinationNullableIfExits) : base(transition, machine, sourceNullableIfAny, destinationNullableIfExits)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract class AacFlTransitionContinuationAbstractWithOr
|
||||||
|
{
|
||||||
|
protected readonly AnimatorTransitionBase Transition;
|
||||||
|
private readonly AnimatorStateMachine _machine;
|
||||||
|
private readonly AnimatorState _sourceNullableIfAny;
|
||||||
|
private readonly AnimatorState _destinationNullableIfExits;
|
||||||
|
|
||||||
|
public AacFlTransitionContinuationAbstractWithOr(AnimatorTransitionBase transition, AnimatorStateMachine machine, AnimatorState sourceNullableIfAny, AnimatorState 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
|
||||||
|
{
|
||||||
|
newTransition = _machine.AddEntryTransition(_destinationNullableIfExits);
|
||||||
|
}
|
||||||
|
|
||||||
|
return newTransition;
|
||||||
|
}
|
||||||
|
|
||||||
|
private AnimatorStateTransition NewTransition()
|
||||||
|
{
|
||||||
|
if (_sourceNullableIfAny == null)
|
||||||
|
{
|
||||||
|
return _machine.AddAnyStateTransition(_destinationNullableIfExits);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_destinationNullableIfExits == null)
|
||||||
|
{
|
||||||
|
return _sourceNullableIfAny.AddExitTransition();
|
||||||
|
}
|
||||||
|
|
||||||
|
return _sourceNullableIfAny.AddTransition(_destinationNullableIfExits);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: c0a803c4ceabee84b9081a8728fc4bf9
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2022 Haï~ (@vr_hai github.com/hai-vr)
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
Reference in New Issue
Block a user