Fix menu item float value (#1140)

* fix: menu item with float value incorrectly generates bool parameter

* fix: reactive components generate transitions with overlapping condition ranges

* chore: add tests for menu item parameter type

* fix: incorrect parameter type detemination for float values

* chore: add more tests for menu item parameter type

* refactor: unify logic to determine parameter type and rename confusing variable
This commit is contained in:
nekobako 2024-09-16 11:32:59 +09:00 committed by GitHub
parent c80d24ea46
commit 48b7d80f7c
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 130 additions and 24 deletions

View File

@ -34,19 +34,10 @@ namespace nadena.dev.modular_avatar.core.editor
hidden = true; hidden = true;
} }
var type = AnimatorControllerParameterType.Bool;
if (type != AnimatorControllerParameterType.Float &&
(_component.Control.value > 1.01 || _component.Control.value < -0.01))
type = AnimatorControllerParameterType.Int;
if (Mathf.Abs(Mathf.Round(_component.Control.value) - _component.Control.value) > 0.01f)
type = AnimatorControllerParameterType.Float;
yield return new ProvidedParameter( yield return new ProvidedParameter(
name, name,
ParameterNamespace.Animator, ParameterNamespace.Animator,
_component, PluginDefinition.Instance, type) _component, PluginDefinition.Instance, _component.AnimatorControllerParameterType)
{ {
WantSynced = _component.isSynced, WantSynced = _component.isSynced,
IsHidden = hidden, IsHidden = hidden,

View File

@ -115,8 +115,7 @@ namespace nadena.dev.modular_avatar.core.editor
var nextValue = 1; var nextValue = 1;
var canBeBool = true; var valueType = VRCExpressionParameters.ValueType.Bool;
var canBeInt = true;
var isSaved = false; var isSaved = false;
var isSynced = false; var isSynced = false;
@ -137,10 +136,11 @@ namespace nadena.dev.modular_avatar.core.editor
} }
} }
if (Mathf.Abs(mami.Control.value - Mathf.Round(mami.Control.value)) > 0.01f) var newValueType = mami.ExpressionParametersValueType;
canBeInt = false; if (valueType == VRCExpressionParameters.ValueType.Bool || newValueType == VRCExpressionParameters.ValueType.Float)
else {
canBeBool &= mami.Control.value is >= 0 and <= 1; valueType = newValueType;
}
isSaved |= mami.isSaved; isSaved |= mami.isSaved;
isSynced |= mami.isSynced; isSynced |= mami.isSynced;
@ -148,15 +148,10 @@ namespace nadena.dev.modular_avatar.core.editor
if (!declaredParams.ContainsKey(paramName)) if (!declaredParams.ContainsKey(paramName))
{ {
VRCExpressionParameters.ValueType newType;
if (canBeBool) newType = VRCExpressionParameters.ValueType.Bool;
else if (canBeInt) newType = VRCExpressionParameters.ValueType.Int;
else newType = VRCExpressionParameters.ValueType.Float;
var newParam = new VRCExpressionParameters.Parameter var newParam = new VRCExpressionParameters.Parameter
{ {
name = paramName, name = paramName,
valueType = newType, valueType = valueType,
saved = isSaved, saved = isSaved,
defaultValue = defaultValue, defaultValue = defaultValue,
networkSynced = isSynced networkSynced = isSynced
@ -221,8 +216,8 @@ namespace nadena.dev.modular_avatar.core.editor
// we basically force-disable any conditions for nonselected menu items and force-enable any for default // we basically force-disable any conditions for nonselected menu items and force-enable any for default
// menu items. // menu items.
InitialValue = mami.isDefault ? mami.Control.value : -999, InitialValue = mami.isDefault ? mami.Control.value : -999,
ParameterValueLo = mami.Control.value - 0.5f, ParameterValueLo = mami.Control.value - 0.005f,
ParameterValueHi = mami.Control.value + 0.5f, ParameterValueHi = mami.Control.value + 0.005f,
DebugReference = mami, DebugReference = mami,
}; };
} }

View File

