mirror of
https://github.com/bdunderscore/modular-avatar.git
synced 2024-12-29 18:55:06 +08:00
30512c26e8
Closes: #1342
351 lines
13 KiB
C#
351 lines
13 KiB
C#
#if MA_VRCSDK3_AVATARS
|
|
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Collections.Immutable;
|
|
using System.Linq;
|
|
using nadena.dev.modular_avatar.core;
|
|
using nadena.dev.modular_avatar.core.editor;
|
|
using nadena.dev.ndmf;
|
|
using NUnit.Framework;
|
|
using UnityEditor.Animations;
|
|
using UnityEngine;
|
|
using VRC.SDK3.Avatars.Components;
|
|
using VRC.SDK3.Avatars.ScriptableObjects;
|
|
using VRC.SDK3.Dynamics.Contact.Components;
|
|
using AvatarProcessor = nadena.dev.modular_avatar.core.editor.AvatarProcessor;
|
|
|
|
namespace modular_avatar_tests.RenameParametersTests
|
|
{
|
|
public class RenameParametersTests : TestBase
|
|
{
|
|
[Test]
|
|
public void RenameParametersRenamesParamDrivers()
|
|
{
|
|
var prefab = CreatePrefab("RenameParametersRenamesParamDrivers.prefab");
|
|
AvatarProcessor.ProcessAvatar(prefab);
|
|
|
|
var layer = findFxLayer(prefab, "test");
|
|
CheckDriver(layer.stateMachine.behaviours[0] as VRCAvatarParameterDriver);
|
|
|
|
var state = FindStateInLayer(layer, "s");
|
|
CheckDriver(state.behaviours[0] as VRCAvatarParameterDriver);
|
|
|
|
var subStateMachine = layer.stateMachine.stateMachines[0].stateMachine;
|
|
CheckDriver(subStateMachine.behaviours[0] as VRCAvatarParameterDriver);
|
|
|
|
var subState = FindStateInLayer(layer, "s");
|
|
CheckDriver(subState.behaviours[0] as VRCAvatarParameterDriver);
|
|
|
|
void CheckDriver(VRCAvatarParameterDriver driver)
|
|
{
|
|
Assert.AreEqual("param_new", driver.parameters[0].name);
|
|
}
|
|
}
|
|
|
|
[Test]
|
|
public void RenameInstalledMenu()
|
|
{
|
|
var prefab = CreatePrefab("RenameInstalledMenu.prefab");
|
|
AvatarProcessor.ProcessAvatar(prefab);
|
|
|
|
var menu = prefab.GetComponent<VRCAvatarDescriptor>().expressionsMenu;
|
|
Assert.AreEqual("test$$Internal_0", menu.controls[0].parameter.name);
|
|
Assert.AreEqual("test$$Internal_0", menu.controls[1].subMenu.controls[0].parameter.name);
|
|
}
|
|
|
|
[Test]
|
|
public void TestRecursiveMenu()
|
|
{
|
|
var menu = LoadAsset<VRCExpressionsMenu>("m1.asset");
|
|
var avatar = CreateRoot("root");
|
|
var child = CreateChild(avatar, "child");
|
|
var param = child.AddComponent<ModularAvatarParameters>();
|
|
param.parameters.Add(new ParameterConfig()
|
|
{
|
|
nameOrPrefix = "test",
|
|
internalParameter = true,
|
|
});
|
|
var installer = child.AddComponent<ModularAvatarMenuInstaller>();
|
|
installer.menuToAppend = menu;
|
|
|
|
AvatarProcessor.ProcessAvatar(avatar);
|
|
}
|
|
|
|
[Test]
|
|
public void TestParameterConflicts()
|
|
{
|
|
var prefab = CreatePrefab("ParameterConflicts.prefab");
|
|
|
|
var context = CreateContext(prefab);
|
|
var maContext = context.ActivateExtensionContext<ModularAvatarContext>().BuildContext;
|
|
|
|
var errors = ErrorReport.CaptureErrors(
|
|
() =>
|
|
{
|
|
using (new ObjectRegistryScope(new ObjectRegistry(prefab.transform)))
|
|
{
|
|
new RenameParametersHook().OnPreprocessAvatar(prefab, maContext);
|
|
}
|
|
});
|
|
|
|
var valueConflict = errors
|
|
.Select(e => e.TheError)
|
|
.Cast<SimpleError>()
|
|
.First(e => e.TitleKey == "error.rename_params.default_value_conflict");
|
|
Assert.AreEqual("a$$Internal_1", valueConflict.DetailsSubst[0]);
|
|
Assert.AreEqual("0", valueConflict.DetailsSubst[1]);
|
|
Assert.AreEqual("1", valueConflict.DetailsSubst[2]);
|
|
|
|
Assert.AreEqual("Conflict/P", valueConflict.References[0].Path);
|
|
Assert.AreEqual("Conflict/P (1)", valueConflict.References[1].Path);
|
|
|
|
var typeConflict = errors
|
|
.Select(e => e.TheError)
|
|
.Cast<SimpleError>()
|
|
.First(e => e.TitleKey == "error.rename_params.type_conflict");
|
|
|
|
Assert.AreEqual("a$$Internal_2", typeConflict.DetailsSubst[0]);
|
|
Assert.AreEqual("Int", typeConflict.DetailsSubst[1]);
|
|
Assert.AreEqual("Float", typeConflict.DetailsSubst[2]);
|
|
|
|
Assert.AreEqual("TypeConflict/P", typeConflict.References[0].Path);
|
|
Assert.AreEqual("TypeConflict/P (2)", typeConflict.References[1].Path);
|
|
}
|
|
|
|
[Test]
|
|
public void TestParameterResults()
|
|
{
|
|
var prefab = CreatePrefab("ParameterResolution.prefab");
|
|
|
|
AvatarProcessor.ProcessAvatar(prefab);
|
|
|
|
var expParams = prefab.GetComponent<VRCAvatarDescriptor>().expressionParameters;
|
|
|
|
Assert.AreEqual(expParams.parameters[0].name, "a");
|
|
Assert.IsTrue(Mathf.Abs(expParams.parameters[0].defaultValue - 0.1f) < 0.0001f);
|
|
}
|
|
|
|
[Test]
|
|
public void AnimatorOnlyParametersTests()
|
|
{
|
|
var prefab = CreatePrefab("AnimatorOnlyParameterValues/AOPV.prefab");
|
|
|
|
AvatarProcessor.ProcessAvatar(prefab);
|
|
|
|
var fx = prefab.GetComponent<VRCAvatarDescriptor>().baseAnimationLayers
|
|
.First(l => l.type == VRCAvatarDescriptor.AnimLayerType.FX)
|
|
.animatorController as AnimatorController;
|
|
Assert.NotNull(fx);
|
|
|
|
AssertParamStates(fx);
|
|
|
|
var action = prefab.GetComponent<VRCAvatarDescriptor>().baseAnimationLayers
|
|
.First(l => l.type == VRCAvatarDescriptor.AnimLayerType.FX)
|
|
.animatorController as AnimatorController;
|
|
Assert.NotNull(action);
|
|
|
|
AssertParamStates(action);
|
|
|
|
void AssertParamStates(AnimatorController controller)
|
|
{
|
|
var parameters = controller.parameters.Select(
|
|
p => new KeyValuePair<String, AnimatorControllerParameter>(p.name, p)
|
|
).ToImmutableDictionary();
|
|
|
|
Assert.LessOrEqual(Mathf.Abs(parameters["float"].defaultFloat - 0.5f), 0.005f);
|
|
Assert.AreEqual(23, parameters["int"].defaultInt);
|
|
Assert.AreEqual(true, parameters["bool"].defaultBool);
|
|
}
|
|
}
|
|
|
|
[Test]
|
|
public void SavedParameterResolution()
|
|
{
|
|
var prefab = CreatePrefab("SavedParamResolution.prefab");
|
|
|
|
AvatarProcessor.ProcessAvatar(prefab);
|
|
|
|
var expParams = prefab.GetComponent<VRCAvatarDescriptor>().expressionParameters.parameters
|
|
.Select(p => new KeyValuePair<string, VRCExpressionParameters.Parameter>(p.name, p))
|
|
.ToImmutableDictionary();
|
|
|
|
Assert.IsTrue(expParams["a"].saved);
|
|
Assert.IsTrue(expParams["b"].saved);
|
|
Assert.IsFalse(expParams["c"].saved);
|
|
Assert.IsTrue(expParams["d"].saved);
|
|
Assert.IsFalse(expParams["e"].saved);
|
|
Assert.IsTrue(expParams["f"].saved);
|
|
}
|
|
|
|
[Test]
|
|
public void TestMultipleRemappings()
|
|
{
|
|
var av = CreateRoot("avatar");
|
|
|
|
var parameters = av.AddComponent<ModularAvatarParameters>();
|
|
|
|
parameters.parameters = new List<ParameterConfig>()
|
|
{
|
|
new ParameterConfig()
|
|
{
|
|
nameOrPrefix = "a",
|
|
remapTo = "z",
|
|
syncType = ParameterSyncType.Float
|
|
},
|
|
new ParameterConfig()
|
|
{
|
|
nameOrPrefix = "b",
|
|
remapTo = "z",
|
|
syncType = ParameterSyncType.Float
|
|
},
|
|
};
|
|
|
|
var c1 = av.AddComponent<VRCContactReceiver>();
|
|
c1.parameter = "a";
|
|
|
|
var c2 = av.AddComponent<VRCContactReceiver>();
|
|
c2.parameter = "a";
|
|
|
|
var context = CreateContext(av);
|
|
var maContext = context.ActivateExtensionContext<ModularAvatarContext>().BuildContext;
|
|
|
|
var errors = ErrorReport.CaptureErrors(() => new RenameParametersHook().OnPreprocessAvatar(av, maContext));
|
|
|
|
Assert.IsEmpty(errors);
|
|
|
|
Assert.AreEqual("z", c1.parameter);
|
|
Assert.AreEqual("z", c2.parameter);
|
|
}
|
|
|
|
[Test]
|
|
public void TestMultipleRemappings_WithConflict()
|
|
{
|
|
var av = CreateRoot("avatar");
|
|
|
|
var parameters = av.AddComponent<ModularAvatarParameters>();
|
|
|
|
parameters.parameters = new List<ParameterConfig>()
|
|
{
|
|
new ParameterConfig()
|
|
{
|
|
nameOrPrefix = "a",
|
|
remapTo = "z",
|
|
syncType = ParameterSyncType.Float
|
|
},
|
|
new ParameterConfig()
|
|
{
|
|
nameOrPrefix = "b",
|
|
remapTo = "z",
|
|
syncType = ParameterSyncType.Int
|
|
},
|
|
};
|
|
|
|
var context = CreateContext(av);
|
|
var maContext = context.ActivateExtensionContext<ModularAvatarContext>().BuildContext;
|
|
|
|
var errors = ErrorReport.CaptureErrors(() => new RenameParametersHook().OnPreprocessAvatar(av, maContext));
|
|
|
|
Assert.IsNotEmpty(errors);
|
|
}
|
|
|
|
[Test]
|
|
public void ParameterOrderTest()
|
|
{
|
|
var av = CreateRoot("avatar");
|
|
|
|
var rootMenu = ScriptableObject.CreateInstance<VRCExpressionsMenu>();
|
|
var paramsAsset = ScriptableObject.CreateInstance<VRCExpressionParameters>();
|
|
|
|
var desc = av.GetComponent<VRCAvatarDescriptor>();
|
|
desc.expressionsMenu = rootMenu;
|
|
desc.expressionParameters = paramsAsset;
|
|
|
|
var c1 = CreateChild(av, "a");
|
|
var c2 = CreateChild(av, "b");
|
|
var c3 = CreateChild(av, "c");
|
|
var c4 = CreateChild(av, "d");
|
|
|
|
AddParam(c1, "A");
|
|
AddParam(c2, "B");
|
|
AddParam(c3, "C");
|
|
AddParam(c4, "D");
|
|
|
|
AvatarProcessor.ProcessAvatar(av);
|
|
|
|
paramsAsset = desc.expressionParameters;
|
|
|
|
Assert.AreEqual("A", paramsAsset.parameters[0].name);
|
|
Assert.AreEqual("B", paramsAsset.parameters[1].name);
|
|
Assert.AreEqual("C", paramsAsset.parameters[2].name);
|
|
Assert.AreEqual("D", paramsAsset.parameters[3].name);
|
|
|
|
void AddParam(GameObject child, String name)
|
|
{
|
|
var param = child.AddComponent<ModularAvatarParameters>();
|
|
param.parameters.Add(new ParameterConfig()
|
|
{
|
|
nameOrPrefix = name,
|
|
syncType = ParameterSyncType.Float
|
|
});
|
|
}
|
|
}
|
|
|
|
[Test]
|
|
public void RecursiveRenameTest()
|
|
{
|
|
var prefab = CreatePrefab("RecursiveRenameTest.prefab");
|
|
|
|
AvatarProcessor.ProcessAvatar(prefab);
|
|
|
|
var fx = (AnimatorController) FindFxController(prefab).animatorController;
|
|
|
|
Assert.IsFalse(fx.parameters.Any(p => p.name.StartsWith("Hoge")));
|
|
var fuga = fx.parameters.First(p => p.name.StartsWith("Fuga"));
|
|
Assert.IsFalse(fx.parameters.Any(p => p.name.StartsWith("Fuga") && p.name != fuga.name));
|
|
|
|
Assert.AreNotEqual(fuga.name, "Fuga"); // should be auto-renamed
|
|
}
|
|
|
|
[Test]
|
|
public void AnimatorOnlyAndLocalParameterShouldNotSync()
|
|
{
|
|
var root = CreateRoot("x");
|
|
|
|
var c1 = CreateChild(root, "c1");
|
|
var c2 = CreateChild(root, "c2");
|
|
|
|
var p1 = c1.AddComponent<ModularAvatarParameters>();
|
|
var p2 = c2.AddComponent<ModularAvatarParameters>();
|
|
|
|
p1.parameters = new()
|
|
{
|
|
new()
|
|
{
|
|
nameOrPrefix = "a",
|
|
syncType = ParameterSyncType.NotSynced,
|
|
localOnly = false
|
|
}
|
|
};
|
|
p2.parameters = new()
|
|
{
|
|
new()
|
|
{
|
|
nameOrPrefix = "a",
|
|
syncType = ParameterSyncType.Int,
|
|
localOnly = true
|
|
}
|
|
};
|
|
|
|
AvatarProcessor.ProcessAvatar(root);
|
|
|
|
var expParams = root.GetComponent<VRCAvatarDescriptor>().expressionParameters.parameters
|
|
.Select(p => new KeyValuePair<string, VRCExpressionParameters.Parameter>(p.name, p))
|
|
.ToImmutableDictionary();
|
|
|
|
Assert.IsFalse(expParams["a"].networkSynced);
|
|
}
|
|
}
|
|
}
|
|
|
|
#endif |