mirror of
https://github.com/bdunderscore/modular-avatar.git
synced 2025-04-11 23:19:00 +08:00
Merge branch 'main' into enhance_EasySetupOutfit_humanoid
This commit is contained in:
commit
05b97e74e5
4
.github/ProjectRoot/vpm-manifest-2022.json
vendored
4
.github/ProjectRoot/vpm-manifest-2022.json
vendored
@ -4,7 +4,7 @@
|
|||||||
"version": "3.7.0"
|
"version": "3.7.0"
|
||||||
},
|
},
|
||||||
"nadena.dev.ndmf": {
|
"nadena.dev.ndmf": {
|
||||||
"version": "1.4.0"
|
"version": "1.5.6"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
@ -19,7 +19,7 @@
|
|||||||
"dependencies": {}
|
"dependencies": {}
|
||||||
},
|
},
|
||||||
"nadena.dev.ndmf": {
|
"nadena.dev.ndmf": {
|
||||||
"version": "1.5.3"
|
"version": "1.5.6"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -7,7 +7,9 @@ using nadena.dev.ndmf;
|
|||||||
using UnityEditor;
|
using UnityEditor;
|
||||||
using UnityEditor.Animations;
|
using UnityEditor.Animations;
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
|
#if MA_VRCSDK3_AVATARS
|
||||||
using VRC.SDK3.Avatars.Components;
|
using VRC.SDK3.Avatars.Components;
|
||||||
|
#endif
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
@ -89,12 +91,14 @@ namespace nadena.dev.modular_avatar.animation
|
|||||||
// HACK: This is a temporary crutch until we rework the entire animator services system
|
// HACK: This is a temporary crutch until we rework the entire animator services system
|
||||||
public void AddPropertyDefinition(AnimatorControllerParameter paramDef)
|
public void AddPropertyDefinition(AnimatorControllerParameter paramDef)
|
||||||
{
|
{
|
||||||
|
#if MA_VRCSDK3_AVATARS
|
||||||
var fx = (AnimatorController)
|
var fx = (AnimatorController)
|
||||||
_context.AvatarDescriptor.baseAnimationLayers
|
_context.AvatarDescriptor.baseAnimationLayers
|
||||||
.First(l => l.type == VRCAvatarDescriptor.AnimLayerType.FX)
|
.First(l => l.type == VRCAvatarDescriptor.AnimLayerType.FX)
|
||||||
.animatorController;
|
.animatorController;
|
||||||
|
|
||||||
fx.parameters = fx.parameters.Concat(new[] { paramDef }).ToArray();
|
fx.parameters = fx.parameters.Concat(new[] { paramDef }).ToArray();
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
public string GetActiveSelfProxy(GameObject obj)
|
public string GetActiveSelfProxy(GameObject obj)
|
||||||
|
@ -1,9 +1,12 @@
|
|||||||
using System.Linq;
|
#if MA_VRCSDK3_AVATARS
|
||||||
|
using System.Linq;
|
||||||
|
using nadena.dev.modular_avatar.core.editor;
|
||||||
using nadena.dev.ndmf;
|
using nadena.dev.ndmf;
|
||||||
using UnityEditor;
|
using UnityEditor;
|
||||||
using UnityEditor.Animations;
|
using UnityEditor.Animations;
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
using VRC.SDK3.Avatars.Components;
|
using VRC.SDK3.Avatars.Components;
|
||||||
|
using BuildContext = nadena.dev.ndmf.BuildContext;
|
||||||
|
|
||||||
namespace nadena.dev.modular_avatar.animation
|
namespace nadena.dev.modular_avatar.animation
|
||||||
{
|
{
|
||||||
@ -23,11 +26,16 @@ namespace nadena.dev.modular_avatar.animation
|
|||||||
|
|
||||||
if (fx == null) return;
|
if (fx == null) return;
|
||||||
|
|
||||||
|
var nullMotion = new AnimationClip();
|
||||||
|
nullMotion.name = "NullMotion";
|
||||||
|
|
||||||
var blendTree = new BlendTree();
|
var blendTree = new BlendTree();
|
||||||
blendTree.blendType = BlendTreeType.Direct;
|
blendTree.blendType = BlendTreeType.Direct;
|
||||||
blendTree.useAutomaticThresholds = false;
|
blendTree.useAutomaticThresholds = false;
|
||||||
|
|
||||||
blendTree.children = asc.BoundReadableProperties.Select(GenerateDelayChild).ToArray();
|
blendTree.children = asc.BoundReadableProperties
|
||||||
|
.Select(prop => GenerateDelayChild(nullMotion, prop))
|
||||||
|
.ToArray();
|
||||||
|
|
||||||
var asm = new AnimatorStateMachine();
|
var asm = new AnimatorStateMachine();
|
||||||
var state = new AnimatorState();
|
var state = new AnimatorState();
|
||||||
@ -52,9 +60,24 @@ namespace nadena.dev.modular_avatar.animation
|
|||||||
defaultWeight = 1,
|
defaultWeight = 1,
|
||||||
blendingMode = AnimatorLayerBlendingMode.Override
|
blendingMode = AnimatorLayerBlendingMode.Override
|
||||||
}).ToArray();
|
}).ToArray();
|
||||||
|
|
||||||
|
// Ensure the initial state of readable props matches the actual state of the gameobject
|
||||||
|
var parameters = fx.parameters;
|
||||||
|
var paramToIndex = parameters.Select((p, i) => (p, i)).ToDictionary(x => x.p.name, x => x.i);
|
||||||
|
foreach (var (binding, prop) in asc.BoundReadableProperties)
|
||||||
|
{
|
||||||
|
var obj = asc.PathMappings.PathToObject(binding.path);
|
||||||
|
|
||||||
|
if (obj != null && paramToIndex.TryGetValue(prop, out var index))
|
||||||
|
{
|
||||||
|
parameters[index].defaultFloat = obj.activeSelf ? 1 : 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fx.parameters = parameters;
|
||||||
}
|
}
|
||||||
|
|
||||||
private ChildMotion GenerateDelayChild((EditorCurveBinding, string) binding)
|
private ChildMotion GenerateDelayChild(Motion nullMotion, (EditorCurveBinding, string) binding)
|
||||||
{
|
{
|
||||||
var ecb = binding.Item1;
|
var ecb = binding.Item1;
|
||||||
var prop = binding.Item2;
|
var prop = binding.Item2;
|
||||||
@ -64,12 +87,43 @@ namespace nadena.dev.modular_avatar.animation
|
|||||||
curve.AddKey(0, 1);
|
curve.AddKey(0, 1);
|
||||||
AnimationUtility.SetEditorCurve(motion, ecb, curve);
|
AnimationUtility.SetEditorCurve(motion, ecb, curve);
|
||||||
|
|
||||||
|
// Occasionally, we'll have a very small value pop up, probably due to FP errors.
|
||||||
|
// To correct for this, instead of directly using the property in the direct blend tree,
|
||||||
|
// we'll use a 1D blend tree to give ourselves a buffer.
|
||||||
|
|
||||||
|
var bufferBlendTree = new BlendTree();
|
||||||
|
bufferBlendTree.blendType = BlendTreeType.Simple1D;
|
||||||
|
bufferBlendTree.useAutomaticThresholds = false;
|
||||||
|
bufferBlendTree.blendParameter = prop;
|
||||||
|
bufferBlendTree.children = new[]
|
||||||
|
{
|
||||||
|
new ChildMotion
|
||||||
|
{
|
||||||
|
motion = nullMotion,
|
||||||
|
timeScale = 1,
|
||||||
|
threshold = 0
|
||||||
|
},
|
||||||
|
new ChildMotion
|
||||||
|
{
|
||||||
|
motion = nullMotion,
|
||||||
|
timeScale = 1,
|
||||||
|
threshold = 0.01f
|
||||||
|
},
|
||||||
|
new ChildMotion
|
||||||
|
{
|
||||||
|
motion = motion,
|
||||||
|
timeScale = 1,
|
||||||
|
threshold = 1
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
return new ChildMotion
|
return new ChildMotion
|
||||||
{
|
{
|
||||||
motion = motion,
|
motion = bufferBlendTree,
|
||||||
directBlendParameter = prop,
|
directBlendParameter = MergeBlendTreePass.ALWAYS_ONE,
|
||||||
timeScale = 1
|
timeScale = 1
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#endif
|
@ -368,6 +368,7 @@ namespace nadena.dev.modular_avatar.animation
|
|||||||
}
|
}
|
||||||
Profiler.EndSample();
|
Profiler.EndSample();
|
||||||
|
|
||||||
|
#if MA_VRCSDK3_AVATARS
|
||||||
var layers = context.AvatarDescriptor.baseAnimationLayers
|
var layers = context.AvatarDescriptor.baseAnimationLayers
|
||||||
.Concat(context.AvatarDescriptor.specialAnimationLayers);
|
.Concat(context.AvatarDescriptor.specialAnimationLayers);
|
||||||
|
|
||||||
@ -383,6 +384,7 @@ namespace nadena.dev.modular_avatar.animation
|
|||||||
ApplyMappingsToAvatarMask(acLayer.avatarMask);
|
ApplyMappingsToAvatarMask(acLayer.avatarMask);
|
||||||
}
|
}
|
||||||
Profiler.EndSample();
|
Profiler.EndSample();
|
||||||
|
#endif
|
||||||
|
|
||||||
Profiler.EndSample();
|
Profiler.EndSample();
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
#region
|
#if MA_VRCSDK3_AVATARS
|
||||||
|
#region
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Immutable;
|
using System.Collections.Immutable;
|
||||||
@ -57,4 +58,5 @@ namespace nadena.dev.modular_avatar.core.editor
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#endif
|
@ -1,4 +1,5 @@
|
|||||||
using UnityEditor;
|
#if MA_VRCSDK3_AVATARS
|
||||||
|
using UnityEditor;
|
||||||
|
|
||||||
namespace nadena.dev.modular_avatar.core.editor
|
namespace nadena.dev.modular_avatar.core.editor
|
||||||
{
|
{
|
||||||
@ -45,3 +46,5 @@ namespace nadena.dev.modular_avatar.core.editor
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endif
|
@ -368,7 +368,7 @@ namespace nadena.dev.modular_avatar.core.editor
|
|||||||
|
|
||||||
serializedObject.ApplyModifiedProperties();
|
serializedObject.ApplyModifiedProperties();
|
||||||
|
|
||||||
Localization.ShowLanguageUI();
|
ShowLanguageUI();
|
||||||
}
|
}
|
||||||
|
|
||||||
private string ObjectHierarchyOrder(Component arg)
|
private string ObjectHierarchyOrder(Component arg)
|
||||||
@ -415,6 +415,9 @@ namespace nadena.dev.modular_avatar.core.editor
|
|||||||
var group = installer.gameObject.AddComponent<ModularAvatarMenuGroup>();
|
var group = installer.gameObject.AddComponent<ModularAvatarMenuGroup>();
|
||||||
var menuRoot = new GameObject();
|
var menuRoot = new GameObject();
|
||||||
menuRoot.name = "Menu";
|
menuRoot.name = "Menu";
|
||||||
|
|
||||||
|
group.targetObject = menuRoot;
|
||||||
|
|
||||||
Undo.RegisterCreatedObjectUndo(menuRoot, "Extract menu");
|
Undo.RegisterCreatedObjectUndo(menuRoot, "Extract menu");
|
||||||
menuRoot.transform.SetParent(group.transform, false);
|
menuRoot.transform.SetParent(group.transform, false);
|
||||||
foreach (var control in menu.controls)
|
foreach (var control in menu.controls)
|
||||||
|
@ -301,10 +301,9 @@ namespace nadena.dev.modular_avatar.core.editor
|
|||||||
EditorGUILayout.BeginVertical();
|
EditorGUILayout.BeginVertical();
|
||||||
|
|
||||||
if (_type.hasMultipleDifferentValues) return;
|
if (_type.hasMultipleDifferentValues) return;
|
||||||
VRCExpressionsMenu.Control.ControlType type =
|
var controlTypeArray = Enum.GetValues(typeof(VRCExpressionsMenu.Control.ControlType));
|
||||||
(VRCExpressionsMenu.Control.ControlType) Enum
|
var index = Math.Clamp(_type.enumValueIndex, 0, controlTypeArray.Length - 1);
|
||||||
.GetValues(typeof(VRCExpressionsMenu.Control.ControlType))
|
var type = (VRCExpressionsMenu.Control.ControlType)controlTypeArray.GetValue(index);
|
||||||
.GetValue(_type.enumValueIndex);
|
|
||||||
|
|
||||||
switch (type)
|
switch (type)
|
||||||
{
|
{
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
using nadena.dev.modular_avatar.ui;
|
#if MA_VRCSDK3_AVATARS
|
||||||
|
using nadena.dev.modular_avatar.ui;
|
||||||
using UnityEditor;
|
using UnityEditor;
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
using VRC.SDK3.Avatars.ScriptableObjects;
|
using VRC.SDK3.Avatars.ScriptableObjects;
|
||||||
@ -62,4 +63,5 @@ namespace nadena.dev.modular_avatar.core.editor
|
|||||||
Undo.RegisterCreatedObjectUndo(toggle, "Create Toggle");
|
Undo.RegisterCreatedObjectUndo(toggle, "Create Toggle");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#endif
|
@ -20,7 +20,8 @@ namespace nadena.dev.modular_avatar.core.editor
|
|||||||
private readonly DropdownField _boolField;
|
private readonly DropdownField _boolField;
|
||||||
|
|
||||||
private ParameterSyncType _syncType;
|
private ParameterSyncType _syncType;
|
||||||
|
private bool _hasInitialBinding;
|
||||||
|
|
||||||
public DefaultValueField()
|
public DefaultValueField()
|
||||||
{
|
{
|
||||||
// Hidden binding elements
|
// Hidden binding elements
|
||||||
@ -57,28 +58,39 @@ namespace nadena.dev.modular_avatar.core.editor
|
|||||||
{
|
{
|
||||||
_numberField.style.display = DisplayStyle.Flex;
|
_numberField.style.display = DisplayStyle.Flex;
|
||||||
_boolField.style.display = DisplayStyle.None;
|
_boolField.style.display = DisplayStyle.None;
|
||||||
OnUpdateNumberValue(_numberField.value);
|
OnUpdateNumberValue(_numberField.value, true);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
_numberField.style.display = DisplayStyle.None;
|
_numberField.style.display = DisplayStyle.None;
|
||||||
_boolField.style.display = DisplayStyle.Flex;
|
_boolField.style.display = DisplayStyle.Flex;
|
||||||
OnUpdateBoolValue(_boolField.value);
|
OnUpdateBoolValue(_boolField.value, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnUpdateNumberValue(string value)
|
private void OnUpdateNumberValue(string value, bool implicitUpdate = false)
|
||||||
{
|
{
|
||||||
|
// Upon initial creation, sometimes the OnUpdateSyncType fires before we receive the initial value event.
|
||||||
|
// In this case, suppress the update to avoid losing data.
|
||||||
|
if (implicitUpdate && !_hasInitialBinding) return;
|
||||||
|
|
||||||
|
var theValue = _defaultValueField.value;
|
||||||
if (string.IsNullOrWhiteSpace(value))
|
if (string.IsNullOrWhiteSpace(value))
|
||||||
{
|
{
|
||||||
_defaultValueField.value = 0;
|
if (!implicitUpdate)
|
||||||
|
{
|
||||||
|
_defaultValueField.value = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
theValue = _defaultValueField.value;
|
||||||
|
|
||||||
_hasExplicitDefaultValueField.value = false;
|
_hasExplicitDefaultValueField.value = false;
|
||||||
}
|
}
|
||||||
else if (float.TryParse(value, NumberStyles.Float, CultureInfo.InvariantCulture, out var parsed)
|
else if (float.TryParse(value, NumberStyles.Float, CultureInfo.InvariantCulture, out var parsed)
|
||||||
&& !float.IsNaN(parsed)
|
&& !float.IsNaN(parsed)
|
||||||
&& !float.IsInfinity(parsed))
|
&& !float.IsInfinity(parsed))
|
||||||
{
|
{
|
||||||
_defaultValueField.value = _syncType switch
|
theValue = _defaultValueField.value = _syncType switch
|
||||||
{
|
{
|
||||||
ParameterSyncType.Int => Mathf.FloorToInt(Mathf.Clamp(parsed, 0, 255)),
|
ParameterSyncType.Int => Mathf.FloorToInt(Mathf.Clamp(parsed, 0, 255)),
|
||||||
ParameterSyncType.Float => Mathf.Clamp(parsed, -1, 1),
|
ParameterSyncType.Float => Mathf.Clamp(parsed, -1, 1),
|
||||||
@ -88,11 +100,15 @@ namespace nadena.dev.modular_avatar.core.editor
|
|||||||
_hasExplicitDefaultValueField.value = true;
|
_hasExplicitDefaultValueField.value = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
UpdateVisibleField(_defaultValueField.value, _hasExplicitDefaultValueField.value);
|
UpdateVisibleField(theValue, _hasExplicitDefaultValueField.value);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnUpdateBoolValue(string value)
|
private void OnUpdateBoolValue(string value, bool implicitUpdate = false)
|
||||||
{
|
{
|
||||||
|
// Upon initial creation, sometimes the OnUpdateSyncType fires before we receive the initial value event.
|
||||||
|
// In this case, suppress the update to avoid losing data.
|
||||||
|
if (implicitUpdate && !_hasInitialBinding) return;
|
||||||
|
|
||||||
_defaultValueField.value = value == V_True ? 1 : 0;
|
_defaultValueField.value = value == V_True ? 1 : 0;
|
||||||
_hasExplicitDefaultValueField.value = value != V_None;
|
_hasExplicitDefaultValueField.value = value != V_None;
|
||||||
|
|
||||||
@ -101,6 +117,8 @@ namespace nadena.dev.modular_avatar.core.editor
|
|||||||
|
|
||||||
private void UpdateVisibleField(float value, bool hasExplicitValue)
|
private void UpdateVisibleField(float value, bool hasExplicitValue)
|
||||||
{
|
{
|
||||||
|
_hasInitialBinding = true;
|
||||||
|
|
||||||
if (hasExplicitValue || Mathf.Abs(value) > 0.0000001)
|
if (hasExplicitValue || Mathf.Abs(value) > 0.0000001)
|
||||||
{
|
{
|
||||||
_numberField.SetValueWithoutNotify(value.ToString(CultureInfo.InvariantCulture));
|
_numberField.SetValueWithoutNotify(value.ToString(CultureInfo.InvariantCulture));
|
||||||
|
@ -119,9 +119,11 @@ namespace nadena.dev.modular_avatar.core.editor
|
|||||||
|
|
||||||
internal static VRCExpressionsMenu.Control CloneControl(VRCExpressionsMenu.Control c)
|
internal static VRCExpressionsMenu.Control CloneControl(VRCExpressionsMenu.Control c)
|
||||||
{
|
{
|
||||||
|
var type = c.type != 0 ? c.type : VRCExpressionsMenu.Control.ControlType.Button;
|
||||||
|
|
||||||
return new VRCExpressionsMenu.Control()
|
return new VRCExpressionsMenu.Control()
|
||||||
{
|
{
|
||||||
type = c.type,
|
type = type,
|
||||||
name = c.name,
|
name = c.name,
|
||||||
icon = c.icon,
|
icon = c.icon,
|
||||||
parameter = new VRCExpressionsMenu.Control.Parameter() { name = c.parameter?.name },
|
parameter = new VRCExpressionsMenu.Control.Parameter() { name = c.parameter?.name },
|
||||||
|
@ -57,26 +57,29 @@ namespace nadena.dev.modular_avatar.core.editor.plugin
|
|||||||
#endif
|
#endif
|
||||||
seq.WithRequiredExtension(typeof(AnimationServicesContext), _s2 =>
|
seq.WithRequiredExtension(typeof(AnimationServicesContext), _s2 =>
|
||||||
{
|
{
|
||||||
|
#if MA_VRCSDK3_AVATARS
|
||||||
seq.Run("Shape Changer", ctx => new ReactiveObjectPass(ctx).Execute())
|
seq.Run("Shape Changer", ctx => new ReactiveObjectPass(ctx).Execute())
|
||||||
.PreviewingWith(new ShapeChangerPreview(), new ObjectSwitcherPreview(), new MaterialSetterPreview());
|
.PreviewingWith(new ShapeChangerPreview(), new ObjectSwitcherPreview(), new MaterialSetterPreview());
|
||||||
#if MA_VRCSDK3_AVATARS
|
|
||||||
// TODO: We currently run this above MergeArmaturePlugin, because Merge Armature might destroy
|
// TODO: We currently run this above MergeArmaturePlugin, because Merge Armature might destroy
|
||||||
// game objects which contain Menu Installers. It'd probably be better however to teach Merge Armature
|
// game objects which contain Menu Installers. It'd probably be better however to teach Merge Armature
|
||||||
// to retain those objects? maybe?
|
// to retain those objects? maybe?
|
||||||
seq.Run(MenuInstallPluginPass.Instance);
|
seq.Run(MenuInstallPluginPass.Instance);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
seq.Run(MergeArmaturePluginPass.Instance);
|
seq.Run(MergeArmaturePluginPass.Instance);
|
||||||
seq.Run(BoneProxyPluginPass.Instance);
|
seq.Run(BoneProxyPluginPass.Instance);
|
||||||
|
#if MA_VRCSDK3_AVATARS
|
||||||
seq.Run(VisibleHeadAccessoryPluginPass.Instance);
|
seq.Run(VisibleHeadAccessoryPluginPass.Instance);
|
||||||
|
#endif
|
||||||
seq.Run("World Fixed Object",
|
seq.Run("World Fixed Object",
|
||||||
ctx => new WorldFixedObjectProcessor().Process(ctx)
|
ctx => new WorldFixedObjectProcessor().Process(ctx)
|
||||||
);
|
);
|
||||||
seq.Run(ReplaceObjectPluginPass.Instance);
|
seq.Run(ReplaceObjectPluginPass.Instance);
|
||||||
#if MA_VRCSDK3_AVATARS
|
#if MA_VRCSDK3_AVATARS
|
||||||
seq.Run(BlendshapeSyncAnimationPluginPass.Instance);
|
seq.Run(BlendshapeSyncAnimationPluginPass.Instance);
|
||||||
#endif
|
|
||||||
seq.Run(GameObjectDelayDisablePass.Instance);
|
seq.Run(GameObjectDelayDisablePass.Instance);
|
||||||
|
#endif
|
||||||
seq.Run(ConstraintConverterPass.Instance);
|
seq.Run(ConstraintConverterPass.Instance);
|
||||||
});
|
});
|
||||||
#if MA_VRCSDK3_AVATARS
|
#if MA_VRCSDK3_AVATARS
|
||||||
@ -213,6 +216,7 @@ namespace nadena.dev.modular_avatar.core.editor.plugin
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if MA_VRCSDK3_AVATARS
|
||||||
class VisibleHeadAccessoryPluginPass : MAPass<VisibleHeadAccessoryPluginPass>
|
class VisibleHeadAccessoryPluginPass : MAPass<VisibleHeadAccessoryPluginPass>
|
||||||
{
|
{
|
||||||
protected override void Execute(ndmf.BuildContext context)
|
protected override void Execute(ndmf.BuildContext context)
|
||||||
@ -220,6 +224,7 @@ namespace nadena.dev.modular_avatar.core.editor.plugin
|
|||||||
new VisibleHeadAccessoryProcessor(MAContext(context)).Process();
|
new VisibleHeadAccessoryProcessor(MAContext(context)).Process();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
class ReplaceObjectPluginPass : MAPass<ReplaceObjectPluginPass>
|
class ReplaceObjectPluginPass : MAPass<ReplaceObjectPluginPass>
|
||||||
{
|
{
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
using System.Collections.Generic;
|
#if MA_VRCSDK3_AVATARS
|
||||||
|
using System.Collections.Generic;
|
||||||
using System.Collections.Immutable;
|
using System.Collections.Immutable;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using nadena.dev.ndmf.preview;
|
using nadena.dev.ndmf.preview;
|
||||||
@ -346,4 +347,5 @@ namespace nadena.dev.modular_avatar.core.editor
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#endif
|
@ -1,4 +1,5 @@
|
|||||||
using System.Collections.Generic;
|
#if MA_VRCSDK3_AVATARS
|
||||||
|
using System.Collections.Generic;
|
||||||
using System.Collections.Immutable;
|
using System.Collections.Immutable;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using nadena.dev.modular_avatar.animation;
|
using nadena.dev.modular_avatar.animation;
|
||||||
@ -128,7 +129,7 @@ namespace nadena.dev.modular_avatar.core.editor
|
|||||||
foreach (var cond in rule.ControllingConditions)
|
foreach (var cond in rule.ControllingConditions)
|
||||||
{
|
{
|
||||||
var paramName = cond.Parameter;
|
var paramName = cond.Parameter;
|
||||||
if (ForcePropertyOverrides.TryGetValue(paramName, out var value))
|
if (ForcePropertyOverrides?.TryGetValue(paramName, out var value) == true)
|
||||||
{
|
{
|
||||||
cond.InitialValue = value;
|
cond.InitialValue = value;
|
||||||
}
|
}
|
||||||
@ -304,4 +305,5 @@ namespace nadena.dev.modular_avatar.core.editor
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#endif
|
@ -1,4 +1,5 @@
|
|||||||
#region
|
#if MA_VRCSDK3_AVATARS
|
||||||
|
#region
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
@ -613,3 +614,5 @@ namespace nadena.dev.modular_avatar.core.editor
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endif
|
@ -1,4 +1,5 @@
|
|||||||
using nadena.dev.ndmf;
|
#if MA_VRCSDK3_AVATARS
|
||||||
|
using nadena.dev.ndmf;
|
||||||
using UnityEditor.Animations;
|
using UnityEditor.Animations;
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
|
|
||||||
@ -53,4 +54,5 @@ namespace nadena.dev.modular_avatar.core.editor
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#endif
|
@ -1,4 +1,5 @@
|
|||||||
using System.Collections.Generic;
|
#if MA_VRCSDK3_AVATARS
|
||||||
|
using System.Collections.Generic;
|
||||||
using System.Collections.Immutable;
|
using System.Collections.Immutable;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
@ -144,4 +145,5 @@ namespace nadena.dev.modular_avatar.core.editor
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#endif
|
@ -1,4 +1,5 @@
|
|||||||
using System;
|
#if MA_VRCSDK3_AVATARS
|
||||||
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using nadena.dev.ndmf;
|
using nadena.dev.ndmf;
|
||||||
using nadena.dev.ndmf.preview;
|
using nadena.dev.ndmf.preview;
|
||||||
@ -70,4 +71,5 @@ namespace nadena.dev.modular_avatar.core.editor
|
|||||||
return _context.Observe(mami, _ => mami.isDefault);
|
return _context.Observe(mami, _ => mami.isDefault);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#endif
|
@ -1,4 +1,5 @@
|
|||||||
using System.Collections.Generic;
|
#if MA_VRCSDK3_AVATARS
|
||||||
|
using System.Collections.Generic;
|
||||||
using System.Collections.Immutable;
|
using System.Collections.Immutable;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
@ -104,4 +105,5 @@ namespace nadena.dev.modular_avatar.core.editor
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#endif
|
@ -1,4 +1,5 @@
|
|||||||
using System.Collections.Generic;
|
#if MA_VRCSDK3_AVATARS
|
||||||
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using nadena.dev.ndmf;
|
using nadena.dev.ndmf;
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
@ -236,4 +237,5 @@ namespace nadena.dev.modular_avatar.core.editor
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#endif
|
@ -1,4 +1,5 @@
|
|||||||
#region
|
#if MA_VRCSDK3_AVATARS
|
||||||
|
#region
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
@ -294,4 +295,5 @@ namespace nadena.dev.modular_avatar.core.editor
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#endif
|
@ -1,4 +1,5 @@
|
|||||||
using System;
|
#if MA_VRCSDK3_AVATARS
|
||||||
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Collections.Immutable;
|
using System.Collections.Immutable;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
@ -637,4 +638,5 @@ namespace nadena.dev.modular_avatar.core.editor.Simulator
|
|||||||
ve_inactive.style.display = activeState ? DisplayStyle.None : DisplayStyle.Flex;
|
ve_inactive.style.display = activeState ? DisplayStyle.None : DisplayStyle.Flex;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#endif
|
@ -1,5 +1,7 @@
|
|||||||
using nadena.dev.modular_avatar.core.editor;
|
using nadena.dev.modular_avatar.core.editor;
|
||||||
|
#if MA_VRCSDK3_AVATARS
|
||||||
using nadena.dev.modular_avatar.core.editor.Simulator;
|
using nadena.dev.modular_avatar.core.editor.Simulator;
|
||||||
|
#endif
|
||||||
using UnityEditor;
|
using UnityEditor;
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
using UnityEngine.UIElements;
|
using UnityEngine.UIElements;
|
||||||
@ -42,11 +44,13 @@ namespace nadena.dev.modular_avatar.core.editor
|
|||||||
|
|
||||||
private void OpenDebugger()
|
private void OpenDebugger()
|
||||||
{
|
{
|
||||||
|
#if MA_VRCSDK3_AVATARS
|
||||||
GameObject target = Selection.activeGameObject;
|
GameObject target = Selection.activeGameObject;
|
||||||
if (ReferenceObject is Component c) target = c.gameObject;
|
if (ReferenceObject is Component c) target = c.gameObject;
|
||||||
else if (ReferenceObject is GameObject go) target = go;
|
else if (ReferenceObject is GameObject go) target = go;
|
||||||
|
|
||||||
ROSimulator.OpenDebugger(target);
|
ROSimulator.OpenDebugger(target);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,4 +1,6 @@
|
|||||||
using nadena.dev.modular_avatar.core.editor.Simulator;
|
#if MA_VRCSDK3_AVATARS
|
||||||
|
using System;
|
||||||
|
using nadena.dev.modular_avatar.core.editor.Simulator;
|
||||||
using UnityEditor;
|
using UnityEditor;
|
||||||
using UnityEngine.UIElements;
|
using UnityEngine.UIElements;
|
||||||
|
|
||||||
@ -74,4 +76,5 @@ namespace nadena.dev.modular_avatar.core.editor
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#endif
|
@ -146,28 +146,57 @@ namespace nadena.dev.modular_avatar.core.editor
|
|||||||
out var avatarRoot, out var avatarHips, out var outfitHips)
|
out var avatarRoot, out var avatarHips, out var outfitHips)
|
||||||
) return;
|
) return;
|
||||||
|
|
||||||
|
Undo.SetCurrentGroupName("Setup Outfit");
|
||||||
|
|
||||||
var avatarArmature = avatarHips.transform.parent;
|
var avatarArmature = avatarHips.transform.parent;
|
||||||
var outfitArmature = outfitHips.transform.parent;
|
var outfitArmature = outfitHips.transform.parent;
|
||||||
|
|
||||||
if (outfitArmature.GetComponent<ModularAvatarMergeArmature>() == null)
|
var merge = outfitArmature.GetComponent<ModularAvatarMergeArmature>();
|
||||||
|
if (merge == null)
|
||||||
|
{
|
||||||
|
merge = Undo.AddComponent<ModularAvatarMergeArmature>(outfitArmature.gameObject);
|
||||||
|
} else {
|
||||||
|
Undo.RecordObject(merge, "");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (merge.mergeTarget == null || merge.mergeTargetObject == null)
|
||||||
{
|
{
|
||||||
var merge = Undo.AddComponent<ModularAvatarMergeArmature>(outfitArmature.gameObject);
|
|
||||||
merge.mergeTarget = new AvatarObjectReference();
|
merge.mergeTarget = new AvatarObjectReference();
|
||||||
merge.mergeTarget.referencePath = RuntimeUtil.RelativePath(avatarRoot, avatarArmature.gameObject);
|
merge.mergeTarget.referencePath = RuntimeUtil.RelativePath(avatarRoot, avatarArmature.gameObject);
|
||||||
merge.LockMode = ArmatureLockMode.BaseToMerge;
|
merge.LockMode = ArmatureLockMode.BaseToMerge;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (string.IsNullOrEmpty(merge.prefix) && string.IsNullOrEmpty(merge.suffix))
|
||||||
|
{
|
||||||
merge.InferPrefixSuffix();
|
merge.InferPrefixSuffix();
|
||||||
|
}
|
||||||
|
|
||||||
var outfitAnimator = outfitRoot.GetComponent<Animator>();
|
PrefabUtility.RecordPrefabInstancePropertyModifications(merge);
|
||||||
var outfitHumanoidBones = GetOutfitHumanoidBones(outfitRoot.transform, outfitAnimator);
|
|
||||||
var avatarAnimator = avatarRoot.GetComponent<Animator>();
|
|
||||||
List<Transform> subRoots = new List<Transform>();
|
|
||||||
HeuristicBoneMapper.RenameBonesByHeuristic(merge, skipped: subRoots, outfitHumanoidBones: outfitHumanoidBones, avatarAnimator: avatarAnimator);
|
|
||||||
|
|
||||||
// If the outfit has an UpperChest bone but the avatar doesn't, add an additional MergeArmature to
|
var outfitAnimator = outfitRoot.GetComponent<Animator>();
|
||||||
// help with this
|
var outfitHumanoidBones = GetOutfitHumanoidBones(outfitRoot.transform, outfitAnimator);
|
||||||
foreach (var subRoot in subRoots)
|
var avatarAnimator = avatarRoot.GetComponent<Animator>();
|
||||||
|
List<Transform> subRoots = new List<Transform>();
|
||||||
|
HeuristicBoneMapper.RenameBonesByHeuristic(merge, skipped: subRoots, outfitHumanoidBones: outfitHumanoidBones, avatarAnimator: avatarAnimator);
|
||||||
|
|
||||||
|
// If the outfit has an UpperChest bone but the avatar doesn't, add an additional MergeArmature to
|
||||||
|
// help with this
|
||||||
|
foreach (var subRoot in subRoots)
|
||||||
|
{
|
||||||
|
var subConfig = subRoot.GetComponent<ModularAvatarMergeArmature>();
|
||||||
|
var subConfigMangleNames = false;
|
||||||
|
if (subConfig == null)
|
||||||
|
{
|
||||||
|
subConfig = Undo.AddComponent<ModularAvatarMergeArmature>(subRoot.gameObject);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Undo.RecordObject(subConfig, "");
|
||||||
|
subConfigMangleNames = subConfig.mangleNames;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (subConfig.mergeTarget == null || subConfig.mergeTargetObject == null)
|
||||||
{
|
{
|
||||||
var subConfig = Undo.AddComponent<ModularAvatarMergeArmature>(subRoot.gameObject);
|
|
||||||
var parentTransform = subConfig.transform.parent;
|
var parentTransform = subConfig.transform.parent;
|
||||||
var parentConfig = parentTransform.GetComponentInParent<ModularAvatarMergeArmature>();
|
var parentConfig = parentTransform.GetComponentInParent<ModularAvatarMergeArmature>();
|
||||||
var parentMapping = parentConfig.MapBone(parentTransform);
|
var parentMapping = parentConfig.MapBone(parentTransform);
|
||||||
@ -178,33 +207,47 @@ namespace nadena.dev.modular_avatar.core.editor
|
|||||||
subConfig.LockMode = ArmatureLockMode.BaseToMerge;
|
subConfig.LockMode = ArmatureLockMode.BaseToMerge;
|
||||||
subConfig.prefix = merge.prefix;
|
subConfig.prefix = merge.prefix;
|
||||||
subConfig.suffix = merge.suffix;
|
subConfig.suffix = merge.suffix;
|
||||||
subConfig.mangleNames = false;
|
subConfig.mangleNames = subConfigMangleNames;
|
||||||
|
PrefabUtility.RecordPrefabInstancePropertyModifications(subConfig);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
var avatarRootMatchingArmature = avatarRoot.transform.Find(outfitArmature.gameObject.name);
|
var avatarRootMatchingArmature = avatarRoot.transform.Find(outfitArmature.gameObject.name);
|
||||||
if (merge.prefix == "" && merge.suffix == "" && avatarRootMatchingArmature != null)
|
if (merge.prefix == "" && merge.suffix == "" && avatarRootMatchingArmature != null)
|
||||||
{
|
{
|
||||||
// We have an armature whose names exactly match the root armature - this can cause some serious
|
// We have an armature whose names exactly match the root armature - this can cause some serious
|
||||||
// confusion in Unity's humanoid armature matching system. Fortunately, we can avoid this by
|
// confusion in Unity's humanoid armature matching system. Fortunately, we can avoid this by
|
||||||
// renaming a bone close to the root; this will ensure the number of matching bones is small, and
|
// renaming a bone close to the root; this will ensure the number of matching bones is small, and
|
||||||
// Unity's heuristics (apparently) will choose the base avatar's armature as the "true" armature.
|
// Unity's heuristics (apparently) will choose the base avatar's armature as the "true" armature.
|
||||||
outfitArmature.name += ".1";
|
outfitArmature.name += ".1";
|
||||||
|
|
||||||
// Also make sure to refresh the avatar's animator humanoid bone cache.
|
// Also make sure to refresh the avatar's animator humanoid bone cache.
|
||||||
var humanDescription = avatarAnimator.avatar;
|
var humanDescription = avatarAnimator.avatar;
|
||||||
avatarAnimator.avatar = null;
|
avatarAnimator.avatar = null;
|
||||||
// ReSharper disable once Unity.InefficientPropertyAccess
|
// ReSharper disable once Unity.InefficientPropertyAccess
|
||||||
avatarAnimator.avatar = humanDescription;
|
avatarAnimator.avatar = humanDescription;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
FixAPose(avatarRoot, outfitArmature);
|
FixAPose(avatarRoot, outfitArmature);
|
||||||
|
|
||||||
|
var meshSettings = outfitRoot.GetComponent<ModularAvatarMeshSettings>();
|
||||||
|
var mSInheritProbeAnchor = ModularAvatarMeshSettings.InheritMode.SetOrInherit;
|
||||||
|
var mSInheritBounds = ModularAvatarMeshSettings.InheritMode.SetOrInherit;
|
||||||
if (outfitRoot != null
|
if (outfitRoot != null
|
||||||
&& outfitRoot.GetComponent<ModularAvatarMeshSettings>() == null
|
&& meshSettings == null
|
||||||
&& outfitRoot.GetComponentInParent<ModularAvatarMeshSettings>() == null)
|
&& outfitRoot.GetComponentInParent<ModularAvatarMeshSettings>() == null)
|
||||||
{
|
{
|
||||||
var meshSettings = Undo.AddComponent<ModularAvatarMeshSettings>(outfitRoot.gameObject);
|
meshSettings = Undo.AddComponent<ModularAvatarMeshSettings>(outfitRoot.gameObject);
|
||||||
|
} else if (outfitRoot != null && meshSettings != null) {
|
||||||
|
Undo.RecordObject(meshSettings, "");
|
||||||
|
mSInheritProbeAnchor = meshSettings.InheritProbeAnchor;
|
||||||
|
mSInheritBounds = meshSettings.InheritBounds;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (meshSettings != null
|
||||||
|
&& (meshSettings.ProbeAnchor == null || meshSettings.ProbeAnchor.Get(meshSettings) == null
|
||||||
|
|| meshSettings.RootBone == null || meshSettings.RootBone.Get(meshSettings) == null))
|
||||||
|
{
|
||||||
Transform rootBone = null, probeAnchor = null;
|
Transform rootBone = null, probeAnchor = null;
|
||||||
Bounds bounds = ModularAvatarMeshSettings.DEFAULT_BOUNDS;
|
Bounds bounds = ModularAvatarMeshSettings.DEFAULT_BOUNDS;
|
||||||
|
|
||||||
@ -220,8 +263,8 @@ namespace nadena.dev.modular_avatar.core.editor
|
|||||||
rootBone = avatarRoot.transform;
|
rootBone = avatarRoot.transform;
|
||||||
}
|
}
|
||||||
|
|
||||||
meshSettings.InheritProbeAnchor = ModularAvatarMeshSettings.InheritMode.SetOrInherit;
|
meshSettings.InheritProbeAnchor = mSInheritProbeAnchor;
|
||||||
meshSettings.InheritBounds = ModularAvatarMeshSettings.InheritMode.SetOrInherit;
|
meshSettings.InheritBounds = mSInheritBounds;
|
||||||
|
|
||||||
meshSettings.ProbeAnchor = new AvatarObjectReference();
|
meshSettings.ProbeAnchor = new AvatarObjectReference();
|
||||||
meshSettings.ProbeAnchor.referencePath = RuntimeUtil.RelativePath(avatarRoot, probeAnchor.gameObject);
|
meshSettings.ProbeAnchor.referencePath = RuntimeUtil.RelativePath(avatarRoot, probeAnchor.gameObject);
|
||||||
@ -229,6 +272,8 @@ namespace nadena.dev.modular_avatar.core.editor
|
|||||||
meshSettings.RootBone = new AvatarObjectReference();
|
meshSettings.RootBone = new AvatarObjectReference();
|
||||||
meshSettings.RootBone.referencePath = RuntimeUtil.RelativePath(avatarRoot, rootBone.gameObject);
|
meshSettings.RootBone.referencePath = RuntimeUtil.RelativePath(avatarRoot, rootBone.gameObject);
|
||||||
meshSettings.Bounds = bounds;
|
meshSettings.Bounds = bounds;
|
||||||
|
|
||||||
|
PrefabUtility.RecordPrefabInstancePropertyModifications(meshSettings);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
#region
|
#if MA_VRCSDK3_AVATARS
|
||||||
|
#region
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
@ -251,3 +252,5 @@ namespace nadena.dev.modular_avatar.core.editor
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endif
|
@ -19,7 +19,7 @@ namespace nadena.dev.modular_avatar.core
|
|||||||
/// initially inactive in the scene (which can have high overhead if the user has a lot of inactive avatars in the
|
/// initially inactive in the scene (which can have high overhead if the user has a lot of inactive avatars in the
|
||||||
/// scene).
|
/// scene).
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[AddComponentMenu("")]
|
[AddComponentMenu("/")]
|
||||||
[ExecuteInEditMode]
|
[ExecuteInEditMode]
|
||||||
[DefaultExecutionOrder(-9998)]
|
[DefaultExecutionOrder(-9998)]
|
||||||
public class Activator : MonoBehaviour, IEditorOnly
|
public class Activator : MonoBehaviour, IEditorOnly
|
||||||
@ -30,7 +30,7 @@ namespace nadena.dev.modular_avatar.core
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[AddComponentMenu("")]
|
[AddComponentMenu("/")]
|
||||||
[ExecuteInEditMode]
|
[ExecuteInEditMode]
|
||||||
[DefaultExecutionOrder(-9997)]
|
[DefaultExecutionOrder(-9997)]
|
||||||
public class AvatarActivator : MonoBehaviour, IEditorOnly
|
public class AvatarActivator : MonoBehaviour, IEditorOnly
|
||||||
|
@ -6,7 +6,7 @@ namespace nadena.dev.modular_avatar.core
|
|||||||
#if MA_VRCSDK3_AVATARS
|
#if MA_VRCSDK3_AVATARS
|
||||||
[AddComponentMenu("Modular Avatar/MA Convert Constraints")]
|
[AddComponentMenu("Modular Avatar/MA Convert Constraints")]
|
||||||
#else
|
#else
|
||||||
[AddComponentMenu("")]
|
[AddComponentMenu("/")]
|
||||||
#endif
|
#endif
|
||||||
[HelpURL("https://modular-avatar.nadena.dev/docs/reference/convert-constraints?lang=auto")]
|
[HelpURL("https://modular-avatar.nadena.dev/docs/reference/convert-constraints?lang=auto")]
|
||||||
public class ModularAvatarConvertConstraints : AvatarTagComponent
|
public class ModularAvatarConvertConstraints : AvatarTagComponent
|
||||||
|
50
UnitTests~/ReactiveComponent/ObjectToggleTests.cs
Normal file
50
UnitTests~/ReactiveComponent/ObjectToggleTests.cs
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
using System.Linq;
|
||||||
|
using modular_avatar_tests;
|
||||||
|
using nadena.dev.modular_avatar.core;
|
||||||
|
using nadena.dev.modular_avatar.core.editor;
|
||||||
|
using NUnit.Framework;
|
||||||
|
using UnityEditor.Animations;
|
||||||
|
using UnityEngine;
|
||||||
|
|
||||||
|
namespace UnitTests.ReactiveComponent
|
||||||
|
{
|
||||||
|
internal class ObjectToggleTests : TestBase
|
||||||
|
{
|
||||||
|
[Test]
|
||||||
|
public void WhenObjectIsAlwaysOn_CorrectProxyParameterIsGenerated()
|
||||||
|
{
|
||||||
|
var root = CreateRoot("root");
|
||||||
|
var obj = CreateChild(root, "obj");
|
||||||
|
var toggle = CreateChild(root, "toggle");
|
||||||
|
|
||||||
|
// Prevent obj from being removed by the GC game objects pass
|
||||||
|
obj.AddComponent<MeshRenderer>();
|
||||||
|
|
||||||
|
var toggleComponent = toggle.AddComponent<ModularAvatarObjectToggle>();
|
||||||
|
var aor = new AvatarObjectReference();
|
||||||
|
aor.Set(obj);
|
||||||
|
|
||||||
|
toggleComponent.Objects = new()
|
||||||
|
{
|
||||||
|
new()
|
||||||
|
{
|
||||||
|
Active = false,
|
||||||
|
Object = aor
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
AvatarProcessor.ProcessAvatar(root);
|
||||||
|
|
||||||
|
// TODO: Ideally we should start using play mode testing for these things...
|
||||||
|
var fx = (AnimatorController)FindFxController(root).animatorController;
|
||||||
|
var readableProp = fx.parameters.FirstOrDefault(
|
||||||
|
p => p.name.StartsWith("__MA/ReadableProp/obj/UnityEngine.GameObject/m_IsActive")
|
||||||
|
);
|
||||||
|
|
||||||
|
Assert.IsNotNull(readableProp);
|
||||||
|
Assert.AreEqual(readableProp.defaultFloat, 0);
|
||||||
|
|
||||||
|
Assert.IsFalse(obj.activeSelf);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
3
UnitTests~/ReactiveComponent/ObjectToggleTests.cs.meta
Normal file
3
UnitTests~/ReactiveComponent/ObjectToggleTests.cs.meta
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 7c68d69f7b4a46c5b2ce3d8f26b0fa76
|
||||||
|
timeCreated: 1729376563
|
@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "nadena.dev.modular-avatar",
|
"name": "nadena.dev.modular-avatar",
|
||||||
"displayName": "Modular Avatar",
|
"displayName": "Modular Avatar",
|
||||||
"version": "1.10.4",
|
"version": "1.10.5",
|
||||||
"unity": "2022.3",
|
"unity": "2022.3",
|
||||||
"description": "A suite of tools for assembling your avatar out of reusable components",
|
"description": "A suite of tools for assembling your avatar out of reusable components",
|
||||||
"author": {
|
"author": {
|
||||||
@ -16,6 +16,6 @@
|
|||||||
},
|
},
|
||||||
"vpmDependencies": {
|
"vpmDependencies": {
|
||||||
"com.vrchat.avatars": ">=3.7.0",
|
"com.vrchat.avatars": ">=3.7.0",
|
||||||
"nadena.dev.ndmf": ">=1.5.4 <2.0.0-a"
|
"nadena.dev.ndmf": ">=1.5.6 <2.0.0-a"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user