@ -149,6 +149,38 @@ namespace nadena.dev.modular_avatar.core
if (control.subParameters.Length > maxSubParams) if (control.subParameters.Length > maxSubParams)
control.subParameters = control.subParameters.Take(maxSubParams).ToArray(); control.subParameters = control.subParameters.Take(maxSubParams).ToArray();
} }
internal VRCExpressionParameters.ValueType ExpressionParametersValueType
{
get
{
// 0, 1
var type = VRCExpressionParameters.ValueType.Bool;
// 2, 3, ..., (255)
if (Control.value > 1)
{
type = VRCExpressionParameters.ValueType.Int;
}
// (-1.0), ..., -0.1, 0.1, ..., 0.9
if (Control.value < 0 || Mathf.Abs(Control.value - Mathf.Round(Control.value)) > 0.01f)
{
type = VRCExpressionParameters.ValueType.Float;
}
return type;
}
}
internal AnimatorControllerParameterType AnimatorControllerParameterType
=> ExpressionParametersValueType switch
{
VRCExpressionParameters.ValueType.Bool => AnimatorControllerParameterType.Bool,
VRCExpressionParameters.ValueType.Int => AnimatorControllerParameterType.Int,
VRCExpressionParameters.ValueType.Float => AnimatorControllerParameterType.Float,
_ => 0,
};
} }
} }

View File

@ -0,0 +1,85 @@
using System;
using System.Linq;
using modular_avatar_tests;
using nadena.dev.modular_avatar.core;
using nadena.dev.modular_avatar.core.editor;
using NUnit.Framework;
using UnityEngine;
using VRC.SDK3.Avatars.Components;
using VRC.SDK3.Avatars.ScriptableObjects;
namespace UnitTests.ReactiveComponent.ParameterAssignment
{
public class ParameterTypeTests : TestBase
{
[Test]
public void BoolTest()
{
Test(new[] { 0.0f }, VRCExpressionParameters.ValueType.Bool);
Test(new[] { 1.0f }, VRCExpressionParameters.ValueType.Bool);
Test(new[] { 0.0f, 1.0f }, VRCExpressionParameters.ValueType.Bool);
Test(new[] { 1.0f, 0.0f }, VRCExpressionParameters.ValueType.Bool);
}
[Test]
public void IntTest()
{
Test(new[] { 2.0f }, VRCExpressionParameters.ValueType.Int);
Test(new[] { 3.0f }, VRCExpressionParameters.ValueType.Int);
Test(new[] { 0.0f, 1.0f, 2.0f }, VRCExpressionParameters.ValueType.Int);
Test(new[] { 2.0f, 1.0f, 0.0f }, VRCExpressionParameters.ValueType.Int);
Test(new[] { 253.0f, 254.0f, 255.0f }, VRCExpressionParameters.ValueType.Int);
Test(new[] { 255.0f, 254.0f, 253.0f }, VRCExpressionParameters.ValueType.Int);
}
[Test]
public void FloatTest()
{
Test(new[] { -1.0f }, VRCExpressionParameters.ValueType.Float);
Test(new[] { -0.1f }, VRCExpressionParameters.ValueType.Float);
Test(new[] { 0.1f }, VRCExpressionParameters.ValueType.Float);
Test(new[] { 0.9f }, VRCExpressionParameters.ValueType.Float);
Test(new[] { -1.0f, 0.0f, 1.0f }, VRCExpressionParameters.ValueType.Float);
Test(new[] { 1.0f, 0.0f, -1.0f }, VRCExpressionParameters.ValueType.Float);
Test(new[] { -0.1f, 0.0f, 0.1f }, VRCExpressionParameters.ValueType.Float);
Test(new[] { 0.1f, 0.0f, -0.1f }, VRCExpressionParameters.ValueType.Float);
Test(new[] { 0.0f, 0.1f, 0.2f }, VRCExpressionParameters.ValueType.Float);
Test(new[] { 0.2f, 0.1f, 0.0f }, VRCExpressionParameters.ValueType.Float);
Test(new[] { 0.7f, 0.8f, 0.9f }, VRCExpressionParameters.ValueType.Float);
Test(new[] { 0.9f, 0.8f, 0.7f }, VRCExpressionParameters.ValueType.Float);
}
private void Test(float[] values, VRCExpressionParameters.ValueType expected)
{
var root = CreateRoot("Root");
var descriptor = root.GetComponent<VRCAvatarDescriptor>();
descriptor.expressionParameters = ScriptableObject.CreateInstance<VRCExpressionParameters>();
descriptor.expressionParameters.parameters = Array.Empty<VRCExpressionParameters.Parameter>();
for (var i = 0; i < values.Length; i++)
{
var obj = CreateChild(root, i.ToString());
var mami = obj.AddComponent<ModularAvatarMenuItem>();
mami.Control = new VRCExpressionsMenu.Control()
{
name = obj.name,
type = VRCExpressionsMenu.Control.ControlType.Toggle,
value = values[i],
parameter = new() { name = "Test" },
};
}
var context = new nadena.dev.ndmf.BuildContext(root, null);
new ParameterAssignerPass().TestExecute(context);
Assert.AreEqual(expected, descriptor.expressionParameters.parameters.Single().valueType);
}
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: c7051ac5a4bbe084c9d34c01c523eda3
timeCreated: 1726276608