From f4d80b857d55a493eaf0b53df950e6ef5259f657 Mon Sep 17 00:00:00 2001 From: nekobako Date: Sun, 15 Sep 2024 09:51:43 +0900 Subject: [PATCH 01/85] fix: exception thrown when opening prefab override ui (#1141) --- Editor/Inspector/MaterialSetter/MaterialSetterEditor.cs | 2 +- Editor/Inspector/MoveIndependently/MoveIndependentlyEditor.cs | 2 +- Editor/Inspector/ObjectToggle/ObjectSwitcherEditor.cs | 2 +- Editor/Inspector/ShapeChanger/ShapeChangerEditor.cs | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Editor/Inspector/MaterialSetter/MaterialSetterEditor.cs b/Editor/Inspector/MaterialSetter/MaterialSetterEditor.cs index d13532c4..c7410eb8 100644 --- a/Editor/Inspector/MaterialSetter/MaterialSetterEditor.cs +++ b/Editor/Inspector/MaterialSetter/MaterialSetterEditor.cs @@ -19,7 +19,7 @@ namespace nadena.dev.modular_avatar.core.editor.ShapeChanger protected override void OnInnerInspectorGUI() { - throw new NotImplementedException(); + EditorGUILayout.HelpBox("Unable to show override changes", MessageType.Info); } protected override VisualElement CreateInnerInspectorGUI() diff --git a/Editor/Inspector/MoveIndependently/MoveIndependentlyEditor.cs b/Editor/Inspector/MoveIndependently/MoveIndependentlyEditor.cs index 8c6da1a7..171a5ae6 100644 --- a/Editor/Inspector/MoveIndependently/MoveIndependentlyEditor.cs +++ b/Editor/Inspector/MoveIndependently/MoveIndependentlyEditor.cs @@ -23,7 +23,7 @@ namespace nadena.dev.modular_avatar.core.editor protected override void OnInnerInspectorGUI() { - throw new NotImplementedException(); + EditorGUILayout.HelpBox("Unable to show override changes", MessageType.Info); } protected override VisualElement CreateInnerInspectorGUI() diff --git a/Editor/Inspector/ObjectToggle/ObjectSwitcherEditor.cs b/Editor/Inspector/ObjectToggle/ObjectSwitcherEditor.cs index 8807e221..627121b7 100644 --- a/Editor/Inspector/ObjectToggle/ObjectSwitcherEditor.cs +++ b/Editor/Inspector/ObjectToggle/ObjectSwitcherEditor.cs @@ -21,7 +21,7 @@ namespace nadena.dev.modular_avatar.core.editor.ShapeChanger protected override void OnInnerInspectorGUI() { - throw new NotImplementedException(); + EditorGUILayout.HelpBox("Unable to show override changes", MessageType.Info); } protected override VisualElement CreateInnerInspectorGUI() diff --git a/Editor/Inspector/ShapeChanger/ShapeChangerEditor.cs b/Editor/Inspector/ShapeChanger/ShapeChangerEditor.cs index 31fc18e4..9a278278 100644 --- a/Editor/Inspector/ShapeChanger/ShapeChangerEditor.cs +++ b/Editor/Inspector/ShapeChanger/ShapeChangerEditor.cs @@ -23,7 +23,7 @@ namespace nadena.dev.modular_avatar.core.editor.ShapeChanger protected override void OnInnerInspectorGUI() { - throw new NotImplementedException(); + EditorGUILayout.HelpBox("Unable to show override changes", MessageType.Info); } protected override VisualElement CreateInnerInspectorGUI() From faa8d210f24a8d4b399e58e9032d6de28507035b Mon Sep 17 00:00:00 2001 From: nekobako Date: Sun, 15 Sep 2024 09:53:00 +0900 Subject: [PATCH 02/85] Enhance default value field (#1125) * feat: enhance default value field input * fix: format default value when update type or value on parameters inspector * fix: don't accept NaN and Infinity for default value setting --- .../Inspector/Parameters/DefaultValueField.cs | 147 +++++++++--------- .../Parameters/ParameterConfigDrawer.cs | 22 +-- Editor/Inspector/Parameters/Parameters.uss | 20 +-- 3 files changed, 87 insertions(+), 102 deletions(-) diff --git a/Editor/Inspector/Parameters/DefaultValueField.cs b/Editor/Inspector/Parameters/DefaultValueField.cs index d044a9b1..6ba6cd22 100644 --- a/Editor/Inspector/Parameters/DefaultValueField.cs +++ b/Editor/Inspector/Parameters/DefaultValueField.cs @@ -1,6 +1,4 @@ using System.Globalization; -using UnityEditor; -using UnityEditor.UIElements; using UnityEngine; using UnityEngine.UIElements; @@ -15,95 +13,104 @@ namespace nadena.dev.modular_avatar.core.editor private const string V_None = " "; private const string V_True = "ON"; private const string V_False = "OFF"; - - private readonly TextField _visibleField; + private readonly FloatField _defaultValueField; + private readonly Toggle _hasExplicitDefaultValueField; + private readonly TextField _numberField; private readonly DropdownField _boolField; - private readonly Toggle _hasExplicitDefaultSetField; + + private ParameterSyncType _syncType; public DefaultValueField() { // Hidden binding elements _defaultValueField = new FloatField(); - _hasExplicitDefaultSetField = new Toggle(); - _boolField = new DropdownField(); + _defaultValueField.style.display = DisplayStyle.None; + _defaultValueField.bindingPath = nameof(ParameterConfig.defaultValue); + _defaultValueField.RegisterValueChangedCallback(evt => UpdateVisibleField(evt.newValue, _hasExplicitDefaultValueField.value)); + _hasExplicitDefaultValueField = new Toggle(); + _hasExplicitDefaultValueField.style.display = DisplayStyle.None; + _hasExplicitDefaultValueField.bindingPath = nameof(ParameterConfig.hasExplicitDefaultValue); + _hasExplicitDefaultValueField.RegisterValueChangedCallback(evt => UpdateVisibleField(_defaultValueField.value, evt.newValue)); + // Visible elements for input + _numberField = new TextField(); + _numberField.isDelayed = true; + _numberField.RegisterValueChangedCallback(evt => OnUpdateNumberValue(evt.newValue)); + _boolField = new DropdownField(); _boolField.choices.Add(V_None); _boolField.choices.Add(V_True); _boolField.choices.Add(V_False); + _boolField.RegisterValueChangedCallback(evt => OnUpdateBoolValue(evt.newValue)); - _defaultValueField.RegisterValueChangedCallback( - evt => UpdateVisibleField(evt.newValue, _hasExplicitDefaultSetField.value)); - _defaultValueField.bindingPath = nameof(ParameterConfig.defaultValue); - - _hasExplicitDefaultSetField.RegisterValueChangedCallback( - evt => UpdateVisibleField(_defaultValueField.value, evt.newValue)); - _hasExplicitDefaultSetField.bindingPath = nameof(ParameterConfig.hasExplicitDefaultValue); - - _visibleField = new TextField(); - _visibleField.RegisterValueChangedCallback(evt => - { - if (string.IsNullOrWhiteSpace(evt.newValue)) - { - _hasExplicitDefaultSetField.value = false; - _defaultValueField.value = 0; - } - else - { - _hasExplicitDefaultSetField.value = true; - _defaultValueField.value = float.Parse(evt.newValue, CultureInfo.InvariantCulture); - } - }); - - _defaultValueField.style.width = 0; - _defaultValueField.SetEnabled(false); - _hasExplicitDefaultSetField.style.width = 0; - _hasExplicitDefaultSetField.SetEnabled(false); - - _boolField.RegisterValueChangedCallback(evt => - { - if (evt.newValue == V_True) - _defaultValueField.value = 1; - else - _defaultValueField.value = 0; - - _hasExplicitDefaultSetField.value = evt.newValue != V_None; - }); - - - style.flexDirection = FlexDirection.Row; - - Add(_visibleField); - Add(_boolField); Add(_defaultValueField); - Add(_hasExplicitDefaultSetField); + Add(_hasExplicitDefaultValueField); + Add(_numberField); + Add(_boolField); } - public void ManualBindProperty(SerializedProperty property) + public void OnUpdateSyncType(ParameterSyncType syncType) { - _defaultValueField.BindProperty(property); - _hasExplicitDefaultSetField.BindProperty(property); + _syncType = syncType; + + if (syncType != ParameterSyncType.Bool) + { + _numberField.style.display = DisplayStyle.Flex; + _boolField.style.display = DisplayStyle.None; + OnUpdateNumberValue(_numberField.value); + } + else + { + _numberField.style.display = DisplayStyle.None; + _boolField.style.display = DisplayStyle.Flex; + OnUpdateBoolValue(_boolField.value); + } } - + + private void OnUpdateNumberValue(string value) + { + if (string.IsNullOrWhiteSpace(value)) + { + _defaultValueField.value = 0; + _hasExplicitDefaultValueField.value = false; + } + else if (float.TryParse(value, NumberStyles.Float, CultureInfo.InvariantCulture, out var parsed) + && !float.IsNaN(parsed) + && !float.IsInfinity(parsed)) + { + _defaultValueField.value = _syncType switch + { + ParameterSyncType.Int => Mathf.FloorToInt(Mathf.Clamp(parsed, 0, 255)), + ParameterSyncType.Float => Mathf.Clamp(parsed, -1, 1), + ParameterSyncType.Bool => parsed != 0 ? 1 : 0, + _ => parsed, + }; + _hasExplicitDefaultValueField.value = true; + } + + UpdateVisibleField(_defaultValueField.value, _hasExplicitDefaultValueField.value); + } + + private void OnUpdateBoolValue(string value) + { + _defaultValueField.value = value == V_True ? 1 : 0; + _hasExplicitDefaultValueField.value = value != V_None; + + UpdateVisibleField(_defaultValueField.value, _hasExplicitDefaultValueField.value); + } + private void UpdateVisibleField(float value, bool hasExplicitValue) { - if (Mathf.Abs(value) > 0.0000001) + if (hasExplicitValue || Mathf.Abs(value) > 0.0000001) { - hasExplicitValue = true; + _numberField.SetValueWithoutNotify(value.ToString(CultureInfo.InvariantCulture)); + _boolField.SetValueWithoutNotify(value != 0 ? V_True : V_False); } - - var str = hasExplicitValue ? value.ToString(CultureInfo.InvariantCulture) : ""; - _visibleField.SetValueWithoutNotify(str); - - string boolStr; - if (!hasExplicitValue) - boolStr = V_None; - else if (value > 0.5) - boolStr = V_True; else - boolStr = V_False; - - _boolField.SetValueWithoutNotify(boolStr); + { + _numberField.SetValueWithoutNotify(string.Empty); + _boolField.SetValueWithoutNotify(V_None); + } } } -} \ No newline at end of file +} diff --git a/Editor/Inspector/Parameters/ParameterConfigDrawer.cs b/Editor/Inspector/Parameters/ParameterConfigDrawer.cs index 32b9ddf2..09bff39d 100644 --- a/Editor/Inspector/Parameters/ParameterConfigDrawer.cs +++ b/Editor/Inspector/Parameters/ParameterConfigDrawer.cs @@ -20,14 +20,14 @@ namespace nadena.dev.modular_avatar.core.editor.Parameters Localization.UI.Localize(root); root.styleSheets.Add(uss); - var type_field = root.Q("f-type"); - - var f_sync_type = root.Q("f-sync-type"); + var f_type = root.Q("f-type"); + var f_sync_type = root.Q("f-sync-type"); + var f_is_prefix = root.Q("f-is-prefix"); SetupPairedDropdownField( root, - type_field, + f_type, f_sync_type, - root.Q("f-is-prefix"), + f_is_prefix, ("Bool", "False", "params.syncmode.Bool"), ("Float", "False", "params.syncmode.Float"), ("Int", "False", "params.syncmode.Int"), @@ -35,15 +35,9 @@ namespace nadena.dev.modular_avatar.core.editor.Parameters (null, "True", "params.syncmode.PhysBonesPrefix") ); - f_sync_type.Q().RegisterValueChangedCallback(evt => - { - var is_anim_only = evt.newValue == "Not Synced"; - - if (is_anim_only) - root.AddToClassList("st-anim-only"); - else - root.RemoveFromClassList("st-anim-only"); - }); + var f_default = root.Q(); + f_default.OnUpdateSyncType((ParameterSyncType)f_sync_type.index); + f_sync_type.RegisterValueChangedCallback(evt => f_default.OnUpdateSyncType((ParameterSyncType)f_sync_type.index)); var f_synced = root.Q("f-synced"); var f_local_only = root.Q("f-local-only"); diff --git a/Editor/Inspector/Parameters/Parameters.uss b/Editor/Inspector/Parameters/Parameters.uss index 5449835c..4d243bb1 100644 --- a/Editor/Inspector/Parameters/Parameters.uss +++ b/Editor/Inspector/Parameters/Parameters.uss @@ -30,7 +30,7 @@ display: none; } -.st-anim-only .st-anim-only__hide { +.st-ty-Not-Synced .st-anim-only__hide { display: none; } @@ -79,28 +79,12 @@ margin: 0; } -DefaultValueField TextField { - display: flex; +DefaultValueField > * { width: 60px; height: 100%; margin: 0; } -DefaultValueField DropdownField { - display: none; - width: 60px; - height: 100%; - margin: 0; -} - -.st-ty-Bool DefaultValueField TextField { - display: none; -} - -.st-ty-Bool DefaultValueField DropdownField { - display: flex; -} - #f-local-only { display: none; } From 4e3001ad650daf2eb62b5ccf357ec5d074cc5f62 Mon Sep 17 00:00:00 2001 From: bd_ Date: Sat, 14 Sep 2024 18:42:01 -0700 Subject: [PATCH 03/85] fix: NullReferenceExceptions from ShapeChangerPreview --- Editor/ReactiveObjects/ShapeChangerPreview.cs | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/Editor/ReactiveObjects/ShapeChangerPreview.cs b/Editor/ReactiveObjects/ShapeChangerPreview.cs index e26e48aa..912fd99b 100644 --- a/Editor/ReactiveObjects/ShapeChangerPreview.cs +++ b/Editor/ReactiveObjects/ShapeChangerPreview.cs @@ -133,12 +133,18 @@ namespace nadena.dev.modular_avatar.core.editor .ToImmutableList(); } - public Task Instantiate(RenderGroup group, IEnumerable<(Renderer, Renderer)> proxyPairs, ComputeContext context) + public async Task Instantiate(RenderGroup group, IEnumerable<(Renderer, Renderer)> proxyPairs, ComputeContext context) { var shapeValues = group.GetData(); var node = new Node(shapeValues, proxyPairs.First().Item2 as SkinnedMeshRenderer, _blendshapeCache); - return node.Refresh(proxyPairs, context, 0); + var rv = await node.Refresh(proxyPairs, context, 0); + if (rv == null) + { + context.Invalidate(); + } + + return node; } private class Node : IRenderFilterNode From 2ea9fb50b6a7ec00d88cc5ff67581b13d0b5dd6e Mon Sep 17 00:00:00 2001 From: bd_ Date: Sat, 14 Sep 2024 19:32:09 -0700 Subject: [PATCH 04/85] 1.10.0-rc.5 --- .github/ProjectRoot/vpm-manifest-2022.json | 2 +- package.json | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/ProjectRoot/vpm-manifest-2022.json b/.github/ProjectRoot/vpm-manifest-2022.json index d4bb97fb..306656c5 100644 --- a/.github/ProjectRoot/vpm-manifest-2022.json +++ b/.github/ProjectRoot/vpm-manifest-2022.json @@ -19,7 +19,7 @@ "dependencies": {} }, "nadena.dev.ndmf": { - "version": "1.5.0-rc.4" + "version": "1.5.0-rc.6" } } } \ No newline at end of file diff --git a/package.json b/package.json index 1ebb50f8..0855ccce 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "nadena.dev.modular-avatar", "displayName": "Modular Avatar", - "version": "1.10.0-rc.4", + "version": "1.10.0-rc.5", "unity": "2022.3", "description": "A suite of tools for assembling your avatar out of reusable components", "author": { @@ -16,6 +16,6 @@ }, "vpmDependencies": { "com.vrchat.avatars": ">=3.7.0", - "nadena.dev.ndmf": ">=1.5.0-rc.4 <2.0.0-a" + "nadena.dev.ndmf": ">=1.5.0-rc.6 <2.0.0-a" } } From 65194fbc800e03a5a0983cb7d6d8ae95126d9fe8 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 14 Sep 2024 19:41:44 -0700 Subject: [PATCH 05/85] chore(deps): bump path-to-regexp from 6.2.1 to 6.3.0 in /docs-site~ (#1132) Bumps [path-to-regexp](https://github.com/pillarjs/path-to-regexp) from 6.2.1 to 6.3.0. - [Release notes](https://github.com/pillarjs/path-to-regexp/releases) - [Changelog](https://github.com/pillarjs/path-to-regexp/blob/master/History.md) - [Commits](https://github.com/pillarjs/path-to-regexp/compare/v6.2.1...v6.3.0) --- updated-dependencies: - dependency-name: path-to-regexp dependency-type: indirect ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- docs-site~/yarn.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs-site~/yarn.lock b/docs-site~/yarn.lock index 560bf271..8a4071ab 100644 --- a/docs-site~/yarn.lock +++ b/docs-site~/yarn.lock @@ -1413,9 +1413,9 @@ __metadata: linkType: hard "path-to-regexp@npm:^6.2.0": - version: 6.2.1 - resolution: "path-to-regexp@npm:6.2.1" - checksum: 10/1e266be712d1a08086ee77beab12a1804842ec635dfed44f9ee1ba960a0e01cec8063fb8c92561115cdc0ce73158cdc7766e353ffa039340b4a85b370084c4d4 + version: 6.3.0 + resolution: "path-to-regexp@npm:6.3.0" + checksum: 10c0/73b67f4638b41cde56254e6354e46ae3a2ebc08279583f6af3d96fe4664fc75788f74ed0d18ca44fa4a98491b69434f9eee73b97bb5314bd1b5adb700f5c18d6 languageName: node linkType: hard From 3b28ea2b1425d4cbeeb1a8220869ba8438bf1833 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 14 Sep 2024 19:48:28 -0700 Subject: [PATCH 06/85] chore(deps): bump express from 4.19.2 to 4.21.0 in /docs~ (#1144) Bumps [express](https://github.com/expressjs/express) from 4.19.2 to 4.21.0. - [Release notes](https://github.com/expressjs/express/releases) - [Changelog](https://github.com/expressjs/express/blob/4.21.0/History.md) - [Commits](https://github.com/expressjs/express/compare/4.19.2...4.21.0) --- updated-dependencies: - dependency-name: express dependency-type: indirect ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- docs~/yarn.lock | 97 ++++++++++++++++++++++++++----------------------- 1 file changed, 52 insertions(+), 45 deletions(-) diff --git a/docs~/yarn.lock b/docs~/yarn.lock index 23f6d154..a5981967 100644 --- a/docs~/yarn.lock +++ b/docs~/yarn.lock @@ -3711,9 +3711,9 @@ __metadata: languageName: node linkType: hard -"body-parser@npm:1.20.2": - version: 1.20.2 - resolution: "body-parser@npm:1.20.2" +"body-parser@npm:1.20.3": + version: 1.20.3 + resolution: "body-parser@npm:1.20.3" dependencies: bytes: 3.1.2 content-type: ~1.0.5 @@ -3723,11 +3723,11 @@ __metadata: http-errors: 2.0.0 iconv-lite: 0.4.24 on-finished: 2.4.1 - qs: 6.11.0 + qs: 6.13.0 raw-body: 2.5.2 type-is: ~1.6.18 unpipe: 1.0.0 - checksum: 14d37ec638ab5c93f6099ecaed7f28f890d222c650c69306872e00b9efa081ff6c596cd9afb9930656aae4d6c4e1c17537bea12bb73c87a217cb3cfea8896737 + checksum: 1a35c59a6be8d852b00946330141c4f142c6af0f970faa87f10ad74f1ee7118078056706a05ae3093c54dabca9cd3770fa62a170a85801da1a4324f04381167d languageName: node linkType: hard @@ -5059,6 +5059,13 @@ __metadata: languageName: node linkType: hard +"encodeurl@npm:~2.0.0": + version: 2.0.0 + resolution: "encodeurl@npm:2.0.0" + checksum: abf5cd51b78082cf8af7be6785813c33b6df2068ce5191a40ca8b1afe6a86f9230af9a9ce694a5ce4665955e5c1120871826df9c128a642e09c58d592e2807fe + languageName: node + linkType: hard + "encoding@npm:^0.1.13": version: 0.1.13 resolution: "encoding@npm:0.1.13" @@ -5367,41 +5374,41 @@ __metadata: linkType: hard "express@npm:^4.17.3": - version: 4.19.2 - resolution: "express@npm:4.19.2" + version: 4.21.0 + resolution: "express@npm:4.21.0" dependencies: accepts: ~1.3.8 array-flatten: 1.1.1 - body-parser: 1.20.2 + body-parser: 1.20.3 content-disposition: 0.5.4 content-type: ~1.0.4 cookie: 0.6.0 cookie-signature: 1.0.6 debug: 2.6.9 depd: 2.0.0 - encodeurl: ~1.0.2 + encodeurl: ~2.0.0 escape-html: ~1.0.3 etag: ~1.8.1 - finalhandler: 1.2.0 + finalhandler: 1.3.1 fresh: 0.5.2 http-errors: 2.0.0 - merge-descriptors: 1.0.1 + merge-descriptors: 1.0.3 methods: ~1.1.2 on-finished: 2.4.1 parseurl: ~1.3.3 - path-to-regexp: 0.1.7 + path-to-regexp: 0.1.10 proxy-addr: ~2.0.7 - qs: 6.11.0 + qs: 6.13.0 range-parser: ~1.2.1 safe-buffer: 5.2.1 - send: 0.18.0 - serve-static: 1.15.0 + send: 0.19.0 + serve-static: 1.16.2 setprototypeof: 1.2.0 statuses: 2.0.1 type-is: ~1.6.18 utils-merge: 1.0.1 vary: ~1.1.2 - checksum: 212dbd6c2c222a96a61bc927639c95970a53b06257080bb9e2838adb3bffdb966856551fdad1ab5dd654a217c35db94f987d0aa88d48fb04d306340f5f34dca5 + checksum: 1c5212993f665809c249bf00ab550b989d1365a5b9171cdfaa26d93ee2ef10cd8add520861ec8d5da74b3194d8374e1d9d53e85ef69b89fd9c4196b87045a5d4 languageName: node linkType: hard @@ -5521,18 +5528,18 @@ __metadata: languageName: node linkType: hard -"finalhandler@npm:1.2.0": - version: 1.2.0 - resolution: "finalhandler@npm:1.2.0" +"finalhandler@npm:1.3.1": + version: 1.3.1 + resolution: "finalhandler@npm:1.3.1" dependencies: debug: 2.6.9 - encodeurl: ~1.0.2 + encodeurl: ~2.0.0 escape-html: ~1.0.3 on-finished: 2.4.1 parseurl: ~1.3.3 statuses: 2.0.1 unpipe: ~1.0.0 - checksum: 92effbfd32e22a7dff2994acedbd9bcc3aa646a3e919ea6a53238090e87097f8ef07cced90aa2cc421abdf993aefbdd5b00104d55c7c5479a8d00ed105b45716 + checksum: a8c58cd97c9cd47679a870f6833a7b417043f5a288cd6af6d0f49b476c874a506100303a128b6d3b654c3d74fa4ff2ffed68a48a27e8630cda5c918f2977dcf4 languageName: node linkType: hard @@ -7586,10 +7593,10 @@ __metadata: languageName: node linkType: hard -"merge-descriptors@npm:1.0.1": - version: 1.0.1 - resolution: "merge-descriptors@npm:1.0.1" - checksum: 5abc259d2ae25bb06d19ce2b94a21632583c74e2a9109ee1ba7fd147aa7362b380d971e0251069f8b3eb7d48c21ac839e21fa177b335e82c76ec172e30c31a26 +"merge-descriptors@npm:1.0.3": + version: 1.0.3 + resolution: "merge-descriptors@npm:1.0.3" + checksum: 52117adbe0313d5defa771c9993fe081e2d2df9b840597e966aadafde04ae8d0e3da46bac7ca4efc37d4d2b839436582659cd49c6a43eacb3fe3050896a105d1 languageName: node linkType: hard @@ -8869,10 +8876,10 @@ __metadata: languageName: node linkType: hard -"path-to-regexp@npm:0.1.7": - version: 0.1.7 - resolution: "path-to-regexp@npm:0.1.7" - checksum: 69a14ea24db543e8b0f4353305c5eac6907917031340e5a8b37df688e52accd09e3cebfe1660b70d76b6bd89152f52183f28c74813dbf454ba1a01c82a38abce +"path-to-regexp@npm:0.1.10": + version: 0.1.10 + resolution: "path-to-regexp@npm:0.1.10" + checksum: ab7a3b7a0b914476d44030340b0a65d69851af2a0f33427df1476100ccb87d409c39e2182837a96b98fb38c4ef2ba6b87bdad62bb70a2c153876b8061760583c languageName: node linkType: hard @@ -9521,12 +9528,12 @@ __metadata: languageName: node linkType: hard -"qs@npm:6.11.0": - version: 6.11.0 - resolution: "qs@npm:6.11.0" +"qs@npm:6.13.0": + version: 6.13.0 + resolution: "qs@npm:6.13.0" dependencies: - side-channel: ^1.0.4 - checksum: 6e1f29dd5385f7488ec74ac7b6c92f4d09a90408882d0c208414a34dd33badc1a621019d4c799a3df15ab9b1d0292f97c1dd71dc7c045e69f81a8064e5af7297 + side-channel: ^1.0.6 + checksum: e9404dc0fc2849245107108ce9ec2766cde3be1b271de0bf1021d049dc5b98d1a2901e67b431ac5509f865420a7ed80b7acb3980099fe1c118a1c5d2e1432ad8 languageName: node linkType: hard @@ -10377,9 +10384,9 @@ __metadata: languageName: node linkType: hard -"send@npm:0.18.0": - version: 0.18.0 - resolution: "send@npm:0.18.0" +"send@npm:0.19.0": + version: 0.19.0 + resolution: "send@npm:0.19.0" dependencies: debug: 2.6.9 depd: 2.0.0 @@ -10394,7 +10401,7 @@ __metadata: on-finished: 2.4.1 range-parser: ~1.2.1 statuses: 2.0.1 - checksum: 74fc07ebb58566b87b078ec63e5a3e41ecd987e4272ba67b7467e86c6ad51bc6b0b0154133b6d8b08a2ddda360464f71382f7ef864700f34844a76c8027817a8 + checksum: 5ae11bd900c1c2575525e2aa622e856804e2f96a09281ec1e39610d089f53aa69e13fd8db84b52f001d0318cf4bb0b3b904ad532fc4c0014eb90d32db0cff55f languageName: node linkType: hard @@ -10438,15 +10445,15 @@ __metadata: languageName: node linkType: hard -"serve-static@npm:1.15.0": - version: 1.15.0 - resolution: "serve-static@npm:1.15.0" +"serve-static@npm:1.16.2": + version: 1.16.2 + resolution: "serve-static@npm:1.16.2" dependencies: - encodeurl: ~1.0.2 + encodeurl: ~2.0.0 escape-html: ~1.0.3 parseurl: ~1.3.3 - send: 0.18.0 - checksum: af57fc13be40d90a12562e98c0b7855cf6e8bd4c107fe9a45c212bf023058d54a1871b1c89511c3958f70626fff47faeb795f5d83f8cf88514dbaeb2b724464d + send: 0.19.0 + checksum: dffc52feb4cc5c68e66d0c7f3c1824d4e989f71050aefc9bd5f822a42c54c9b814f595fc5f2b717f4c7cc05396145f3e90422af31186a93f76cf15f707019759 languageName: node linkType: hard @@ -10530,7 +10537,7 @@ __metadata: languageName: node linkType: hard -"side-channel@npm:^1.0.4": +"side-channel@npm:^1.0.6": version: 1.0.6 resolution: "side-channel@npm:1.0.6" dependencies: From b83b89ce38d339957aba36301305818cef860891 Mon Sep 17 00:00:00 2001 From: nekobako Date: Mon, 16 Sep 2024 06:23:15 +0900 Subject: [PATCH 07/85] fix: incorrect default value for single menu item with automatic value (#1147) --- Editor/ReactiveObjects/ParameterAssignerPass.cs | 14 +++++--------- .../AutoValueAssignmentTests.cs | 15 +++++++++++---- 2 files changed, 16 insertions(+), 13 deletions(-) diff --git a/Editor/ReactiveObjects/ParameterAssignerPass.cs b/Editor/ReactiveObjects/ParameterAssignerPass.cs index 5bfa59f7..1f3ff8c4 100644 --- a/Editor/ReactiveObjects/ParameterAssignerPass.cs +++ b/Editor/ReactiveObjects/ParameterAssignerPass.cs @@ -96,10 +96,10 @@ namespace nadena.dev.modular_avatar.core.editor { defaultValue = list.FirstOrDefault(m => m.isDefault && !m.automaticValue)?.Control?.value ?? 0; - if (list.Count == 1) - // If we have only a single entry, it's probably an on-off toggle, so we'll implicitly let 0 - // be the 'unselected' default value (if this is not default) - defaultValue = 0; + if (list.Count == 1 && list[0].isDefault && list[0].automaticValue) + // If we have only a single entry, it's probably an on-off toggle, so we'll implicitly let 1 + // be the 'selected' default value (if this is default and automatic value) + defaultValue = 1; } HashSet usedValues = new(); @@ -124,11 +124,7 @@ namespace nadena.dev.modular_avatar.core.editor { if (mami.automaticValue) { - if (list.Count == 1) - { - mami.Control.value = 1; - } - else if (mami.isDefault) + if (mami.isDefault) { mami.Control.value = defaultValue; } diff --git a/UnitTests~/ReactiveComponent/ParameterAssignment/AutoValueAssignmentTests.cs b/UnitTests~/ReactiveComponent/ParameterAssignment/AutoValueAssignmentTests.cs index 62c3745c..ce0bd961 100644 --- a/UnitTests~/ReactiveComponent/ParameterAssignment/AutoValueAssignmentTests.cs +++ b/UnitTests~/ReactiveComponent/ParameterAssignment/AutoValueAssignmentTests.cs @@ -16,10 +16,14 @@ namespace UnitTests.ReactiveComponent.ParameterAssignment [Test] public void ManuallyAssignedParametersAreNotReplaced() { - TestAssignments( - new[] { (false, 1.0f), (false, 4.0f) }, - new[] { 1.0f, 4.0f } - ); + TestAssignments(new[] { (false, 1.0f) }, new[] { 1.0f }); + TestAssignments(new[] { (false, 1.0f) }, new[] { 1.0f }, 0); + + TestAssignments(new[] { (false, 4.0f) }, new[] { 4.0f }); + TestAssignments(new[] { (false, 4.0f) }, new[] { 4.0f }, 0); + + TestAssignments(new[] { (false, 1.0f), (false, 4.0f) }, new[] { 1.0f, 4.0f }); + TestAssignments(new[] { (false, 1.0f), (false, 4.0f) }, new[] { 1.0f, 4.0f }, 0); } [Test] @@ -98,6 +102,9 @@ namespace UnitTests.ReactiveComponent.ParameterAssignment { Assert.AreEqual(expected, mami.Control.value); } + + var expectedDefaultValue = defaultIndex.HasValue ? expectedAssignments[defaultIndex.Value] : 0; + Assert.AreEqual(expectedDefaultValue, avDesc.expressionParameters.parameters.Single().defaultValue); } } } \ No newline at end of file From c80d24ea462f4b7f985c20efe8080463635900ce Mon Sep 17 00:00:00 2001 From: nekobako Date: Mon, 16 Sep 2024 06:24:13 +0900 Subject: [PATCH 08/85] Fix parameter synced conflict (#1150) * fix: parameter should be synced if any of sibling parameter is set to be synced * fix: parameter should be saved/synced if any of menu item references same parameter is set to be saved/synced --- Editor/ReactiveObjects/ParameterAssignerPass.cs | 8 ++++---- Editor/RenameParametersHook.cs | 3 ++- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/Editor/ReactiveObjects/ParameterAssignerPass.cs b/Editor/ReactiveObjects/ParameterAssignerPass.cs index 1f3ff8c4..267be91f 100644 --- a/Editor/ReactiveObjects/ParameterAssignerPass.cs +++ b/Editor/ReactiveObjects/ParameterAssignerPass.cs @@ -117,8 +117,8 @@ namespace nadena.dev.modular_avatar.core.editor var canBeBool = true; var canBeInt = true; - var isSaved = true; - var isSynced = true; + var isSaved = false; + var isSynced = false; foreach (var mami in list) { @@ -142,8 +142,8 @@ namespace nadena.dev.modular_avatar.core.editor else canBeBool &= mami.Control.value is >= 0 and <= 1; - isSaved &= mami.isSaved; - isSynced &= mami.isSynced; + isSaved |= mami.isSaved; + isSynced |= mami.isSynced; } if (!declaredParams.ContainsKey(paramName)) diff --git a/Editor/RenameParametersHook.cs b/Editor/RenameParametersHook.cs index a47e27cc..5bd401c3 100644 --- a/Editor/RenameParametersHook.cs +++ b/Editor/RenameParametersHook.cs @@ -116,6 +116,7 @@ namespace nadena.dev.modular_avatar.core.editor } ResolvedParameter.saved |= info.ResolvedParameter.saved; + ResolvedParameter.localOnly &= info.ResolvedParameter.localOnly; } public void MergeChild(ParameterInfo info) @@ -305,7 +306,7 @@ namespace nadena.dev.modular_avatar.core.editor newParameter.defaultValue = info.ResolvedParameter.HasDefaultValue ? info.ResolvedParameter.defaultValue : parameter.defaultValue; newParameter.name = parameter.name; newParameter.valueType = parameter.valueType; - newParameter.networkSynced = parameter.networkSynced; + newParameter.networkSynced = parameter.networkSynced || !info.ResolvedParameter.localOnly; newParameter.saved = parameter.saved || info.ResolvedParameter.saved; return newParameter; From 48b7d80f7c8cd8e70dbba15b14ea324abdc3ceab Mon Sep 17 00:00:00 2001 From: nekobako Date: Mon, 16 Sep 2024 11:32:59 +0900 Subject: [PATCH 09/85] 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 --- .../ParamsUsage/MAParametersIntrospection.cs | 11 +-- .../ReactiveObjects/ParameterAssignerPass.cs | 23 ++--- Runtime/ModularAvatarMenuItem.cs | 32 +++++++ .../ParameterAssignment/ParameterTypeTests.cs | 85 +++++++++++++++++++ .../ParameterTypeTests.cs.meta | 3 + 5 files changed, 130 insertions(+), 24 deletions(-) create mode 100644 UnitTests~/ReactiveComponent/ParameterAssignment/ParameterTypeTests.cs create mode 100644 UnitTests~/ReactiveComponent/ParameterAssignment/ParameterTypeTests.cs.meta diff --git a/Editor/ParamsUsage/MAParametersIntrospection.cs b/Editor/ParamsUsage/MAParametersIntrospection.cs index 2388d178..6ff9f720 100644 --- a/Editor/ParamsUsage/MAParametersIntrospection.cs +++ b/Editor/ParamsUsage/MAParametersIntrospection.cs @@ -34,19 +34,10 @@ namespace nadena.dev.modular_avatar.core.editor 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( name, ParameterNamespace.Animator, - _component, PluginDefinition.Instance, type) + _component, PluginDefinition.Instance, _component.AnimatorControllerParameterType) { WantSynced = _component.isSynced, IsHidden = hidden, diff --git a/Editor/ReactiveObjects/ParameterAssignerPass.cs b/Editor/ReactiveObjects/ParameterAssignerPass.cs index 267be91f..eb0e512f 100644 --- a/Editor/ReactiveObjects/ParameterAssignerPass.cs +++ b/Editor/ReactiveObjects/ParameterAssignerPass.cs @@ -115,8 +115,7 @@ namespace nadena.dev.modular_avatar.core.editor var nextValue = 1; - var canBeBool = true; - var canBeInt = true; + var valueType = VRCExpressionParameters.ValueType.Bool; var isSaved = 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) - canBeInt = false; - else - canBeBool &= mami.Control.value is >= 0 and <= 1; + var newValueType = mami.ExpressionParametersValueType; + if (valueType == VRCExpressionParameters.ValueType.Bool || newValueType == VRCExpressionParameters.ValueType.Float) + { + valueType = newValueType; + } isSaved |= mami.isSaved; isSynced |= mami.isSynced; @@ -148,15 +148,10 @@ namespace nadena.dev.modular_avatar.core.editor 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 { name = paramName, - valueType = newType, + valueType = valueType, saved = isSaved, defaultValue = defaultValue, 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 // menu items. InitialValue = mami.isDefault ? mami.Control.value : -999, - ParameterValueLo = mami.Control.value - 0.5f, - ParameterValueHi = mami.Control.value + 0.5f, + ParameterValueLo = mami.Control.value - 0.005f, + ParameterValueHi = mami.Control.value + 0.005f, DebugReference = mami, }; } diff --git a/Runtime/ModularAvatarMenuItem.cs b/Runtime/ModularAvatarMenuItem.cs index e38023ee..b5fd5d31 100644 --- a/Runtime/ModularAvatarMenuItem.cs +++ b/Runtime/ModularAvatarMenuItem.cs @@ -149,6 +149,38 @@ namespace nadena.dev.modular_avatar.core if (control.subParameters.Length > maxSubParams) 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, + }; } } diff --git a/UnitTests~/ReactiveComponent/ParameterAssignment/ParameterTypeTests.cs b/UnitTests~/ReactiveComponent/ParameterAssignment/ParameterTypeTests.cs new file mode 100644 index 00000000..6a4a45b5 --- /dev/null +++ b/UnitTests~/ReactiveComponent/ParameterAssignment/ParameterTypeTests.cs @@ -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(); + descriptor.expressionParameters = ScriptableObject.CreateInstance(); + descriptor.expressionParameters.parameters = Array.Empty(); + + for (var i = 0; i < values.Length; i++) + { + var obj = CreateChild(root, i.ToString()); + var mami = obj.AddComponent(); + 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); + } + } +} \ No newline at end of file diff --git a/UnitTests~/ReactiveComponent/ParameterAssignment/ParameterTypeTests.cs.meta b/UnitTests~/ReactiveComponent/ParameterAssignment/ParameterTypeTests.cs.meta new file mode 100644 index 00000000..e8b62222 --- /dev/null +++ b/UnitTests~/ReactiveComponent/ParameterAssignment/ParameterTypeTests.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: c7051ac5a4bbe084c9d34c01c523eda3 +timeCreated: 1726276608 \ No newline at end of file From 9073ff8c2d7dd9a3f5e979d172192dc8592e7f54 Mon Sep 17 00:00:00 2001 From: bd_ Date: Sun, 15 Sep 2024 22:33:10 -0400 Subject: [PATCH 10/85] fix: blendshape sync reserializes prefab assets (#1153) Hopefully fixes: #1148 --- Runtime/ModularAvatarBlendshapeSync.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Runtime/ModularAvatarBlendshapeSync.cs b/Runtime/ModularAvatarBlendshapeSync.cs index cbaef34f..c6019341 100644 --- a/Runtime/ModularAvatarBlendshapeSync.cs +++ b/Runtime/ModularAvatarBlendshapeSync.cs @@ -72,7 +72,9 @@ namespace nadena.dev.modular_avatar.core private void Rebind() { + #if UNITY_EDITOR if (this == null) return; + if (UnityEditor.PrefabUtility.IsPartOfPrefabAsset(this)) return; _editorBindings = new List(); @@ -110,6 +112,7 @@ namespace nadena.dev.modular_avatar.core } Update(); + #endif } private void Update() From 3648348184bad2e304b031766293eda4fa616ca4 Mon Sep 17 00:00:00 2001 From: bd_ Date: Sun, 15 Sep 2024 22:47:26 -0400 Subject: [PATCH 11/85] fix: ScaleAdjusterPreview breaks when avatar descriptors are nested (#1154) --- Editor/ScaleAdjuster/ScaleAdjusterPreview.cs | 34 ++++++++++---------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/Editor/ScaleAdjuster/ScaleAdjusterPreview.cs b/Editor/ScaleAdjuster/ScaleAdjusterPreview.cs index 31f3beb6..6ea4b838 100644 --- a/Editor/ScaleAdjuster/ScaleAdjusterPreview.cs +++ b/Editor/ScaleAdjuster/ScaleAdjusterPreview.cs @@ -61,27 +61,27 @@ namespace nadena.dev.modular_avatar.core.editor var avatarToRenderer = new Dictionary>(new ObjectIdentityComparer()); - foreach (var adjuster in scaleAdjusters) + foreach (var root in ctx.GetAvatarRoots()) { - if (adjuster == null) continue; - - // Find parent object - // TODO: Reactive helper - var root = FindAvatarRootObserving(ctx, adjuster.gameObject); - if (root == null) continue; - - if (!avatarToRenderer.TryGetValue(root, out var renderers)) + if (ctx.GetComponentsInChildren(root, true).Length == 0) { - renderers = new HashSet(new ObjectIdentityComparer()); - avatarToRenderer.Add(root, renderers); + continue; + } - foreach (var renderer in root.GetComponentsInChildren()) - { - // For now, the preview system only supports MeshRenderer and SkinnedMeshRenderer - if (renderer is not MeshRenderer and not SkinnedMeshRenderer) continue; + if (ctx.GetAvatarRoot(root?.transform?.parent?.gameObject) != null) + { + continue; // nested avatar descriptor + } + + var renderers = new HashSet(new ObjectIdentityComparer()); + avatarToRenderer.Add(root, renderers); - renderers.Add(renderer); - } + foreach (var renderer in root.GetComponentsInChildren()) + { + // For now, the preview system only supports MeshRenderer and SkinnedMeshRenderer + if (renderer is not MeshRenderer and not SkinnedMeshRenderer) continue; + + renderers.Add(renderer); } } From 56f1b67d310b0c2843bc7714168db1f4d2390c1f Mon Sep 17 00:00:00 2001 From: nekobako Date: Wed, 18 Sep 2024 11:47:56 +0900 Subject: [PATCH 12/85] fix: animator initial value type conversion (#1163) --- Editor/ApplyAnimatorDefaultValuesPass.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Editor/ApplyAnimatorDefaultValuesPass.cs b/Editor/ApplyAnimatorDefaultValuesPass.cs index f2554d13..7b3c91ed 100644 --- a/Editor/ApplyAnimatorDefaultValuesPass.cs +++ b/Editor/ApplyAnimatorDefaultValuesPass.cs @@ -40,7 +40,7 @@ namespace nadena.dev.modular_avatar.core.editor switch (parameters[i].type) { case AnimatorControllerParameterType.Bool: - parameters[i].defaultBool = defaultValue > 0.5f; + parameters[i].defaultBool = defaultValue != 0.0f; break; case AnimatorControllerParameterType.Int: parameters[i].defaultInt = Mathf.RoundToInt(defaultValue); From 8ed877c99c8885edc5dc304718a53e340bc3df86 Mon Sep 17 00:00:00 2001 From: Sayamame-beans <61457993+Sayamame-beans@users.noreply.github.com> Date: Wed, 18 Sep 2024 11:56:15 +0900 Subject: [PATCH 13/85] fix: add pattern of "upper_chest" as a chest bone (#1168) --- Editor/HeuristicBoneMapper.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Editor/HeuristicBoneMapper.cs b/Editor/HeuristicBoneMapper.cs index 5f5b1044..b1ba169b 100644 --- a/Editor/HeuristicBoneMapper.cs +++ b/Editor/HeuristicBoneMapper.cs @@ -46,7 +46,7 @@ namespace nadena.dev.modular_avatar.core.editor new[] {"LeftFoot", "Foot_Left", "Foot_L", "Ankle_L", "Foot.L.001", "Left ankle", "heel.L", "heel"}, new[] {"RightFoot", "Foot_Right", "Foot_R", "Ankle_R", "Foot.R.001", "Right ankle", "heel.R", "heel"}, new[] {"Spine", "spine01"}, - new[] {"Chest", "Bust", "spine02"}, + new[] {"Chest", "Bust", "spine02", "upper_chest"}, new[] {"Neck"}, new[] {"Head"}, new[] {"LeftShoulder", "Shoulder_Left", "Shoulder_L"}, From c2b6766a40ecc0088d927351f78ece6c85ee3e90 Mon Sep 17 00:00:00 2001 From: nadena-dev-ci Date: Wed, 18 Sep 2024 12:25:41 +0900 Subject: [PATCH 14/85] New Crowdin updates (#1169) * New translations en-us.json (Japanese) * New translations en-us.json (Japanese) --- Editor/Localization/ja-JP.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Editor/Localization/ja-JP.json b/Editor/Localization/ja-JP.json index 96f1ccfc..7c011df0 100644 --- a/Editor/Localization/ja-JP.json +++ b/Editor/Localization/ja-JP.json @@ -183,6 +183,8 @@ "menuitem.prop.type.tooltip": "この項目の種別", "menuitem.prop.value": "パラメーター値", "menuitem.prop.value.tooltip": "この項目が操作されたとき、パラメーターが設定される値", + "menuitem.prop.automatic_value": "自動", + "menuitem.prop.automatic_value.tooltip": "かぶらない値を自動的に割り振る", "menuitem.prop.parameter": "パラメーター名", "menuitem.prop.label": "表示名", "menuitem.prop.submenu_asset": "サブメニューアセット", @@ -197,8 +199,6 @@ "menuitem.prop.is_saved.tooltip": "有効になっていると、アバター変更やワールド移動するときこの設定が保持されます。", "menuitem.prop.is_synced": "同期する", "menuitem.prop.is_synced.tooltip": "有効の場合はほかのプレイヤーに同期されます。", - "menuitem.prop.automatic_value": "自動", - "menuitem.prop.automatic_value.tooltip": "かぶらない値を自動的に割り振る", "menuitem.param.rotation": "回転パラメーター名", "menuitem.param.rotation.tooltip": "このメニューアイテムの回転に連動するべきパラメーター", "menuitem.param.horizontal": "横パラメーター名", From a98ef213fffbdef929482df29b58a7c8e611aa75 Mon Sep 17 00:00:00 2001 From: bd_ Date: Tue, 17 Sep 2024 23:25:47 -0400 Subject: [PATCH 15/85] fix: performance issues with MAMenuItem (#1170) Cache parameter introspection results (using PropCache) to avoid excessive recomputation. Closes: #1165 --- Editor/Inspector/Menu/MenuItemGUI.cs | 43 +++++++++++++++++++++++++--- 1 file changed, 39 insertions(+), 4 deletions(-) diff --git a/Editor/Inspector/Menu/MenuItemGUI.cs b/Editor/Inspector/Menu/MenuItemGUI.cs index 67458e40..29c75b63 100644 --- a/Editor/Inspector/Menu/MenuItemGUI.cs +++ b/Editor/Inspector/Menu/MenuItemGUI.cs @@ -2,10 +2,12 @@ using System; using System.Collections.Generic; +using System.Collections.Immutable; using System.Linq; using System.Runtime.Serialization; using nadena.dev.modular_avatar.core.menu; using nadena.dev.ndmf; +using nadena.dev.ndmf.preview; using UnityEditor; using UnityEngine; using VRC.SDK3.Avatars.Components; @@ -21,6 +23,39 @@ namespace nadena.dev.modular_avatar.core.editor protected override string localizationPrefix => "submenu_source"; } + internal static class ParameterIntrospectionCache + { + internal static PropCache> ProvidedParameterCache = new (GetParametersForObject_miss); + + internal static PropCache> + ParameterRemappingCache = new(GetParameterRemappingsAt_miss); + + private static ImmutableList GetParametersForObject_miss(ComputeContext ctx, GameObject obj) + { + if (obj == null) return ImmutableList.Empty; + + return ParameterInfo.ForPreview(ctx).GetParametersForObject(obj).ToImmutableList(); + } + + private static ImmutableDictionary<(ParameterNamespace, string), ParameterMapping> + GetParameterRemappingsAt_miss(ComputeContext ctx, GameObject obj) + { + if (obj == null) return ImmutableDictionary<(ParameterNamespace, string), ParameterMapping>.Empty; + + return ParameterInfo.ForPreview(ctx).GetParameterRemappingsAt(obj); + } + + internal static ImmutableList GetParametersForObject(GameObject avatar) + { + return ProvidedParameterCache.Get(ComputeContext.NullContext, avatar); + } + + internal static ImmutableDictionary<(ParameterNamespace, string), ParameterMapping> GetParameterRemappingsAt(GameObject avatar) + { + return ParameterRemappingCache.Get(ComputeContext.NullContext, avatar); + } + } + internal class MenuItemCoreGUI { private static readonly ObjectIDGenerator IdGenerator = new ObjectIDGenerator(); @@ -134,12 +169,12 @@ namespace nadena.dev.modular_avatar.core.editor Dictionary rootParameters = new(); - foreach (var param in ParameterInfo.ForUI.GetParametersForObject(parentAvatar.gameObject) + foreach (var param in ParameterIntrospectionCache.GetParametersForObject(parentAvatar.gameObject) .Where(p => p.Namespace == ParameterNamespace.Animator) ) rootParameters[param.EffectiveName] = param; - var remaps = ParameterInfo.ForUI.GetParameterRemappingsAt(paramRef); + var remaps = ParameterIntrospectionCache.GetParameterRemappingsAt(paramRef); foreach (var remap in remaps) { if (remap.Key.Item1 != ParameterNamespace.Animator) continue; @@ -613,7 +648,7 @@ namespace nadena.dev.modular_avatar.core.editor var myParameterName = myMenuItem.Control.parameter.name; if (string.IsNullOrEmpty(myParameterName)) return new List(); - var myMappings = ParameterInfo.ForUI.GetParameterRemappingsAt(myMenuItem.gameObject); + var myMappings = ParameterIntrospectionCache.GetParameterRemappingsAt(myMenuItem.gameObject); if (myMappings.TryGetValue((ParameterNamespace.Animator, myParameterName), out var myReplacement)) myParameterName = myReplacement.ParameterName; @@ -627,7 +662,7 @@ namespace nadena.dev.modular_avatar.core.editor var otherParameterName = otherMenuItem.Control.parameter.name; if (string.IsNullOrEmpty(otherParameterName)) continue; - var otherMappings = ParameterInfo.ForUI.GetParameterRemappingsAt(otherMenuItem.gameObject); + var otherMappings = ParameterIntrospectionCache.GetParameterRemappingsAt(otherMenuItem.gameObject); if (otherMappings.TryGetValue((ParameterNamespace.Animator, otherParameterName), out var otherReplacement)) otherParameterName = otherReplacement.ParameterName; From 9b4e76e053fa6bb2b278b32b141486779decc8f9 Mon Sep 17 00:00:00 2001 From: bd_ Date: Tue, 17 Sep 2024 23:26:26 -0400 Subject: [PATCH 16/85] fix: Scale Adjuster preview breaks after changing scale of avatar root (#1172) Closes: #1171 --- Editor/ScaleAdjuster/ScaleAdjusterPreview.cs | 42 ++++++++++++++------ 1 file changed, 30 insertions(+), 12 deletions(-) diff --git a/Editor/ScaleAdjuster/ScaleAdjusterPreview.cs b/Editor/ScaleAdjuster/ScaleAdjusterPreview.cs index 6ea4b838..892d20e6 100644 --- a/Editor/ScaleAdjuster/ScaleAdjusterPreview.cs +++ b/Editor/ScaleAdjuster/ScaleAdjusterPreview.cs @@ -129,28 +129,37 @@ namespace nadena.dev.modular_avatar.core.editor var priorScene = SceneManager.GetActiveScene(); var bonesSet = GetSourceBonesSet(context, proxyPairList); - var bones = bonesSet.ToArray(); + var bones = bonesSet.OrderBy(k => k.gameObject.name).ToArray(); + Transform[] sourceBones; Transform[] destinationBones; try { SceneManager.SetActiveScene(scene); VirtualAvatarRoot = new GameObject(avatarRoot.name + " [ScaleAdjuster]"); - _srcBones = new TransformAccessArray(bones.ToArray()); - destinationBones = CreateShadowBones(bones); + + _shadowBoneMap = CreateShadowBones(bones); + sourceBones = new Transform[_shadowBoneMap.Count]; + destinationBones = new Transform[_shadowBoneMap.Count]; + + var i = 0; + foreach (var (src, dst) in _shadowBoneMap) + { + sourceBones[i] = src; + destinationBones[i] = dst; + i++; + } } finally { SceneManager.SetActiveScene(priorScene); } - _shadowBoneMap = new Dictionary(new ObjectIdentityComparer()); - for (var i = 0; i < bones.Length; i++) _shadowBoneMap[bones[i]] = destinationBones[i]; - + _srcBones = new TransformAccessArray(sourceBones); _dstBones = new TransformAccessArray(destinationBones); - _boneIsValid = new NativeArray(bones.Length, Allocator.Persistent); - _boneStates = new NativeArray(bones.Length, Allocator.Persistent); + _boneIsValid = new NativeArray(sourceBones.Length, Allocator.Persistent); + _boneStates = new NativeArray(sourceBones.Length, Allocator.Persistent); FindScaleAdjusters(context); TransferBoneStates(); @@ -170,8 +179,12 @@ namespace nadena.dev.modular_avatar.core.editor if (smr == null) continue; foreach (var b in context.Observe(smr, smr_ => smr_.bones, Enumerable.SequenceEqual)) + { if (b != null) + { bonesSet.Add(b); + } + } } return bonesSet; @@ -182,10 +195,14 @@ namespace nadena.dev.modular_avatar.core.editor _finalBonesMap.Clear(); foreach (var (sa, proxy) in _scaleAdjusters.ToList()) + { // Note: We leak the proxy here, as destroying it can cause visual artifacts. They'll eventually get // cleaned up whenever the pipeline is fully reset, or when the scene is reloaded. if (sa == null) + { _scaleAdjusters.Remove(sa); + } + } _scaleAdjusters.Clear(); @@ -224,14 +241,13 @@ namespace nadena.dev.modular_avatar.core.editor return Task.FromResult(this); } - private Transform[] CreateShadowBones(Transform[] srcBones) + private Dictionary CreateShadowBones(Transform[] srcBones) { var srcToDst = new Dictionary(new ObjectIdentityComparer()); - var dstBones = new Transform[srcBones.Length]; - for (var i = 0; i < srcBones.Length; i++) dstBones[i] = GetShadowBone(srcBones[i]); + for (var i = 0; i < srcBones.Length; i++) GetShadowBone(srcBones[i]); - return dstBones; + return srcToDst; Transform GetShadowBone(Transform srcBone) { @@ -278,12 +294,14 @@ namespace nadena.dev.modular_avatar.core.editor BoneIsValid[index] = transform.isValid; if (transform.isValid) + { BoneStates[index] = new TransformState { localPosition = transform.position, localRotation = transform.rotation, localScale = transform.localScale }; + } } } From 71ddd257a330367384172552b44269dbbe5ae843 Mon Sep 17 00:00:00 2001 From: bd_ Date: Tue, 17 Sep 2024 23:40:09 -0400 Subject: [PATCH 17/85] test: add tests for PropCache (#1156) * test: add tests for PropCache * chore: update NDMF dependency --- .github/ProjectRoot/vpm-manifest-2022.json | 2 +- UnitTests~/PropCacheTest.meta | 3 + UnitTests~/PropCacheTest/PropCacheTest.cs | 71 +++++++++++++++++++ .../PropCacheTest/PropCacheTest.cs.meta | 3 + package.json | 2 +- 5 files changed, 79 insertions(+), 2 deletions(-) create mode 100644 UnitTests~/PropCacheTest.meta create mode 100644 UnitTests~/PropCacheTest/PropCacheTest.cs create mode 100644 UnitTests~/PropCacheTest/PropCacheTest.cs.meta diff --git a/.github/ProjectRoot/vpm-manifest-2022.json b/.github/ProjectRoot/vpm-manifest-2022.json index 306656c5..bbb71a9e 100644 --- a/.github/ProjectRoot/vpm-manifest-2022.json +++ b/.github/ProjectRoot/vpm-manifest-2022.json @@ -19,7 +19,7 @@ "dependencies": {} }, "nadena.dev.ndmf": { - "version": "1.5.0-rc.6" + "version": "1.5.0-rc.7" } } } \ No newline at end of file diff --git a/UnitTests~/PropCacheTest.meta b/UnitTests~/PropCacheTest.meta new file mode 100644 index 00000000..158892ac --- /dev/null +++ b/UnitTests~/PropCacheTest.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 77aba4362cec4cea91ee64c6e640b6b2 +timeCreated: 1726436552 \ No newline at end of file diff --git a/UnitTests~/PropCacheTest/PropCacheTest.cs b/UnitTests~/PropCacheTest/PropCacheTest.cs new file mode 100644 index 00000000..2b63161c --- /dev/null +++ b/UnitTests~/PropCacheTest/PropCacheTest.cs @@ -0,0 +1,71 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; +using nadena.dev.modular_avatar.core.editor; +using nadena.dev.ndmf.preview; +using NUnit.Framework; +using UnityEngine; +using UnityEngine.TestTools; + +namespace UnitTests.PropCacheTest +{ + public class PropCacheTest + { + [UnityTest] + public IEnumerator TestCacheInvalidation() + { + int seq = 0; + + Dictionary>> invalidators = new(); + PropCache cache = new PropCache((ctx, k) => + { + Debug.Log("Generating value for " + k); + if (!invalidators.TryGetValue(k, out var list)) + { + list = new List>(); + invalidators[k] = list; + } + + list.Add(new WeakReference(ctx)); + + return (k * 10) + seq++; + }); + + ComputeContext ctx = new ComputeContext("c1"); + int val = cache.Get(ctx, 1); + Assert.AreEqual(10, val); + + ComputeContext ctx2 = new ComputeContext("c2"); + val = cache.Get(ctx2, 1); + Assert.AreEqual(10, val); + + invalidators[1][0].TryGetTarget(out var target); + target?.Invalidate(); + + Debug.Log("Pre-flush"); + ComputeContext.FlushInvalidates(); + Debug.Log("Mid-flush"); + ComputeContext.FlushInvalidates(); + Debug.Log("Post-flush"); + + // Task processing can happen asynchronously. + + int limit = 10; + while (limit-- > 0 && (!ctx.IsInvalidated || !ctx2.IsInvalidated)) + { + Debug.Log("Waiting for invalidation: " + limit); + Thread.Sleep(100); + } + + Assert.IsTrue(ctx.IsInvalidated); + Assert.IsTrue(ctx2.IsInvalidated); + + val = cache.Get(ctx, 1); + Assert.AreEqual(12, val); + + yield return null; + } + } +} \ No newline at end of file diff --git a/UnitTests~/PropCacheTest/PropCacheTest.cs.meta b/UnitTests~/PropCacheTest/PropCacheTest.cs.meta new file mode 100644 index 00000000..ef69296a --- /dev/null +++ b/UnitTests~/PropCacheTest/PropCacheTest.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 6891e8d136c942878bca9b50b5c58ec9 +timeCreated: 1726436558 \ No newline at end of file diff --git a/package.json b/package.json index 0855ccce..75123de2 100644 --- a/package.json +++ b/package.json @@ -16,6 +16,6 @@ }, "vpmDependencies": { "com.vrchat.avatars": ">=3.7.0", - "nadena.dev.ndmf": ">=1.5.0-rc.6 <2.0.0-a" + "nadena.dev.ndmf": ">=1.5.0-rc.7 <2.0.0-a" } } From c11a76642cb852897dd7eaf1612adae80d9267a9 Mon Sep 17 00:00:00 2001 From: bd_ Date: Tue, 17 Sep 2024 20:40:32 -0700 Subject: [PATCH 18/85] 1.10.0-rc.6 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 75123de2..e411fa3a 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "nadena.dev.modular-avatar", "displayName": "Modular Avatar", - "version": "1.10.0-rc.5", + "version": "1.10.0-rc.6", "unity": "2022.3", "description": "A suite of tools for assembling your avatar out of reusable components", "author": { From 7bf510624616649a54e1257e980b67bb901f60bb Mon Sep 17 00:00:00 2001 From: bd_ Date: Fri, 20 Sep 2024 20:32:27 -0700 Subject: [PATCH 19/85] fix: animation clips are not added to the persistent asset object on build (#1182) This resulted in data loss when `AssetDatabase.StopAssetEditing()` was called, which can happen if VRCF triggers Poi lockdown. --- Editor/Animation/AnimationDatabase.cs | 27 ++++++++++++++++++++++++++- Editor/Animation/DeepClone.cs | 5 +++++ 2 files changed, 31 insertions(+), 1 deletion(-) diff --git a/Editor/Animation/AnimationDatabase.cs b/Editor/Animation/AnimationDatabase.cs index 6c35e7df..f9ef2335 100644 --- a/Editor/Animation/AnimationDatabase.cs +++ b/Editor/Animation/AnimationDatabase.cs @@ -9,6 +9,7 @@ using nadena.dev.ndmf; using UnityEditor; using UnityEditor.Animations; using UnityEngine; +using UnityEngine.Profiling; using BuildContext = nadena.dev.ndmf.BuildContext; #if MA_VRCSDK3_AVATARS using VRC.SDK3.Avatars.Components; @@ -192,7 +193,11 @@ namespace nadena.dev.modular_avatar.animation var clipHolder = RegisterMotion(state.motion, state, processClip, _originalToHolder); state.motion = clipHolder.CurrentClip; - _clipCommitActions.Add(() => { state.motion = clipHolder.CurrentClip; }); + _clipCommitActions.Add(() => + { + state.motion = clipHolder.CurrentClip; + MaybeSaveClip(clipHolder.CurrentClip); + }); } internal void ForeachClip(Action processClip) @@ -368,6 +373,8 @@ namespace nadena.dev.modular_avatar.animation children[i].motion = curClip; dirty = true; } + + MaybeSaveClip(curClip); } if (dirty) @@ -379,5 +386,23 @@ namespace nadena.dev.modular_avatar.animation return treeHolder; } + + private void MaybeSaveClip(Motion curClip) + { + Profiler.BeginSample("MaybeSaveClip"); + if (curClip != null && !EditorUtility.IsPersistent(curClip) && EditorUtility.IsPersistent(_context.AssetContainer) && _context.AssetContainer != null) + { + try + { + AssetDatabase.AddObjectToAsset(curClip, _context.AssetContainer); + } + catch (Exception e) + { + Debug.LogException(e); + throw; + } + } + Profiler.EndSample(); + } } } \ No newline at end of file diff --git a/Editor/Animation/DeepClone.cs b/Editor/Animation/DeepClone.cs index 4667733a..e84bac6f 100644 --- a/Editor/Animation/DeepClone.cs +++ b/Editor/Animation/DeepClone.cs @@ -93,6 +93,11 @@ namespace nadena.dev.modular_avatar.animation { ObjectRegistry.RegisterReplacedObject(original, obj); } + + if (_isSaved && !EditorUtility.IsPersistent(obj)) + { + AssetDatabase.AddObjectToAsset(obj, _combined); + } return (T)obj; } From 5090d45cfe7269e458dabdd959cab3cdb5005106 Mon Sep 17 00:00:00 2001 From: bd_ Date: Fri, 20 Sep 2024 20:46:35 -0700 Subject: [PATCH 20/85] prof: add some profiling annotations (#1183) --- Editor/Animation/AnimationDatabase.cs | 7 +++++++ Editor/Animation/PathMappings.cs | 14 +++++++++++++- 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/Editor/Animation/AnimationDatabase.cs b/Editor/Animation/AnimationDatabase.cs index f9ef2335..bf788923 100644 --- a/Editor/Animation/AnimationDatabase.cs +++ b/Editor/Animation/AnimationDatabase.cs @@ -98,11 +98,13 @@ namespace nadena.dev.modular_avatar.animation internal void Commit() { + Profiler.BeginSample("AnimationDatabase.Commit"); foreach (var clip in _clips) { if (clip.IsProxyAnimation) clip.CurrentClip = clip.OriginalClip; } + Profiler.BeginSample("UpdateClipProperties"); foreach (var clip in _clips) { // Changing the "high quality curve" setting can result in behavior changes (but can happen accidentally @@ -122,11 +124,16 @@ namespace nadena.dev.modular_avatar.animation } } } + Profiler.EndSample(); + Profiler.BeginSample("ClipCommitActions"); foreach (var action in _clipCommitActions) { action(); } + Profiler.EndSample(); + + Profiler.EndSample(); } internal void OnActivate(BuildContext context) diff --git a/Editor/Animation/PathMappings.cs b/Editor/Animation/PathMappings.cs index bbd6648b..9546a063 100644 --- a/Editor/Animation/PathMappings.cs +++ b/Editor/Animation/PathMappings.cs @@ -8,6 +8,7 @@ using nadena.dev.ndmf.util; using UnityEditor; using UnityEditor.Animations; using UnityEngine; +using UnityEngine.Profiling; #if MA_VRCSDK3_AVATARS_3_5_2_OR_NEWER #endif @@ -337,8 +338,10 @@ namespace nadena.dev.modular_avatar.animation internal void OnDeactivate(BuildContext context) { + Profiler.BeginSample("PathMappings.OnDeactivate"); Dictionary clipCache = new Dictionary(); - + + Profiler.BeginSample("ApplyMappingsToClip"); _animationDatabase.ForeachClip(holder => { if (holder.CurrentClip is AnimationClip clip) @@ -346,23 +349,29 @@ namespace nadena.dev.modular_avatar.animation holder.CurrentClip = ApplyMappingsToClip(clip, clipCache); } }); + Profiler.EndSample(); #if MA_VRCSDK3_AVATARS_3_5_2_OR_NEWER + Profiler.BeginSample("MapPlayAudio"); _animationDatabase.ForeachPlayAudio(playAudio => { if (playAudio == null) return; playAudio.SourcePath = MapPath(playAudio.SourcePath, true); }); + Profiler.EndSample(); #endif + Profiler.BeginSample("InvokeIOnCommitObjectRenamesCallbacks"); foreach (var listener in context.AvatarRootObject.GetComponentsInChildren()) { listener.OnCommitObjectRenames(context, this); } + Profiler.EndSample(); var layers = context.AvatarDescriptor.baseAnimationLayers .Concat(context.AvatarDescriptor.specialAnimationLayers); + Profiler.BeginSample("ApplyMappingsToAvatarMasks"); foreach (var layer in layers) { ApplyMappingsToAvatarMask(layer.mask); @@ -373,6 +382,9 @@ namespace nadena.dev.modular_avatar.animation foreach (var acLayer in ac.layers) ApplyMappingsToAvatarMask(acLayer.avatarMask); } + Profiler.EndSample(); + + Profiler.EndSample(); } public GameObject PathToObject(string path) From 9dfa0dae23d9d4aa6e80e9c9d691e363dc297fdc Mon Sep 17 00:00:00 2001 From: nekobako Date: Mon, 23 Sep 2024 05:42:31 +0900 Subject: [PATCH 21/85] fix: remove unnecessory exit transitions for reactive components (#1161) --- .../AnimationGeneration/ReactiveObjectPass.cs | 40 +++++++++---------- 1 file changed, 19 insertions(+), 21 deletions(-) diff --git a/Editor/ReactiveObjects/AnimationGeneration/ReactiveObjectPass.cs b/Editor/ReactiveObjects/AnimationGeneration/ReactiveObjectPass.cs index ed4fd727..b3e49145 100644 --- a/Editor/ReactiveObjects/AnimationGeneration/ReactiveObjectPass.cs +++ b/Editor/ReactiveObjects/AnimationGeneration/ReactiveObjectPass.cs @@ -295,7 +295,8 @@ namespace nadena.dev.modular_avatar.core.editor var transitionBuffer = new List<(AnimatorState, List)>(); var entryTransitions = new List(); - transitionBuffer.Add((initialState, new List())); + var initialStateTransitionList = new List(); + transitionBuffer.Add((initialState, initialStateTransitionList)); foreach (var group in info.actionGroups.Skip(lastConstant)) { @@ -315,33 +316,30 @@ namespace nadena.dev.modular_avatar.core.editor var conditions = GetTransitionConditions(asc, group); - foreach (var (st, transitions) in transitionBuffer) + if (!group.Inverted) { - if (!group.Inverted) + var transition = new AnimatorStateTransition { - var transition = new AnimatorStateTransition + isExit = true, + hasExitTime = false, + duration = 0, + hasFixedDuration = true, + conditions = (AnimatorCondition[])conditions.Clone() + }; + initialStateTransitionList.Add(transition); + } + else + { + foreach (var cond in conditions) + { + initialStateTransitionList.Add(new AnimatorStateTransition { isExit = true, hasExitTime = false, duration = 0, hasFixedDuration = true, - conditions = (AnimatorCondition[])conditions.Clone() - }; - transitions.Add(transition); - } - else - { - foreach (var cond in conditions) - { - transitions.Add(new AnimatorStateTransition - { - isExit = true, - hasExitTime = false, - duration = 0, - hasFixedDuration = true, - conditions = new[] { InvertCondition(cond) } - }); - } + conditions = new[] { InvertCondition(cond) } + }); } } From 54288ebd445f186a8753e6d73042f8a3bc302db5 Mon Sep 17 00:00:00 2001 From: lilxyzw <74490257+lilxyzw@users.noreply.github.com> Date: Mon, 23 Sep 2024 06:35:05 +0900 Subject: [PATCH 22/85] fix: MenuInstaller does not support cloning (#1173) (#1184) * fix: MenuInstaller does not support cloning (#1173) * fix: error when root menu is specified --- Editor/Menu/VirtualMenu.cs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/Editor/Menu/VirtualMenu.cs b/Editor/Menu/VirtualMenu.cs index 24b5971f..c50ee654 100644 --- a/Editor/Menu/VirtualMenu.cs +++ b/Editor/Menu/VirtualMenu.cs @@ -7,6 +7,7 @@ using System.Linq; using JetBrains.Annotations; using nadena.dev.modular_avatar.core.menu; using nadena.dev.modular_avatar.editor.ErrorReporting; +using nadena.dev.ndmf; using UnityEngine; using VRC.SDK3.Avatars.Components; using VRC.SDK3.Avatars.ScriptableObjects; @@ -102,7 +103,7 @@ namespace nadena.dev.modular_avatar.core.editor.menu PushControl(control); } - if (_menuToInstallerMap.TryGetValue(expMenu, out var installers)) + if (_menuToInstallerMap.TryGetValue(ObjectRegistry.GetReference(expMenu), out var installers)) { foreach (var installer in installers) { @@ -311,7 +312,7 @@ namespace nadena.dev.modular_avatar.core.editor.menu // initial validation if (installer.menuToAppend == null && installer.GetComponent() == null) return; - var target = installer.installTargetMenu ? (object) installer.installTargetMenu : RootMenuKey; + var target = installer.installTargetMenu ? (object) ObjectRegistry.GetReference(installer.installTargetMenu) : RootMenuKey; if (!_targetMenuToInstaller.TryGetValue(target, out var targets)) { targets = new List(); @@ -366,7 +367,7 @@ namespace nadena.dev.modular_avatar.core.editor.menu } // Some menu installers may be bound to the root menu _asset_ directly. - if (menuToInstallerFiltered.TryGetValue(menu, out var installers)) + if (menuToInstallerFiltered.TryGetValue(ObjectRegistry.GetReference(menu), out var installers)) { foreach (var installer in installers) { From a5e716cb3e40c7b83b358b1b6342db6e77b24ec2 Mon Sep 17 00:00:00 2001 From: bd_ Date: Sun, 22 Sep 2024 18:12:26 -0700 Subject: [PATCH 23/85] fix: incorrect auto parameter assignment when a non-auto item is set to 0 (#1189) --- .../ReactiveObjects/ParameterAssignerPass.cs | 26 ++++++++++++++----- .../AutoValueAssignmentTests.cs | 9 +++++-- 2 files changed, 27 insertions(+), 8 deletions(-) diff --git a/Editor/ReactiveObjects/ParameterAssignerPass.cs b/Editor/ReactiveObjects/ParameterAssignerPass.cs index eb0e512f..9b891f84 100644 --- a/Editor/ReactiveObjects/ParameterAssignerPass.cs +++ b/Editor/ReactiveObjects/ParameterAssignerPass.cs @@ -87,14 +87,15 @@ namespace nadena.dev.modular_avatar.core.editor foreach (var (paramName, list) in _mamiByParam) { // Assign automatic values first - float defaultValue; + int? defaultValue = null; if (declaredParams.TryGetValue(paramName, out var p)) { - defaultValue = p.defaultValue; + defaultValue = (int) p.defaultValue; } else { - defaultValue = list.FirstOrDefault(m => m.isDefault && !m.automaticValue)?.Control?.value ?? 0; + var floatDefault = list.FirstOrDefault(m => m.isDefault && !m.automaticValue)?.Control?.value; + if (floatDefault.HasValue) defaultValue = (int) floatDefault.Value; if (list.Count == 1 && list[0].isDefault && list[0].automaticValue) // If we have only a single entry, it's probably an on-off toggle, so we'll implicitly let 1 @@ -103,7 +104,7 @@ namespace nadena.dev.modular_avatar.core.editor } HashSet usedValues = new(); - usedValues.Add((int)defaultValue); + if (defaultValue.HasValue) usedValues.Add(defaultValue.Value); foreach (var item in list) { @@ -113,6 +114,19 @@ namespace nadena.dev.modular_avatar.core.editor } } + if (!defaultValue.HasValue) + { + for (int i = 0; i < 256; i++) + { + if (!usedValues.Contains(i)) + { + defaultValue = i; + usedValues.Add(i); + break; + } + } + } + var nextValue = 1; var valueType = VRCExpressionParameters.ValueType.Bool; @@ -125,7 +139,7 @@ namespace nadena.dev.modular_avatar.core.editor { if (mami.isDefault) { - mami.Control.value = defaultValue; + mami.Control.value = defaultValue.GetValueOrDefault(); } else { @@ -153,7 +167,7 @@ namespace nadena.dev.modular_avatar.core.editor name = paramName, valueType = valueType, saved = isSaved, - defaultValue = defaultValue, + defaultValue = defaultValue.GetValueOrDefault(), networkSynced = isSynced }; newParameters[paramName] = newParam; diff --git a/UnitTests~/ReactiveComponent/ParameterAssignment/AutoValueAssignmentTests.cs b/UnitTests~/ReactiveComponent/ParameterAssignment/AutoValueAssignmentTests.cs index ce0bd961..d7eb71f5 100644 --- a/UnitTests~/ReactiveComponent/ParameterAssignment/AutoValueAssignmentTests.cs +++ b/UnitTests~/ReactiveComponent/ParameterAssignment/AutoValueAssignmentTests.cs @@ -48,13 +48,18 @@ namespace UnitTests.ReactiveComponent.ParameterAssignment { TestAssignments(new[] { (false, 2.0f), (true, 0.0f), (true, 0.0f) }, new[] { 2.0f, 1.0f, 3.0f }, null); TestAssignments(new[] { (false, 2.7f), (true, 0.0f), (true, 0.0f) }, new[] { 2.7f, 1.0f, 3.0f }, null); + TestAssignments(new[] { (true, 1.0f), (false, 0.0f) }, new[] { 2.0f, 0.0f }, null, overrideExpectedDefaultValue: 1.0f); + TestAssignments(new[] { (true, 1.0f), (false, 0.0f) }, new[] { 1.0f, 0.0f }, 0); + TestAssignments(new[] { (true, 1.0f), (false, 0.0f) }, new[] { 1.0f, 0.0f }, 1); + } void TestAssignments( (bool, float)[] assignments, float[] expectedAssignments, int? defaultIndex = null, - Action> customize = null + Action> customize = null, + float? overrideExpectedDefaultValue = null ) { var root = CreateRoot("root"); @@ -103,7 +108,7 @@ namespace UnitTests.ReactiveComponent.ParameterAssignment Assert.AreEqual(expected, mami.Control.value); } - var expectedDefaultValue = defaultIndex.HasValue ? expectedAssignments[defaultIndex.Value] : 0; + var expectedDefaultValue = overrideExpectedDefaultValue ?? (defaultIndex.HasValue ? expectedAssignments[defaultIndex.Value] : 0); Assert.AreEqual(expectedDefaultValue, avDesc.expressionParameters.parameters.Single().defaultValue); } } From 2d8f5d764e41216cca433dea00ba4cd8b690e034 Mon Sep 17 00:00:00 2001 From: nekobako Date: Mon, 23 Sep 2024 10:18:27 +0900 Subject: [PATCH 24/85] =?UTF-8?q?fix:=20resolve=20parameter=20type=20confl?= =?UTF-8?q?icts=20for=20menu=20items=20in=20params=20usage=20=E2=80=A6=20(?= =?UTF-8?q?#1174)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fix: resolve parameter type conflicts for menu items in params usage window * Revert "fix: resolve parameter type conflicts for menu items in params usage window" This reverts commit 4c6b41de4c92da5828219657b2927c90685e275a. * fix: expand conflicting parameter types for menu item in introspection * chore: update NDMF dependency --------- Co-authored-by: bd_ --- .github/ProjectRoot/vpm-manifest-2022.json | 2 +- Editor/ParamsUsage/MAParametersIntrospection.cs | 1 + package.json | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/.github/ProjectRoot/vpm-manifest-2022.json b/.github/ProjectRoot/vpm-manifest-2022.json index bbb71a9e..cdf4ad72 100644 --- a/.github/ProjectRoot/vpm-manifest-2022.json +++ b/.github/ProjectRoot/vpm-manifest-2022.json @@ -19,7 +19,7 @@ "dependencies": {} }, "nadena.dev.ndmf": { - "version": "1.5.0-rc.7" + "version": "1.5.0-rc.8" } } } \ No newline at end of file diff --git a/Editor/ParamsUsage/MAParametersIntrospection.cs b/Editor/ParamsUsage/MAParametersIntrospection.cs index 6ff9f720..1924c2d0 100644 --- a/Editor/ParamsUsage/MAParametersIntrospection.cs +++ b/Editor/ParamsUsage/MAParametersIntrospection.cs @@ -39,6 +39,7 @@ namespace nadena.dev.modular_avatar.core.editor ParameterNamespace.Animator, _component, PluginDefinition.Instance, _component.AnimatorControllerParameterType) { + ExpandTypeOnConflict = true, WantSynced = _component.isSynced, IsHidden = hidden, DefaultValue = _component.isDefault ? _component.Control.value : null diff --git a/package.json b/package.json index e411fa3a..ccbbc798 100644 --- a/package.json +++ b/package.json @@ -16,6 +16,6 @@ }, "vpmDependencies": { "com.vrchat.avatars": ">=3.7.0", - "nadena.dev.ndmf": ">=1.5.0-rc.7 <2.0.0-a" + "nadena.dev.ndmf": ">=1.5.0-rc.8 <2.0.0-a" } } From fd3de6e6805c9c4deedeb2d709737112fc316827 Mon Sep 17 00:00:00 2001 From: bd_ Date: Sun, 22 Sep 2024 18:18:52 -0700 Subject: [PATCH 25/85] 1.10.0-rc.7 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index ccbbc798..62189162 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "nadena.dev.modular-avatar", "displayName": "Modular Avatar", - "version": "1.10.0-rc.6", + "version": "1.10.0-rc.7", "unity": "2022.3", "description": "A suite of tools for assembling your avatar out of reusable components", "author": { From 3b86822547e410512bf37ac902fe131bb7977f6b Mon Sep 17 00:00:00 2001 From: Sayamame-beans <61457993+Sayamame-beans@users.noreply.github.com> Date: Tue, 24 Sep 2024 11:12:39 +0900 Subject: [PATCH 26/85] fix: Setup Outfit cause NRE when nothing selected (#1197) --- Editor/SetupOutfit.cs | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/Editor/SetupOutfit.cs b/Editor/SetupOutfit.cs index f6d28c53..6c263c89 100644 --- a/Editor/SetupOutfit.cs +++ b/Editor/SetupOutfit.cs @@ -386,6 +386,14 @@ namespace nadena.dev.modular_avatar.core.editor private static bool ValidateSetupOutfit(GameObject gameObj) { Object obj; + + if (gameObj == null) + { + errorHeader = S("setup_outfit.err.header.notarget"); + errorMessageGroups = new string[] { S("setup_outfit.err.no_selection") }; + return false; + } + errorHeader = S_f("setup_outfit.err.header", gameObj.name); var xform = gameObj.transform; @@ -542,4 +550,4 @@ namespace nadena.dev.modular_avatar.core.editor return avatarHips != null && outfitHips != null; } } -} \ No newline at end of file +} From 032e7a692e6a69ed0fbde984e2c46d05095d7239 Mon Sep 17 00:00:00 2001 From: Sayamame-beans <61457993+Sayamame-beans@users.noreply.github.com> Date: Tue, 24 Sep 2024 11:13:29 +0900 Subject: [PATCH 27/85] chore: fpvisible.NotUnderHead is now Warning, not Error (#1194) --- Editor/Inspector/FirstPersonVisibleEditor.cs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Editor/Inspector/FirstPersonVisibleEditor.cs b/Editor/Inspector/FirstPersonVisibleEditor.cs index 81b51ad2..91052b28 100644 --- a/Editor/Inspector/FirstPersonVisibleEditor.cs +++ b/Editor/Inspector/FirstPersonVisibleEditor.cs @@ -35,6 +35,9 @@ namespace nadena.dev.modular_avatar.core.editor case VisibleHeadAccessoryValidation.ReadyStatus.ParentMarked: EditorGUILayout.HelpBox(Localization.S("fpvisible.normal"), MessageType.Info); break; + case VisibleHeadAccessoryValidation.ReadyStatus.NotUnderHead: + EditorGUILayout.HelpBox(Localization.S("fpvisible.NotUnderHead"), MessageType.Warning); + break; default: { var label = "fpvisible." + status; @@ -49,4 +52,4 @@ namespace nadena.dev.modular_avatar.core.editor Localization.ShowLanguageUI(); } } -} \ No newline at end of file +} From 8e49df703f79433177976c95aa6d21350b07f6c9 Mon Sep 17 00:00:00 2001 From: Sayamame-beans <61457993+Sayamame-beans@users.noreply.github.com> Date: Tue, 24 Sep 2024 11:14:26 +0900 Subject: [PATCH 28/85] fix: BoneProxy target couldn't be empty after assigned (#1192) --- Editor/Inspector/BoneProxyEditor.cs | 4 ++-- Runtime/ModularAvatarBoneProxy.cs | 9 ++++++++- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/Editor/Inspector/BoneProxyEditor.cs b/Editor/Inspector/BoneProxyEditor.cs index f9d3ec6d..22566984 100644 --- a/Editor/Inspector/BoneProxyEditor.cs +++ b/Editor/Inspector/BoneProxyEditor.cs @@ -95,7 +95,7 @@ namespace nadena.dev.modular_avatar.core.editor var t = (ModularAvatarBoneProxy) targets[i]; Undo.RecordObjects(targets, "Set targets"); var xform = ((TempObjRef) objRefs[i]).target; - if (RuntimeUtil.FindAvatarTransformInParents(xform)?.gameObject != parentAvatar) continue; + if (xform != null && RuntimeUtil.FindAvatarTransformInParents(xform)?.gameObject != parentAvatar) continue; t.target = xform; } } @@ -159,4 +159,4 @@ namespace nadena.dev.modular_avatar.core.editor } } } -} \ No newline at end of file +} diff --git a/Runtime/ModularAvatarBoneProxy.cs b/Runtime/ModularAvatarBoneProxy.cs index 35f0cd7d..38957bdc 100644 --- a/Runtime/ModularAvatarBoneProxy.cs +++ b/Runtime/ModularAvatarBoneProxy.cs @@ -205,6 +205,13 @@ namespace nadena.dev.modular_avatar.core Transform iter = newTarget; + if (newTarget == null) + { + boneReference = HumanBodyBones.LastBone; + subPath = null; + return; + } + if (newTarget == avatarTransform) { boneReference = HumanBodyBones.LastBone; @@ -230,4 +237,4 @@ namespace nadena.dev.modular_avatar.core _targetCache = newTarget; } } -} \ No newline at end of file +} From bf47a4c544368db308b354e0d369a397a8333494 Mon Sep 17 00:00:00 2001 From: bd_ Date: Mon, 23 Sep 2024 20:18:04 -0700 Subject: [PATCH 29/85] fix: reactive components break WD ON avatars (#1202) Closes: #1199 --- Editor/MergeAnimatorProcessor.cs | 4 +++- .../AnimationGeneration/ReactiveObjectPass.cs | 23 +++++++++++++++---- 2 files changed, 21 insertions(+), 6 deletions(-) diff --git a/Editor/MergeAnimatorProcessor.cs b/Editor/MergeAnimatorProcessor.cs index 223cfde7..50efd939 100644 --- a/Editor/MergeAnimatorProcessor.cs +++ b/Editor/MergeAnimatorProcessor.cs @@ -236,8 +236,10 @@ namespace nadena.dev.modular_avatar.core.editor } } - private bool? ProbeWriteDefaults(AnimatorController controller) + internal static bool? ProbeWriteDefaults(AnimatorController controller) { + if (controller == null) return null; + bool hasWDOn = false; bool hasWDOff = false; diff --git a/Editor/ReactiveObjects/AnimationGeneration/ReactiveObjectPass.cs b/Editor/ReactiveObjects/AnimationGeneration/ReactiveObjectPass.cs index b3e49145..793fba66 100644 --- a/Editor/ReactiveObjects/AnimationGeneration/ReactiveObjectPass.cs +++ b/Editor/ReactiveObjects/AnimationGeneration/ReactiveObjectPass.cs @@ -25,6 +25,7 @@ namespace nadena.dev.modular_avatar.core.editor private HashSet activeProps = new(); private AnimationClip _initialStateClip; + private bool _writeDefaults; public ReactiveObjectPass(ndmf.BuildContext context) { @@ -33,6 +34,10 @@ namespace nadena.dev.modular_avatar.core.editor internal void Execute() { + // Having a WD OFF layer after WD ON layers can break WD. We match the behavior of the existing states, + // and if mixed, use WD ON to maximize compatibility. + _writeDefaults = MergeAnimatorProcessor.ProbeWriteDefaults(FindFxController().animatorController as AnimatorController) ?? true; + var analysis = new ReactiveObjectAnalyzer(context).Analyze(context.AvatarRootObject); var shapes = analysis.Shapes; @@ -277,7 +282,7 @@ namespace nadena.dev.modular_avatar.core.editor var initial = new AnimationClip(); var initialState = new AnimatorState(); initialState.motion = initial; - initialState.writeDefaultValues = false; + initialState.writeDefaultValues = _writeDefaults; initialState.name = ""; asm.defaultState = initialState; @@ -349,7 +354,7 @@ namespace nadena.dev.modular_avatar.core.editor state.name = group.ControllingConditions[0].DebugName.Replace(".", "_"); state.motion = clip; - state.writeDefaultValues = false; + state.writeDefaultValues = _writeDefaults; states.Add(new ChildAnimatorState { position = new Vector3(x, y), @@ -525,13 +530,13 @@ namespace nadena.dev.modular_avatar.core.editor private void ApplyController(AnimatorStateMachine asm, string layerName) { - var fx = context.AvatarDescriptor.baseAnimationLayers - .FirstOrDefault(l => l.type == VRCAvatarDescriptor.AnimLayerType.FX); + var fx = FindFxController(); + if (fx.animatorController == null) { throw new InvalidOperationException("No FX layer found"); } - + if (!context.IsTemporaryAsset(fx.animatorController)) { throw new InvalidOperationException("FX layer is not a temporary asset"); @@ -567,5 +572,13 @@ namespace nadena.dev.modular_avatar.core.editor } ).ToArray(); } + + private VRCAvatarDescriptor.CustomAnimLayer FindFxController() + { + var fx = context.AvatarDescriptor.baseAnimationLayers + .FirstOrDefault(l => l.type == VRCAvatarDescriptor.AnimLayerType.FX); + + return fx; + } } } From 51fedbd9b01aebb3700f8ced70652985d4b770f2 Mon Sep 17 00:00:00 2001 From: bd_ Date: Mon, 23 Sep 2024 20:27:56 -0700 Subject: [PATCH 30/85] fix: ROSimulator registers multiple event handlers for state override buttons (#1203) --- Editor/ReactiveObjects/Simulator/ROSimulator.cs | 8 ++++---- .../ReactiveObjects/Simulator/StateOverrideController.cs | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Editor/ReactiveObjects/Simulator/ROSimulator.cs b/Editor/ReactiveObjects/Simulator/ROSimulator.cs index d4188fbc..e34a7a40 100644 --- a/Editor/ReactiveObjects/Simulator/ROSimulator.cs +++ b/Editor/ReactiveObjects/Simulator/ROSimulator.cs @@ -286,7 +286,7 @@ namespace nadena.dev.modular_avatar.core.editor.Simulator // these properties in a closure _menuItemOverrideProperty = prop; _menuItemOverrideTarget = mami; - soc.OnStateOverrideChanged += MenuItemOverrideChanged; + soc.OnStateOverrideChanged = MenuItemOverrideChanged; } private void MenuItemOverrideChanged(bool? obj) @@ -319,7 +319,7 @@ namespace nadena.dev.modular_avatar.core.editor.Simulator _propertyOverrideProperty = property; _propertyOverrideTargetValue = targetValue; - soc.OnStateOverrideChanged += OnParameterOverrideChanged; + soc.OnStateOverrideChanged = OnParameterOverrideChanged; } private void OnParameterOverrideChanged(bool? state) @@ -539,11 +539,11 @@ namespace nadena.dev.modular_avatar.core.editor.Simulator soc.SetWithoutNotify(menuOverride); } - soc.OnStateOverrideChanged += value => { UpdateMenuItemOverride(prop, mami, value); }; + soc.OnStateOverrideChanged = value => { UpdateMenuItemOverride(prop, mami, value); }; } else { - soc.OnStateOverrideChanged += value => UpdatePropertyOverride(prop, value, targetValue); + soc.OnStateOverrideChanged = value => UpdatePropertyOverride(prop, value, targetValue); } var active = condition.InitiallyActive; diff --git a/Editor/ReactiveObjects/Simulator/StateOverrideController.cs b/Editor/ReactiveObjects/Simulator/StateOverrideController.cs index 1e05122f..74d9c45e 100644 --- a/Editor/ReactiveObjects/Simulator/StateOverrideController.cs +++ b/Editor/ReactiveObjects/Simulator/StateOverrideController.cs @@ -16,7 +16,7 @@ namespace nadena.dev.modular_avatar.core.editor private static StyleSheet uss; private Button btn_disable, btn_default, btn_enable; - public event System.Action OnStateOverrideChanged; + public System.Action OnStateOverrideChanged; public StateOverrideController() { From 2826c27d6387a75ec64a996c307de5635d50e325 Mon Sep 17 00:00:00 2001 From: lilxyzw <74490257+lilxyzw@users.noreply.github.com> Date: Wed, 25 Sep 2024 10:11:39 +0900 Subject: [PATCH 31/85] fix: cloned AnimatorController is not registered in ObjectRegistry #1205 (#1206) --- Editor/Animation/AnimationUtil.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Editor/Animation/AnimationUtil.cs b/Editor/Animation/AnimationUtil.cs index 61e09659..aa026548 100644 --- a/Editor/Animation/AnimationUtil.cs +++ b/Editor/Animation/AnimationUtil.cs @@ -42,7 +42,9 @@ namespace nadena.dev.modular_avatar.animation throw new Exception("Unknown RuntimeAnimatorContoller type " + controller.GetType()); } - return merger.Finish(); + var clone = merger.Finish(); + ObjectRegistry.RegisterReplacedObject(controller, clone); + return clone; } internal static void CloneAllControllers(BuildContext context) From d82c41c3904d25296afcaea221b0a732642fefed Mon Sep 17 00:00:00 2001 From: nadena-dev-ci Date: Wed, 25 Sep 2024 10:56:57 +0900 Subject: [PATCH 32/85] New translations en-us.json (Japanese) (#1204) --- Editor/Localization/ja-JP.json | 178 ++++++++++++++++----------------- 1 file changed, 89 insertions(+), 89 deletions(-) diff --git a/Editor/Localization/ja-JP.json b/Editor/Localization/ja-JP.json index 7c011df0..776db759 100644 --- a/Editor/Localization/ja-JP.json +++ b/Editor/Localization/ja-JP.json @@ -9,7 +9,7 @@ "menuinstall.showcontents": "メニュー内容を表示", "menuinstall.showcontents.notselected": "メニューが選択されていません", "menuinstall.devoptions": "プレハブ開発者向け設定", - "menuinstall.menu_icon_too_large": "メニューに設定されているアイコンが256ピクセルより大きすぎます。", + "menuinstall.menu_icon_too_large": "メニューに設定されているアイコンが256x256より大きいです。", "menuinstall.menu_icon_uncompressed": "メニューに設定されているアイコンが圧縮設定されていません。", "menuinstall.srcmenu": "インストールされるメニュー", "params.syncmode.NotSynced": "Animatorのみ", @@ -31,32 +31,32 @@ "merge_parameter.ui.name": "パラメーター名", "merge_parameter.ui.prefix": "PhysBone 接頭辞", "merge_parameter.ui.remapTo": "名前を変更", - "merge_parameter.ui.remapTo.tooltip": "ここに新しい名前を入れることで、このパラメーターの名前を変更できます。これで名前かぶりを回避したり、あるいはあえて複数のギミックを連動できます。", + "merge_parameter.ui.remapTo.tooltip": "ここに新しい名前を入れることで、このパラメーターの名前を変更できます。これで名前かぶりを回避したり、複数のギミックを連動させたりすることができます。", "merge_parameter.ui.remapTo.automatic": "(自動的に設定)", "merge_parameter.ui.defaultValue": "初期値", - "merge_parameter.ui.defaultValue.tooltip": "アバターがリセット、または最初に着た時にこの値が採用されます。", + "merge_parameter.ui.defaultValue.tooltip": "アバターをリセットした時、または最初に着た時にこの値が採用されます。", "merge_parameter.ui.saved": "保存する", - "merge_parameter.ui.saved.tooltip": "保存されたパラメーターは、アバター変更やワールド移動で保持されます", + "merge_parameter.ui.saved.tooltip": "保存されたパラメーターは、アバター変更やワールド移動をしても保持されます", "merge_parameter.ui.internalParameter": "自動リネーム", "merge_parameter.ui.internalParameter.tooltip": "有効にすると、名前かぶりを回避するために自動的に名前を変更します", "merge_parameter.ui.isPrefix": "PhysBone 接頭辞", "merge_parameter.ui.syncType": "パラメーター型", "merge_parameter.ui.synced": "同期する", - "merge_parameter.ui.synced.tooltip": "有効にすると、ネットワーク上同期されます", + "merge_parameter.ui.synced.tooltip": "有効にすると、このパラメーターは同期されます", "merge_parameter.ui.unregistered_foldout": "未登録パラメーター", "merge_parameter.ui.add_button": "追加", "merge_parameter.ui.details": "パラメーターの詳細設定", - "merge_parameter.ui.overrideAnimatorDefaults": "アニメーターの初期値を設定", + "merge_parameter.ui.overrideAnimatorDefaults": "アニメーターでの初期値を設定", "merge_armature.merge_target": "統合先", "merge_armature.merge_target.tooltip": "このオブジェクトを統合先のアーマチュアに統合します", "merge_armature.prefix": "接頭辞", - "merge_armature.prefix.tooltip": "マージするボーンに付いている接頭辞", + "merge_armature.prefix.tooltip": "統合されるボーンに付いている接頭辞", "merge_armature.suffix": "接尾辞", - "merge_armature.suffix.tooltip": "マージするボーンに付いている接尾辞", + "merge_armature.suffix.tooltip": "統合されるボーンに付いている接尾辞", "merge_armature.locked": "位置を固定", - "merge_armature.locked.tooltip": "このオブジェクトのボーンを統合先のボーンに常に相互的に位置を合わせる。アニメーション制作向け", + "merge_armature.locked.tooltip": "このオブジェクトのボーンと統合先のボーンの位置を常に合わせます。アニメーション作成時に便利です。", "merge_armature.adjust_names": "ボーン名を統合先に合わせる", - "merge_armature.adjust_names.tooltip": "統合先のボーン名に合わせて、衣装のボーン名を合わせて変更します。統合先アバターに非対応の衣装導入向け機能です。", + "merge_armature.adjust_names.tooltip": "衣装のボーン名をアバターのボーン名に合わせて変更します。アバターに非対応の衣装を導入する時に便利です。", "merge_armature.mangle_names": "名前かぶりを回避", "merge_armature.mangle_names.tooltip": "ほかのアセットとの名前かぶりを裂けるため、新規ボーンの名前を自動で変更する", "path_mode.Relative": "相対的(このオブジェクトからのパスを使用)", @@ -66,12 +66,12 @@ "merge_animator.delete_attached_animator": "付属アニメーターを削除", "merge_animator.delete_attached_animator.tooltip": "統合後、このオブジェクトについているアニメーターを削除します", "merge_animator.path_mode": "パスモード", - "merge_animator.path_mode.tooltip": "アニメーション内のパスを解釈するモード。相対的にすると、このオブジェクトについているアニメーターでアニメーション編集できます", + "merge_animator.path_mode.tooltip": "アニメーション内のパスを解釈するモード。相対的にすると、このオブジェクトにつけたアニメーターでアニメーションを編集することができます。", "merge_animator.match_avatar_write_defaults": "アバターのWrite Defaults設定に合わせる", "merge_animator.match_avatar_write_defaults.tooltip": "アバターの該当アニメーターのWrite Defaults設定に合わせます。アバター側の設定が矛盾する場合は、統合されるアニメーターのWD値がそのまま採用されます。", "merge_animator.relative_path_root": "相対的パスのルート", "merge_animator.relative_path_root.tooltip": "相対的パスはこのオブジェクトを基準に解釈されます。指定がない場合は、このコンポーネントがついているオブジェクトを基準とします。", - "merge_animator.layer_priority": "レイヤー優先度", + "merge_animator.layer_priority": "レイヤー統合優先度", "merge_animator.layer_priority.tooltip": "アニメーターにレイヤーが統合される順番を制御します。低い値から高い値の順に統合されます。マイナスの場合は元々のAvatar Descriptorについているコントローラーより前に統合され、ゼロ以上の場合はそのあとに統合されます。", "merge_armature.lockmode": "位置追従モード", "merge_armature.lockmode.not_locked.title": "追従なし", @@ -81,28 +81,28 @@ "merge_armature.lockmode.bidirectional.title": "アバター <=====> オブジェクト (双方向)", "merge_armature.lockmode.bidirectional.body": "アバターと統合されるアーマチュアは常に同じ位置になります。元のアバターを操作するアニメーションを作る時に便利かもしれません。有効にするためには、統合されるアーマチュアの位置を統合先と同じにしておく必要があります。", "merge_armature.reset_pos": "位置を元アバターに合わせてリセット", - "merge_armature.reset_pos.info": "このコマンドは、衣装のボーンの位置をアバターのボーンの位置に合わせます。非対応衣装を導入するとき、アバウトに合わせるために便利です。", + "merge_armature.reset_pos.info": "衣装のボーンの位置をアバターのボーンの位置に合わせます。非対応衣装を導入する際、アバウトに位置を合わせるのに便利です。", "merge_armature.reset_pos.adjust_rotation": "回転も合わせる", "merge_armature.reset_pos.adjust_scale": "スケールも合わせる", "merge_armature.reset_pos.execute": "実行", "merge_armature.reset_pos.heuristic_scale": "衣装の全体的なスケールをアバターに合わせる", - "merge_armature.reset_pos.heuristic_scale.tooltip": "腕の長さを参考に、衣装全体のスケールをアバターに合わせます。非対応衣装を導入するときは推奨です。", + "merge_armature.reset_pos.heuristic_scale.tooltip": "腕の長さを参考に、衣装全体のスケールをアバターに合わせます。非対応衣装を導入する時にお勧めです。", "merge_blend_tree.blend_tree": "ブレンドツリー", "merge_blend_tree.path_mode": "パスモード", - "merge_blend_tree.path_mode.tooltip": "アニメーション内のパスを解釈するモード。相対的にすると、このオブジェクトについているアニメーターでアニメーション編集できます", + "merge_blend_tree.path_mode.tooltip": "アニメーション内のパスを解釈するモード。相対的にすると、このオブジェクトにつけたアニメーターでアニメーションを編集することができます。", "merge_blend_tree.relative_path_root": "相対的パスのルート", "merge_blend_tree.relative_path_root.tooltip": "相対的パスはこのオブジェクトを基準に解釈されます。指定がない場合は、このコンポーネントがついているオブジェクトを基準とします。", - "worldfixed.quest": "このコンポーネントはアンドロイドビルド非対応のため無効となっています。", + "worldfixed.quest": "このコンポーネントはアンドロイドビルドに非対応であるため、無効となっています。", "worldfixed.normal": "このオブジェクトはConstraint等でアバターに追従させない限りワールドに固定されます。", - "fpvisible.normal": "このオブジェクトは一人視点で表示されます。", - "fpvisible.NotUnderHead": "このコンポーネントはヘッドボーン外では効果がありません。", - "fpvisible.quest": "このコンポーネントはアンドロイドビルド非対応のため無効となっています。", - "fpvisible.InPhysBoneChain": "このオブジェクトはPhysBoneに制御されているため、一人視点で表示できません。PhysBoneの始点を指定してください。", + "fpvisible.normal": "このオブジェクトは一人称視点で表示されます。", + "fpvisible.NotUnderHead": "このコンポーネントはヘッドボーン以下にないオブジェクトには効果がありません。", + "fpvisible.quest": "このコンポーネントはアンドロイドビルドに非対応であるため、無効となっています。", + "fpvisible.InPhysBoneChain": "このオブジェクトはPhysBoneで制御されているため、一人称視点でうまく表示させることができません。PhysBoneの始点を指定してください。", "blendshape.mesh": "メッシュ", - "blendshape.source": "元メッシュのブレンドシェープ", - "blendshape.target": "このメッシュのブレンドシェープ", - "hint.not_in_avatar": "このコンポーネントが正しく動作するには、アバター内に配置する必要があります。", - "boneproxy.err.MovingTarget": "他のモジュラーアバターコンポーネントで移動されるオブジェクトを指定できません。", + "blendshape.source": "元メッシュのブレンドシェイプ", + "blendshape.target": "このメッシュのブレンドシェイプ", + "hint.not_in_avatar": "このコンポーネントを正しく動作させるには、アバター内に配置する必要があります。", + "boneproxy.err.MovingTarget": "他のモジュラーアバターコンポーネントで移動されるオブジェクトは指定できません。", "boneproxy.err.NotInAvatar": "アバター内のオブジェクトを指定してください。", "boneproxy.attachment": "配置モード", "boneproxy.attachment.AsChildAtRoot": "子として・ルートに配置", @@ -111,28 +111,28 @@ "boneproxy.attachment.AsChildKeepRotation": "子として・ワールド向きを維持", "mesh_settings.header_probe_anchor": "Anchor Override 設定", "mesh_settings.inherit_probe_anchor": "設定モード", - "mesh_settings.probe_anchor": "アンカーオーバーライド", - "mesh_settings.probe_anchor.tooltip": "このオブジェクトとその子のレンダラーのAnchorOverrideを設定します。", + "mesh_settings.probe_anchor": "Anchor Override", + "mesh_settings.probe_anchor.tooltip": "このオブジェクトとその子のレンダラーのAnchor Overrideを設定します。", "mesh_settings.header_bounds": "Bounds 設定", "mesh_settings.inherit_bounds": "設定モード", "mesh_settings.root_bone": "ルートボーン", - "mesh_settings.root_bone.tooltip": "このオブジェクトとその子のメッシュで設定されるルートボーン。メッシュのバウンズを計算するための参照点として使用されます。", - "mesh_settings.bounds": "バウンズ", + "mesh_settings.root_bone.tooltip": "このオブジェクトとその子のメッシュで設定されるルートボーン。メッシュのBoundsを計算する際の基準として使用されます。", + "mesh_settings.bounds": "Bounds", "mesh_settings.bounds.tooltip": "このオブジェクトとその子のメッシュで設定されるバウンズ。画面外のメッシュのレンダリングを省略するかどうかを決定するために使用されます。", "mesh_settings.inherit_mode.Inherit": "継承", "mesh_settings.inherit_mode.Set": "設定", "mesh_settings.inherit_mode.DontSet": "設定しない(メッシュ本体の設定のまま)", - "mesh_settings.inherit_mode.SetOrInherit": "親が指定されてる時は継承、または設定", + "mesh_settings.inherit_mode.SetOrInherit": "親で指定されている時は継承、それ以外では設定", "pb_blocker.help": "このオブジェクトは親のPhysBoneから影響を受けなくなります。", - "hint.bad_vrcsdk": "使用中のVRCSDKのバージョンとは互換性がありません。\n\nVRCSDKを更新してみてください。それでもだめでしたら、Modular Avatarにも最新版が出てないかチェックしてください。", + "hint.bad_vrcsdk": "使用中のVRCSDKのバージョンとは互換性がありません。\n\nVRCSDKを更新してみてください。それでも駄目な場合、Modular Avatarにも最新版が出ていないか確認してみてください。", "error.stack_trace": "スタックトレース(バグを報告する時は必ず添付してください!)", "error.merge_armature.circular_dependency": "[MA-0001] Merge Armatureに循環参照があります", - "error.merge_armature.circular_dependency:description": "Merge Armature コンポーネントは、自分自身、または自分の子をマージターゲットとして参照しています。", - "error.merge_armature.circular_dependency:hint": "Merge Armature は通常、ターゲットフィールドにアバター本体の Armature オブジェクトを指定する必要があります。衣装自体を指定しないでください。", - "error.merge_armature.physbone_on_humanoid_bone": "[MA-0002] ヒューマノイドボーンにPhysBoneコンポーネントを検出", - "error.merge_armature.physbone_on_humanoid_bone:hint": "一部のヒューマノイドボーンは、PhysBonesによって制御されています。 マージ対象の対応するヒューマノイドボーンとは位置が異なるため、適切にマージすることはできません。マージするにはヒューマノイドボーンのPhysBonesを取り除く必要があります。", + "error.merge_armature.circular_dependency:description": "Merge Armatureコンポーネントの統合先として、自分自身、または自分の子が参照されています。", + "error.merge_armature.circular_dependency:hint": "通常、Merge Armatureは統合先としてアバター本体のArmatureオブジェクトを指定する必要があります。衣装自体を指定しないように注意してください。", + "error.merge_armature.physbone_on_humanoid_bone": "[MA-0002] HumanoidボーンにPhysBoneコンポーネントがついています。", + "error.merge_armature.physbone_on_humanoid_bone:hint": "一部のHumanoidボーンがPhysBoneによって制御されています。対応する統合先のHumanoidボーンと位置が異なるため、適切に統合することができません。統合するにはHumanoidボーンについているPhysBoneを取り除く必要があります。", "error.merge_blend_tree.missing_tree": "[MA-0009] ブレンドツリーが指定されていません", - "error.merge_blend_tree.missing_tree:hint": "Merge Blend Treeが動作するには、どのブレンドツリーを統合するかを指定する必要があります。「ブレンドツリー」欄を設定してみてください。", + "error.merge_blend_tree.missing_tree:hint": "Merge Blend Treeが動作するには、どのブレンドツリーを統合するか指定する必要があります。「ブレンドツリー」欄を設定しているかご確認ください。", "error.internal_error": "[MA-9999] 内部エラーが発生しました:{0}\n以下のオブジェクトの処理中に発生しました:", "error.merge_animator.param_type_mismatch": "[MA-0003] パラメータの型が競合しています", "error.merge_animator.param_type_mismatch:description": "パラメータ {0} には複数の型が指定されています: {1} != {2}", @@ -142,37 +142,37 @@ "error.rename_params.type_conflict:description": "パラメータ {0} には複数の型が指定されています: {1} != {2}", "error.rename_params.default_value_conflict": "[MA-0007] 初期値の競合", "error.rename_params.default_value_conflict:description": "パラメータ {0} には複数の初期値が指定されています: {1} != {2}", - "error.rename_params.default_value_conflict:hint": "予測不可能な動作を避けるために、MAパラメータコンポーネントのデフォルト値フィールドはパラメーター名毎に一個のコンポーネント以外空白のままにしてください。 複数の値が存在する場合、Modular Avatarは階層順に指定された最初のデフォルト値を選択します。", - "error.replace_object.null_target": "[MA-0008] ターゲットが指定されていません", - "error.replace_object.null_target:hint": "Replace Object には置き換えるべきターゲットオブジェクトが必要です。設定してみてください。", - "validation.blendshape_sync.no_local_renderer": "[MA-1000] このオブジェクトにはSkinnedMeshRendererがありません。", - "validation.blendshape_sync.no_local_renderer:hint": "Blendshape Syncは同じGameObject上のSkinned Mesh Rendererに作用します。正しいオブジェクトに追加しましたか?", - "validation.blendshape_sync.no_local_mesh": "[MA-1001] このオブジェクトにはSkinnedMeshRendererがありますが、メッシュがありません。", + "error.rename_params.default_value_conflict:hint": "予測不可能な動作を避けるため、MA Parametersコンポーネントの初期値フィールドはパラメーター名毎に1つだけしか指定しないようにし、他のコンポーネントでは空白のままにしてください。複数の値が存在する場合、Modular Avatarは階層順で最初に指定された初期値を採用します。", + "error.replace_object.null_target": "[MA-0008] 置き換え先が指定されていません", + "error.replace_object.null_target:hint": "Replace Objectは置き換え先のオブジェクトを指定する必要があります。", + "validation.blendshape_sync.no_local_renderer": "[MA-1000] このオブジェクトにはSkinned Mesh Rendererがありません。", + "validation.blendshape_sync.no_local_renderer:hint": "Blendshape Syncは同じGameObject上のSkinned Mesh Rendererに作用します。コンポーネントが正しいオブジェクトに追加されているか確認してください。", + "validation.blendshape_sync.no_local_mesh": "[MA-1001] このオブジェクトにはSkinned Mesh Rendererがありますが、メッシュがありません。", "validation.blendshape_sync.no_local_mesh:hint": "このオブジェクトの Skinned Mesh Renderer の設定が壊れている可能性があります。 元のプレハブまたはFBXからオブジェクトを再作成してみてください。", - "validation.blendshape_sync.no_bindings": "[MA-1002] このBlendshapeSyncにはバインドが設定されていません。", + "validation.blendshape_sync.no_bindings": "[MA-1002] このBlendshape Syncにはバインドが設定されていません。", "validation.blendshape_sync.no_bindings:hint": "Blendshape Syncは、どのブレンドシェイプを同期するかを知る必要があります。追加するには、「+」ボタンをクリックしてください。", - "validation.blendshape_sync.missing_local_shape": "[MA-1003] 同期先のメッシュに該当するブレンドシェープ「{0}」がありません。", - "validation.blendshape_sync.missing_local_shape:description": "ローカルブレンドシェイプがありません: {0}", - "validation.blendshape_sync.missing_local_shape:hint": "ターゲットオブジェクトから値を受け取るように設定されたブレンドシェイプがありません。赤で示されているブレンドシェイプ名を変更してみてください。", - "validation.blendshape_sync.missing_target_shape": "[MA-1004] 同期先メッシュにブレンドシェープ「{0}」が見つかりません", - "validation.blendshape_sync.missing_target_shape:description": "ターゲットブレンドシェイプがありません: {0}", - "validation.blendshape_sync.missing_target_shape:hint": "ローカルオブジェクトに値を「送る」ように設定されたブレンドシェイプがありません。赤で示されているブレンドシェイプ名を変更してみてください。", - "validation.blendshape_sync.no_target": "[MA-1005] このBlendshapeSyncには同期元が設定されていないバインドがあります。", - "validation.blendshape_sync.no_target:hint": "どのオブジェクトからBlendshapeを同期するかを教える必要があります。メッシュを設定してみてください。", - "validation.blendshape_sync.missing_target_renderer": "[MA-1006] 同期元のオブジェクトにはSkinnedMeshRendererがありません。", - "validation.blendshape_sync.missing_target_renderer:hint": "Blendshape Syncは、対象オブジェクトのSkinned Mesh Rendererからブレンド形状の値を受け取ります。正しいオブジェクトに追加しましたか?", - "validation.blendshape_sync.missing_target_mesh": "[MA-1007] 同期元のオブジェクトにはSkinnedMeshRendererがありますが、メッシュがありません。", - "validation.blendshape_sync.missing_target_mesh:hint": "ターゲットオブジェクトの Skinned Mesh Renderer の設定が壊れている可能性があります。 元のプレハブまたはFBXからオブジェクトを再作成してみてください。", - "validation.bone_proxy.no_target": "[MA-1100] ターゲットオブジェクトが未設定、もしくは存在しません。", - "validation.bone_proxy.no_target:hint": "ボーンプロキシがどのオブジェクトに追尾するかを知る必要があります。追尾すべきオブジェクトをターゲットフィールドに設定してみてください。", + "validation.blendshape_sync.missing_local_shape": "[MA-1003] 同期先のメッシュにブレンドシェイプ「{0}」がありません。", + "validation.blendshape_sync.missing_local_shape:description": "ブレンドシェイプ「{0}」がありません。", + "validation.blendshape_sync.missing_local_shape:hint": "値を「受け取る」ように設定されたブレンドシェイプが同期先のメッシュに存在しません。赤で示されているブレンドシェイプ名を変更してみてください。", + "validation.blendshape_sync.missing_target_shape": "[MA-1004] 同期元のメッシュにブレンドシェイプ「{0}」がありません。", + "validation.blendshape_sync.missing_target_shape:description": "ブレンドシェイプ「{0}」がありません。", + "validation.blendshape_sync.missing_target_shape:hint": "値を「送る」ように設定されたブレンドシェイプが同期元のメッシュに存在しません。赤で示されているブレンドシェイプ名を変更してみてください。", + "validation.blendshape_sync.no_target": "[MA-1005] このBlendshape Syncには同期元が設定されていないバインドがあります。", + "validation.blendshape_sync.no_target:hint": "どのオブジェクトからBlendshapeを同期するか指定する必要があります。メッシュを設定してください。", + "validation.blendshape_sync.missing_target_renderer": "[MA-1006] 同期元のオブジェクトにSkinned Mesh Rendererがありません。", + "validation.blendshape_sync.missing_target_renderer:hint": "Blendshape Syncは、同期元のSkinned Mesh Rendererからブレンドシェイプの値を受け取ります。コンポーネントが正しいオブジェクトに追加されているか確認してください。", + "validation.blendshape_sync.missing_target_mesh": "[MA-1007] 同期元のオブジェクトにはSkinned Mesh Rendererがありますが、メッシュがありません。", + "validation.blendshape_sync.missing_target_mesh:hint": "同期元のオブジェクトの Skinned Mesh Renderer の設定が壊れている可能性があります。 元のプレハブまたはFBXからオブジェクトを再作成してみてください。", + "validation.bone_proxy.no_target": "[MA-1100] ターゲットオブジェクトが未設定であるか、存在しません。", + "validation.bone_proxy.no_target:hint": "Bone Proxyはどのオブジェクトに追従させるかを指定する必要があります。追従させたい対象のオブジェクトをターゲット欄に設定してみてください。", "validation.menu_installer.no_menu": "[MA-1200] インストールするメニューがありません。", "validation.menu_installer.no_menu:hint": "Menu Installer は、どのメニューをインストールするべきか設定する必要があります。 「Prefab開発者向けオプション」内の「インストールするメニュー」フィールドを設定するか、MA Menu Itemコンポーネントを追加してみてください。", - "validation.merge_animator.no_animator": "[MA-1300] Animator Controllerが設定されていません", - "validation.merge_animator.no_animator:hint": "Animatorをマージするには、どのアニメーターを統合するかを設定する必要があります。「統合されるアニメーター」を設定してみてください。", - "validation.merge_armature.no_target": "[MA-1400] 統合先が未設定、もしくは存在しません。", + "validation.merge_animator.no_animator": "[MA-1300] Animator Controllerが未設定であるか、存在しません。", + "validation.merge_animator.no_animator:hint": "どのアニメーターを統合するか設定する必要があります。「統合されるアニメーター」を設定してみてください。", + "validation.merge_armature.no_target": "[MA-1400] 統合先が未設定であるか、存在しません。", "validation.merge_armature.no_target:hint": "Merge Armatureはどこに統合するか設定する必要があります。「統合先」を設定してみてください。", - "validation.merge_armature.target_is_child": "[MA-1500] 統合先をこのオブジェクトの子にすることができません", - "validation.merge_armature.target_is_child:hint": "Merge Armature は自身の子に統合できません。「統合先」を別のオブジェクトに設定してみてください。", + "validation.merge_armature.target_is_child": "[MA-1500] 統合先として自身の子を指定することはできません。", + "validation.merge_armature.target_is_child:hint": "Merge Armatureで自身の子に統合することはできません。「統合先」を別のオブジェクトに設定してみてください。", "submenu_source.Children": "子オブジェクトから生成", "submenu_source.MenuAsset": "Expressions Menu アセットを指定", "menuitem.showcontents": "メニュー内容を表示", @@ -182,7 +182,7 @@ "menuitem.prop.type": "タイプ", "menuitem.prop.type.tooltip": "この項目の種別", "menuitem.prop.value": "パラメーター値", - "menuitem.prop.value.tooltip": "この項目が操作されたとき、パラメーターが設定される値", + "menuitem.prop.value.tooltip": "この項目が操作されたとき、パラメーターに設定される値", "menuitem.prop.automatic_value": "自動", "menuitem.prop.automatic_value.tooltip": "かぶらない値を自動的に割り振る", "menuitem.prop.parameter": "パラメーター名", @@ -190,19 +190,19 @@ "menuitem.prop.submenu_asset": "サブメニューアセット", "menuitem.prop.submenu_asset.tooltip": "サブメニューとして引用するアセット", "menuitem.prop.submenu_source": "サブメニュー引用元", - "menuitem.prop.submenu_source.tooltip": "このサブメニューの内容をどこから引用するべきかを指定", + "menuitem.prop.submenu_source.tooltip": "このサブメニューの内容をどこから引用するべきか指定します。", "menuitem.prop.source_override": "引用元オブジェクト", - "menuitem.prop.source_override.tooltip": "指定した場合は、指定したオブジェクトの子をメニューの内容として指定します。指定されてない場合はこのオブジェクト直下の子を使用します。", + "menuitem.prop.source_override.tooltip": "指定した場合、指定したオブジェクトの子をメニューの内容として指定します。指定されてない場合はこのオブジェクト直下の子を使用します。", "menuitem.prop.is_default": "初期設定にする", - "menuitem.prop.is_default.tooltip": "ONの場合、アバター初期化の際にこのメニューアイテムを選択します", + "menuitem.prop.is_default.tooltip": "有効になっていると、アバター初期化の際にこのメニューアイテムを選択した状態にします。", "menuitem.prop.is_saved": "保存する", - "menuitem.prop.is_saved.tooltip": "有効になっていると、アバター変更やワールド移動するときこの設定が保持されます。", + "menuitem.prop.is_saved.tooltip": "有効になっていると、アバター変更やワールド移動をしてもこの設定が保持されます。", "menuitem.prop.is_synced": "同期する", - "menuitem.prop.is_synced.tooltip": "有効の場合はほかのプレイヤーに同期されます。", - "menuitem.param.rotation": "回転パラメーター名", - "menuitem.param.rotation.tooltip": "このメニューアイテムの回転に連動するべきパラメーター", + "menuitem.prop.is_synced.tooltip": "有効になっていると、メニューがほかのプレイヤーに同期されます。", + "menuitem.param.rotation": "ラジアルメニュー用パラメーター名", + "menuitem.param.rotation.tooltip": "このラジアルメニューの操作と連動するべきパラメーター", "menuitem.param.horizontal": "横パラメーター名", - "menuitem.param.horizontal.tooltip": "横操作に連動するパラメーター名", + "menuitem.param.horizontal.tooltip": "左右操作に連動するパラメーター名", "menuitem.param.vertical": "縦パラメーター名", "menuitem.param.vertical.tooltip": "上下操作に連動するパラメーター名", "menuitem.label.control_labels_and_params": "表示名・パラメーター", @@ -218,29 +218,29 @@ "control_group.foldout.actions": "アクション", "control_group.foldout.menu_items": "関連付けされたメニューアイテム", "control_group.is_saved": "保存する", - "control_group.is_saved.tooltip": "有効になっていると、アバター変更やワールド移動するときこの設定が保持されます。", + "control_group.is_saved.tooltip": "有効になっていると、アバター変更やワールド移動をしてもこの設定が保持されます。", "control_group.is_synced": "同期する", - "control_group.is_synced.tooltip": "有効の場合はほかのプレイヤーに同期されます。", + "control_group.is_synced.tooltip": "有効になっていると、メニューがほかのプレイヤーに同期されます。", "control_group.default_value": "初期値", "control_group.default_value.unset": "(どれも選択されない)", "animation_gen.duplicate_binding": "別々のコントロールグループから、同じパラメーターが操作されています。パラメーター:{0}", - "animation_gen.multiple_defaults": "同じコントロールグループに初期設定に指定されたメニューアイテムが複数あります。", + "animation_gen.multiple_defaults": "同じコントロールグループに初期設定にするとして指定されたメニューアイテムが複数あります。", "menuitem.misc.add_item": "メニューアイテムを追加", - "replace_object.target_object": "上書き先", - "setup_outfit.err.header.notarget": "Setup outfit の処理が失敗しました", - "setup_outfit.err.header": "Setup outfit が「{0}」を処理中に失敗しました。", + "replace_object.target_object": "置き換え先", + "setup_outfit.err.header.notarget": "Setup Outfit の処理に失敗しました", + "setup_outfit.err.header": "Setup Outfit が「{0}」を処理中に失敗しました。", "setup_outfit.err.unknown": "原因不明のエラーが発生しました。", "setup_outfit.err.no_selection": "オブジェクトが選択されていません。", - "setup_outfit.err.run_on_avatar_itself": "Setup Outfitはアバター自体ではなく、衣装のほうで実行してください。\n\nキメラアバターを作る場合は、中のほうのAvatar Descriptorを消して、衣装として扱ってください。", - "setup_outfit.err.multiple_avatar_descriptors": "「{0}」とその親に、複数のavatar descriptorを発見しました。\n\nキメラアバターを作る場合は、中のほうのAvatar Descriptorを消して、衣装として扱ってください。", - "setup_outfit.err.no_avatar_descriptor": "「{0}」の親に、avatar descriptorが見つかりませんでした。衣装のオブジェクトをアバターの中に配置してください。", + "setup_outfit.err.run_on_avatar_itself": "Setup Outfitはアバター自体ではなく、衣装の方で実行してください。\n\nキメラアバターを作る場合は、中の方のAvatar Descriptorを消して、衣装として扱ってください。", + "setup_outfit.err.multiple_avatar_descriptors": "「{0}」とその親で複数のAvatar Descriptorを発見しました。\n\nキメラアバターを作る場合は、中の方のAvatar Descriptorを消して、衣装として扱ってください。", + "setup_outfit.err.no_avatar_descriptor": "「{0}」の親にAvatar Descriptorが見つかりませんでした。衣装のオブジェクトをアバターの中に配置してください。", "setup_outfit.err.no_animator": "アバターにAnimatorコンポーネントがありません。", - "setup_outfit.err.no_hips": "アバターにHipsボーンがありません。なお、Setup Outfitはヒューマノイドアバター以外には対応していません。", - "setup_outfit.err.no_outfit_hips": "衣装のHipsボーンを発見できませんでした。以下の名前を含むボーンを探しました:", - "move_independently.group-header": "一緒に動かすオブジェクト", + "setup_outfit.err.no_hips": "アバターにHipsボーンがありません。なお、Setup OutfitはHumanoidアバター以外には対応していません。", + "setup_outfit.err.no_outfit_hips": "衣装のHipsボーンを発見できませんでした。アクセサリー等に対してSetup Outfitを試みた場合は、代わりにBone Proxyコンポーネントを使って配置してみてください。\n以下の名前を含むボーンを探しました:", + "move_independently.group-header": "同時に動かすオブジェクト", "scale_adjuster.scale": "Scale調整値", "scale_adjuster.adjust_children": "子オブジェクトの位置を調整", - "world_fixed_object.err.unsupported_platform": "World Fixed Objectがこのプラットフォームに対応していません", + "world_fixed_object.err.unsupported_platform": "World Fixed Objectはこのプラットフォームに対応していません。", "world_fixed_object.err.unsupported_platform:description": "World Fixed ObjectはAndroid向けビルドには対応していないため、動作しません。", "ma_info.param_usage_ui.header": "Expressions Parameter 使用状況", "ma_info.param_usage_ui.other_objects": "このアバター内の他のオブジェクト", @@ -250,8 +250,8 @@ "reactive_object.inverse": "条件を反転", "reactive_object.material-setter.set-to": "変更先のマテリアル ", "menuitem.misc.add_toggle": "トグルを追加", - "ro_sim.open_debugger_button": "リアクションデバッグツールを開く", - "ro_sim.window.title": "MA リアクションデバッグツール", + "ro_sim.open_debugger_button": "Reaction デバッガーを開く", + "ro_sim.window.title": "MA Reaction デバッガー", "ro_sim.header.inspecting": "表示中のオブジェクト", "ro_sim.header.clear_overrides": "すべてのオーバーライドを解除", "ro_sim.header.object_state": "オブジェクトのアクティブ状態", @@ -260,16 +260,16 @@ "ro_sim.header.override_gameobject_state": "GameObject のアクティブ状態をオーバーライド", "ro_sim.header.override_menuitem_state": "MenuItem の選択状態をオーバーライト", "ro_sim.affected_by.title": "以下のルールに影響されています", - "ro_sim.effect_group.controls_obj_state": "オブジェクトのアクティブ状態を設定する➡", + "ro_sim.effect_group.controls_obj_state": "オブジェクトのアクティブ状態を次に設定する➡", "ro_sim.effect_group.target_component": "コンポーネント", "ro_sim.effect_group.target_component.tooltip": "Reactive Componentに影響されるコンポーネント", "ro_sim.effect_group.property": "プロパティ", "ro_sim.effect_group.property.tooltip": "設定されるプロパティ", "ro_sim.effect_group.value": "値", - "ro_sim.effect_group.value.tooltip": "上記 Reactive Component が活性状態の時に設定される値", + "ro_sim.effect_group.value.tooltip": "上記の Reactive Component がアクティブな時に設定される値", "ro_sim.effect_group.material": "マテリアル", - "ro_sim.effect_group.material.tooltip": "上記 Reactive Component が活性状態の時に設定されるマテリアル", - "ro_sim.effect_group.rule_inverted": "このルールの条件が反転されています", + "ro_sim.effect_group.material.tooltip": "上記の Reactive Component がアクティブな時に設定されるマテリアル", + "ro_sim.effect_group.rule_inverted": "このルールの条件は反転されています", "ro_sim.effect_group.rule_inverted.tooltip": "このルールは、いずれかの条件が満たされていない場合に適用されます", "ro_sim.effect_group.conditions": "条件" } \ No newline at end of file From 119c56878ccf1a41a2d8822c8fbe14b2d38b2652 Mon Sep 17 00:00:00 2001 From: bd_ Date: Tue, 24 Sep 2024 18:59:49 -0700 Subject: [PATCH 33/85] 1.10.0-rc.8 --- package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index 62189162..472a247c 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "nadena.dev.modular-avatar", "displayName": "Modular Avatar", - "version": "1.10.0-rc.7", + "version": "1.10.0-rc.8", "unity": "2022.3", "description": "A suite of tools for assembling your avatar out of reusable components", "author": { @@ -16,6 +16,6 @@ }, "vpmDependencies": { "com.vrchat.avatars": ">=3.7.0", - "nadena.dev.ndmf": ">=1.5.0-rc.8 <2.0.0-a" + "nadena.dev.ndmf": ">=1.5.0-rc.9 <2.0.0-a" } } From de1744b0805c247d6fb370041a16fbbebc84b0c0 Mon Sep 17 00:00:00 2001 From: Sayamame-beans <61457993+Sayamame-beans@users.noreply.github.com> Date: Thu, 26 Sep 2024 11:35:25 +0900 Subject: [PATCH 34/85] chore: update some messages (#1208) --- Editor/Localization/en-US.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Editor/Localization/en-US.json b/Editor/Localization/en-US.json index 812970c0..bc7e8ec8 100644 --- a/Editor/Localization/en-US.json +++ b/Editor/Localization/en-US.json @@ -99,7 +99,7 @@ "worldfixed.quest": "This component is not compatible with Android builds and will have no effect.", "worldfixed.normal": "This object will be fixed to world unless you fixed to avatar with constraint.", "fpvisible.normal": "This object will be visible in your first person view.", - "fpvisible.NotUnderHead": "This component has no effect when not placed under the head bone.", + "fpvisible.NotUnderHead": "This component has no effect when not placed under the head bone.\nIf this will be placed under the head bone through Bone Proxy etc., this warning can be ignored.", "fpvisible.quest": "This component is not compatible with Android builds and will have no effect.", "fpvisible.InPhysBoneChain": "This object is controlled by a Physics Bone chain and cannot be made visible in first person safely. Select the start of the chain instead.", "blendshape.mesh": "Mesh", @@ -240,7 +240,7 @@ "setup_outfit.err.no_avatar_descriptor": "No avatar descriptor found in {0}'s parents. Make sure your outfit is placed inside your avatar.", "setup_outfit.err.no_animator": "Your avatar does not have an Animator component.", "setup_outfit.err.no_hips": "Your avatar does not have a Hips bone. Setup Outfit only works on humanoid avatars.", - "setup_outfit.err.no_outfit_hips": "Unable to identify the Hips object for the outfit. Searched for objects containing the following names:", + "setup_outfit.err.no_outfit_hips": "Unable to identify the Hips object for the outfit. Searched for objects containing the following names(case-insensitive):", "move_independently.group-header": "Objects to move together", "scale_adjuster.scale": "Scale adjustment", "scale_adjuster.adjust_children": "Adjust position of child objects", @@ -281,4 +281,4 @@ "ro_sim.effect_group.rule_inverted": "This rule is inverted", "ro_sim.effect_group.rule_inverted.tooltip": "This rule will be applied when one of its conditions is NOT met", "ro_sim.effect_group.conditions": "Conditions" -} \ No newline at end of file +} From 13b0ffe0b51818053a4b5722e8eab44fac3a8ec2 Mon Sep 17 00:00:00 2001 From: bd_ Date: Wed, 25 Sep 2024 20:01:55 -0700 Subject: [PATCH 35/85] fix: missing observations in LocateReactions (#1210) --- .../ReactiveObjectAnalyzer.LocateReactions.cs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Editor/ReactiveObjects/AnimationGeneration/ReactiveObjectAnalyzer.LocateReactions.cs b/Editor/ReactiveObjects/AnimationGeneration/ReactiveObjectAnalyzer.LocateReactions.cs index 1aeb0f1b..f84d0b30 100644 --- a/Editor/ReactiveObjects/AnimationGeneration/ReactiveObjectAnalyzer.LocateReactions.cs +++ b/Editor/ReactiveObjects/AnimationGeneration/ReactiveObjectAnalyzer.LocateReactions.cs @@ -82,7 +82,7 @@ namespace nadena.dev.modular_avatar.core.editor Parameter = GetActiveSelfProxy(cursor.gameObject), DebugName = cursor.gameObject.name, IsConstant = false, - InitialValue = cursor.gameObject.activeSelf ? 1.0f : 0.0f, + InitialValue = _computeContext.Observe(cursor.gameObject, go => go.activeSelf) ? 1.0f : 0.0f, ParameterValueLo = 0.5f, ParameterValueHi = float.PositiveInfinity, ReferenceObject = cursor.gameObject, @@ -228,7 +228,8 @@ namespace nadena.dev.modular_avatar.core.editor if (!objectGroups.TryGetValue(key, out var group)) { - group = new AnimatedProperty(key, target.activeSelf ? 1 : 0); + var active = _computeContext.Observe(target, t => t.activeSelf); + group = new AnimatedProperty(key, active ? 1 : 0); objectGroups[key] = group; } From a018df921963277f468cee6d6135ddfbcda4b4ca Mon Sep 17 00:00:00 2001 From: bd_ Date: Wed, 25 Sep 2024 20:01:59 -0700 Subject: [PATCH 36/85] chore: improve PropCache debuggability by adding a name property (#1209) --- Editor/Inspector/Menu/MenuItemGUI.cs | 5 +++-- .../AnimationGeneration/PropCache.cs | 14 +++++++++----- .../AnimationGeneration/ReactiveObjectAnalyzer.cs | 2 +- Editor/ReactiveObjects/MaterialSetterPreview.cs | 2 +- Editor/ReactiveObjects/ShapeChangerPreview.cs | 4 ++-- UnitTests~/PropCacheTest/PropCacheTest.cs | 2 +- 6 files changed, 17 insertions(+), 12 deletions(-) diff --git a/Editor/Inspector/Menu/MenuItemGUI.cs b/Editor/Inspector/Menu/MenuItemGUI.cs index 29c75b63..c89c3817 100644 --- a/Editor/Inspector/Menu/MenuItemGUI.cs +++ b/Editor/Inspector/Menu/MenuItemGUI.cs @@ -25,10 +25,11 @@ namespace nadena.dev.modular_avatar.core.editor internal static class ParameterIntrospectionCache { - internal static PropCache> ProvidedParameterCache = new (GetParametersForObject_miss); + internal static PropCache> ProvidedParameterCache = + new("GetParametersForObject", GetParametersForObject_miss); internal static PropCache> - ParameterRemappingCache = new(GetParameterRemappingsAt_miss); + ParameterRemappingCache = new("GetParameterRemappingsAt", GetParameterRemappingsAt_miss); private static ImmutableList GetParametersForObject_miss(ComputeContext ctx, GameObject obj) { diff --git a/Editor/ReactiveObjects/AnimationGeneration/PropCache.cs b/Editor/ReactiveObjects/AnimationGeneration/PropCache.cs index 63fc36ef..e0063697 100644 --- a/Editor/ReactiveObjects/AnimationGeneration/PropCache.cs +++ b/Editor/ReactiveObjects/AnimationGeneration/PropCache.cs @@ -1,7 +1,6 @@ using System; using System.Collections.Generic; using nadena.dev.ndmf.preview; -using UnityEngine; namespace nadena.dev.modular_avatar.core.editor { @@ -13,21 +12,25 @@ namespace nadena.dev.modular_avatar.core.editor public PropCache Owner; public Key Key; public Value Value; + public string DebugName; } + private readonly string _debugName; private readonly Func _operator; private readonly Func _equalityComparer; private readonly Dictionary _cache = new(); - public PropCache(Func operatorFunc, Func equalityComparer = null) + public PropCache(string debugName, Func operatorFunc, + Func equalityComparer = null) { + _debugName = debugName; _operator = operatorFunc; _equalityComparer = equalityComparer; } private static void InvalidateEntry(CacheEntry entry) { - var newGenContext = new ComputeContext("PropCache for key " + entry.Key); + var newGenContext = new ComputeContext("PropCache/" + entry.DebugName + " key " + entry.Key); var newValue = entry.Owner._operator(newGenContext, entry.Key); if (entry.Owner._equalityComparer != null && entry.Owner._equalityComparer(entry.Value, newValue)) { @@ -44,14 +47,15 @@ namespace nadena.dev.modular_avatar.core.editor { if (!_cache.TryGetValue(key, out var entry) || entry.GenerateContext.IsInvalidated) { - var subContext = new ComputeContext("PropCache for key " + key); + var subContext = new ComputeContext("PropCache/" + _debugName + " key " + key); entry = new CacheEntry { GenerateContext = subContext, ObserverContext = new ComputeContext("Observer for PropCache for key " + key), Owner = this, Key = key, - Value = _operator(subContext, key) + Value = _operator(subContext, key), + DebugName = _debugName }; _cache[key] = entry; diff --git a/Editor/ReactiveObjects/AnimationGeneration/ReactiveObjectAnalyzer.cs b/Editor/ReactiveObjects/AnimationGeneration/ReactiveObjectAnalyzer.cs index 096c3e94..42f11821 100644 --- a/Editor/ReactiveObjects/AnimationGeneration/ReactiveObjectAnalyzer.cs +++ b/Editor/ReactiveObjects/AnimationGeneration/ReactiveObjectAnalyzer.cs @@ -67,7 +67,7 @@ namespace nadena.dev.modular_avatar.core.editor { if (_analysisCache == null) { - _analysisCache = new PropCache((ctx, root) => + _analysisCache = new PropCache("ROAnalyzer", (ctx, root) => { var analysis = new ReactiveObjectAnalyzer(ctx); analysis.ForcePropertyOverrides = ctx.Observe(ROSimulator.PropertyOverrides, a=>a, (a,b) => false) diff --git a/Editor/ReactiveObjects/MaterialSetterPreview.cs b/Editor/ReactiveObjects/MaterialSetterPreview.cs index 29f0b07d..a181429d 100644 --- a/Editor/ReactiveObjects/MaterialSetterPreview.cs +++ b/Editor/ReactiveObjects/MaterialSetterPreview.cs @@ -28,7 +28,7 @@ namespace nadena.dev.modular_avatar.core.editor private const string PREFIX = "m_Materials.Array.data["; private PropCache> _cache = new( - GetMaterialOverridesForRenderer, Enumerable.SequenceEqual + "GetMaterialOverridesForRenderer", GetMaterialOverridesForRenderer, Enumerable.SequenceEqual ); private static ImmutableList<(int, Material)> GetMaterialOverridesForRenderer(ComputeContext ctx, Renderer r) diff --git a/Editor/ReactiveObjects/ShapeChangerPreview.cs b/Editor/ReactiveObjects/ShapeChangerPreview.cs index 912fd99b..4977053c 100644 --- a/Editor/ReactiveObjects/ShapeChangerPreview.cs +++ b/Editor/ReactiveObjects/ShapeChangerPreview.cs @@ -60,8 +60,8 @@ namespace nadena.dev.modular_avatar.core.editor } } - private PropCache>> - _blendshapeCache = new(ShapesForAvatar); + private readonly PropCache>> + _blendshapeCache = new("ShapesForAvatar", ShapesForAvatar); private static ImmutableDictionary> ShapesForAvatar(ComputeContext context, GameObject avatarRoot) { diff --git a/UnitTests~/PropCacheTest/PropCacheTest.cs b/UnitTests~/PropCacheTest/PropCacheTest.cs index 2b63161c..2f0c9c5f 100644 --- a/UnitTests~/PropCacheTest/PropCacheTest.cs +++ b/UnitTests~/PropCacheTest/PropCacheTest.cs @@ -19,7 +19,7 @@ namespace UnitTests.PropCacheTest int seq = 0; Dictionary>> invalidators = new(); - PropCache cache = new PropCache((ctx, k) => + PropCache cache = new PropCache("test", (ctx, k) => { Debug.Log("Generating value for " + k); if (!invalidators.TryGetValue(k, out var list)) From e63a34e2bacd03673dcb545b88a0b33f58e0693b Mon Sep 17 00:00:00 2001 From: bd_ Date: Wed, 25 Sep 2024 21:09:58 -0700 Subject: [PATCH 37/85] fix: scale adjuster preview destroys proxy renderers inappropriately (#1213) The scale adjuster preview system reparented proxy renderers under proxy bones, in order to handle null root bones and MeshRenderers. However, it then destroyed the entire proxy bone hierarchy, taking all proxy renderers with it. This change instead tracks proxies, and reparents them back to the root to avoid this issue. Closes: #1177 --- Editor/ScaleAdjuster/ScaleAdjusterPreview.cs | 23 +++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/Editor/ScaleAdjuster/ScaleAdjusterPreview.cs b/Editor/ScaleAdjuster/ScaleAdjusterPreview.cs index 892d20e6..626894c2 100644 --- a/Editor/ScaleAdjuster/ScaleAdjusterPreview.cs +++ b/Editor/ScaleAdjuster/ScaleAdjusterPreview.cs @@ -97,6 +97,8 @@ namespace nadena.dev.modular_avatar.core.editor internal class ScaleAdjusterPreviewNode : IRenderFilterNode { + private readonly HashSet _knownProxies = new(); + private readonly GameObject SourceAvatarRoot; private readonly GameObject VirtualAvatarRoot; @@ -230,6 +232,9 @@ namespace nadena.dev.modular_avatar.core.editor { if (SourceAvatarRoot == null) return Task.FromResult(null); + // Clean any destroyed objects out of _knownProxies to avoid growing this set indefinitely + _knownProxies.RemoveWhere(p => p == null); + var proxyPairList = proxyPairs.ToList(); if (!GetSourceBonesSet(context, proxyPairList).SetEquals(_shadowBoneMap.Keys)) @@ -339,7 +344,15 @@ namespace nadena.dev.modular_avatar.core.editor if (proxy == null) return; var curParent = proxy.transform.parent ?? original.transform.parent; - if (_finalBonesMap.TryGetValue(curParent, out var newRoot)) proxy.transform.SetParent(newRoot, false); + if (_finalBonesMap.TryGetValue(curParent, out var newRoot)) + { + // We need to remember this proxy so we can avoid destroying it when we destroy VirtualAvatarRoot + // in Dispose + + _knownProxies.Add(proxy.transform); + + proxy.transform.SetParent(newRoot, false); + } var smr = proxy as SkinnedMeshRenderer; if (smr == null) return; @@ -351,6 +364,14 @@ namespace nadena.dev.modular_avatar.core.editor public void Dispose() { + foreach (var proxy in _knownProxies) + { + if (proxy != null && proxy.IsChildOf(VirtualAvatarRoot.transform)) + { + proxy.transform.SetParent(null, false); + } + } + Object.DestroyImmediate(VirtualAvatarRoot); _srcBones.Dispose(); From ee64cafe021393ac74bbde9256cf40024d54af3e Mon Sep 17 00:00:00 2001 From: bd_ Date: Wed, 25 Sep 2024 21:39:01 -0700 Subject: [PATCH 38/85] fix: remove ObjectIdentityComparer (#1211) Apparently, it's safe to use Unity objects as keys in HashMaps, and doing so actually fixes some edge cases where assets are recreated as a new C# object. --- .../MoveIndependentlyEditor.cs | 2 +- .../ConstraintConverterPass.cs | 2 +- Editor/ReactiveObjects/ShapeChangerPreview.cs | 3 +-- Editor/ScaleAdjuster/ScaleAdjustedBones.cs | 2 +- Editor/ScaleAdjuster/ScaleAdjusterPreview.cs | 16 ++++++------- Runtime/Util/ObjectIdentityComparer.cs | 23 ------------------- Runtime/Util/ObjectIdentityComparer.cs.meta | 3 --- 7 files changed, 12 insertions(+), 39 deletions(-) delete mode 100644 Runtime/Util/ObjectIdentityComparer.cs delete mode 100644 Runtime/Util/ObjectIdentityComparer.cs.meta diff --git a/Editor/Inspector/MoveIndependently/MoveIndependentlyEditor.cs b/Editor/Inspector/MoveIndependently/MoveIndependentlyEditor.cs index 171a5ae6..4b741d90 100644 --- a/Editor/Inspector/MoveIndependently/MoveIndependentlyEditor.cs +++ b/Editor/Inspector/MoveIndependently/MoveIndependentlyEditor.cs @@ -61,7 +61,7 @@ namespace nadena.dev.modular_avatar.core.editor var grouped = ctx.Observe(target, t => (t.GroupedBones ?? Array.Empty()) .Select(obj => obj.transform) - .ToHashSet(new ObjectIdentityComparer()), + .ToHashSet(), (x, y) => x.SetEquals(y) ); diff --git a/Editor/OptimizationPasses/ConstraintConverterPass.cs b/Editor/OptimizationPasses/ConstraintConverterPass.cs index 10c8dccc..2dfa9a7e 100644 --- a/Editor/OptimizationPasses/ConstraintConverterPass.cs +++ b/Editor/OptimizationPasses/ConstraintConverterPass.cs @@ -45,7 +45,7 @@ namespace nadena.dev.modular_avatar.core.editor { var converters = context.AvatarRootObject.GetComponentsInChildren(true) .Select(c => c.gameObject) - .ToHashSet(new ObjectIdentityComparer()); + .ToHashSet(); if (converters.Count == 0) return; var constraintGameObjects = context.AvatarRootObject.GetComponentsInChildren(true) diff --git a/Editor/ReactiveObjects/ShapeChangerPreview.cs b/Editor/ReactiveObjects/ShapeChangerPreview.cs index 4977053c..d17c7a37 100644 --- a/Editor/ReactiveObjects/ShapeChangerPreview.cs +++ b/Editor/ReactiveObjects/ShapeChangerPreview.cs @@ -5,7 +5,6 @@ using System.Collections.Generic; using System.Collections.Immutable; using System.Linq; using System.Threading.Tasks; -using nadena.dev.modular_avatar.core.editor.Simulator; using nadena.dev.ndmf.preview; using UnityEngine; using Object = UnityEngine.Object; @@ -75,7 +74,7 @@ namespace nadena.dev.modular_avatar.core.editor ImmutableDictionary>.Builder rendererStates = ImmutableDictionary.CreateBuilder>( - new ObjectIdentityComparer() + ); var avatarRootTransform = avatarRoot.transform; diff --git a/Editor/ScaleAdjuster/ScaleAdjustedBones.cs b/Editor/ScaleAdjuster/ScaleAdjustedBones.cs index fdda046c..1220e982 100644 --- a/Editor/ScaleAdjuster/ScaleAdjustedBones.cs +++ b/Editor/ScaleAdjuster/ScaleAdjustedBones.cs @@ -31,7 +31,7 @@ namespace nadena.dev.modular_avatar.core.editor.ScaleAdjuster public BoneState parentHint; } - private Dictionary _bones = new(new ObjectIdentityComparer()); + private readonly Dictionary _bones = new(); //private List _states = new List(); public void Clear() diff --git a/Editor/ScaleAdjuster/ScaleAdjusterPreview.cs b/Editor/ScaleAdjuster/ScaleAdjusterPreview.cs index 626894c2..542cd5ff 100644 --- a/Editor/ScaleAdjuster/ScaleAdjusterPreview.cs +++ b/Editor/ScaleAdjuster/ScaleAdjusterPreview.cs @@ -59,7 +59,7 @@ namespace nadena.dev.modular_avatar.core.editor var scaleAdjusters = ctx.GetComponentsByType(); var avatarToRenderer = - new Dictionary>(new ObjectIdentityComparer()); + new Dictionary>(); foreach (var root in ctx.GetAvatarRoots()) { @@ -72,8 +72,8 @@ namespace nadena.dev.modular_avatar.core.editor { continue; // nested avatar descriptor } - - var renderers = new HashSet(new ObjectIdentityComparer()); + + var renderers = new HashSet(); avatarToRenderer.Add(root, renderers); foreach (var renderer in root.GetComponentsInChildren()) @@ -112,12 +112,12 @@ namespace nadena.dev.modular_avatar.core.editor private readonly Dictionary _shadowBoneMap; // Map from bones found in initial proxy state to shadow bones (with scale adjuster bones substituted) - private readonly Dictionary _finalBonesMap = new(new ObjectIdentityComparer()); + private readonly Dictionary _finalBonesMap = new(); private readonly Dictionary _scaleAdjusters = - new(new ObjectIdentityComparer()); + new(); - private Dictionary _rendererBoneStates = new(new ObjectIdentityComparer()); + private Dictionary _rendererBoneStates = new(); public ScaleAdjusterPreviewNode(ComputeContext context, RenderGroup group, IEnumerable<(Renderer, Renderer)> proxyPairs) @@ -169,7 +169,7 @@ namespace nadena.dev.modular_avatar.core.editor private HashSet GetSourceBonesSet(ComputeContext context, List<(Renderer, Renderer)> proxyPairs) { - var bonesSet = new HashSet(new ObjectIdentityComparer()); + var bonesSet = new HashSet(); foreach (var (_, r) in proxyPairs) { if (r == null) continue; @@ -248,7 +248,7 @@ namespace nadena.dev.modular_avatar.core.editor private Dictionary CreateShadowBones(Transform[] srcBones) { - var srcToDst = new Dictionary(new ObjectIdentityComparer()); + var srcToDst = new Dictionary(); for (var i = 0; i < srcBones.Length; i++) GetShadowBone(srcBones[i]); diff --git a/Runtime/Util/ObjectIdentityComparer.cs b/Runtime/Util/ObjectIdentityComparer.cs deleted file mode 100644 index 80d47032..00000000 --- a/Runtime/Util/ObjectIdentityComparer.cs +++ /dev/null @@ -1,23 +0,0 @@ -#region - -using System.Collections.Generic; -using System.Runtime.CompilerServices; - -#endregion - -namespace nadena.dev.modular_avatar -{ - internal class ObjectIdentityComparer : IEqualityComparer - { - public bool Equals(T x, T y) - { - return (object)x == (object)y; - } - - public int GetHashCode(T obj) - { - if (obj == null) return 0; - return RuntimeHelpers.GetHashCode(obj); - } - } -} \ No newline at end of file diff --git a/Runtime/Util/ObjectIdentityComparer.cs.meta b/Runtime/Util/ObjectIdentityComparer.cs.meta deleted file mode 100644 index a1ec9a3e..00000000 --- a/Runtime/Util/ObjectIdentityComparer.cs.meta +++ /dev/null @@ -1,3 +0,0 @@ -fileFormatVersion: 2 -guid: e674cbd75db24fb2b238674cd7010edb -timeCreated: 1709448428 \ No newline at end of file From 4f398d21c3315851e1368639df6f018c7eb0656b Mon Sep 17 00:00:00 2001 From: nadena-dev-ci Date: Sat, 28 Sep 2024 10:06:53 +0900 Subject: [PATCH 39/85] New Crowdin updates (#1212) * New translations en-us.json (Japanese) * New translations en-us.json (Korean) * New translations en-us.json (Chinese Simplified) * New translations en-us.json (Chinese Traditional) * Update source file en-US.json * New translations en-us.json (Japanese) --- Editor/Localization/ja-JP.json | 7 ++++--- Editor/Localization/ko-KR.json | 3 +-- Editor/Localization/zh-Hans.json | 4 +--- Editor/Localization/zh-Hant.json | 4 +--- 4 files changed, 7 insertions(+), 11 deletions(-) diff --git a/Editor/Localization/ja-JP.json b/Editor/Localization/ja-JP.json index 776db759..94c6022a 100644 --- a/Editor/Localization/ja-JP.json +++ b/Editor/Localization/ja-JP.json @@ -95,7 +95,7 @@ "worldfixed.quest": "このコンポーネントはアンドロイドビルドに非対応であるため、無効となっています。", "worldfixed.normal": "このオブジェクトはConstraint等でアバターに追従させない限りワールドに固定されます。", "fpvisible.normal": "このオブジェクトは一人称視点で表示されます。", - "fpvisible.NotUnderHead": "このコンポーネントはヘッドボーン以下にないオブジェクトには効果がありません。", + "fpvisible.NotUnderHead": "このコンポーネントは頭ボーンの配下でないと効果がありません。\n(Bone Proxyなどで頭ボーンの配下に配置される場合は効果あります)", "fpvisible.quest": "このコンポーネントはアンドロイドビルドに非対応であるため、無効となっています。", "fpvisible.InPhysBoneChain": "このオブジェクトはPhysBoneで制御されているため、一人称視点でうまく表示させることができません。PhysBoneの始点を指定してください。", "blendshape.mesh": "メッシュ", @@ -236,7 +236,7 @@ "setup_outfit.err.no_avatar_descriptor": "「{0}」の親にAvatar Descriptorが見つかりませんでした。衣装のオブジェクトをアバターの中に配置してください。", "setup_outfit.err.no_animator": "アバターにAnimatorコンポーネントがありません。", "setup_outfit.err.no_hips": "アバターにHipsボーンがありません。なお、Setup OutfitはHumanoidアバター以外には対応していません。", - "setup_outfit.err.no_outfit_hips": "衣装のHipsボーンを発見できませんでした。アクセサリー等に対してSetup Outfitを試みた場合は、代わりにBone Proxyコンポーネントを使って配置してみてください。\n以下の名前を含むボーンを探しました:", + "setup_outfit.err.no_outfit_hips": "衣装のHipsボーンを発見できませんでした。アクセサリー等に対してSetup Outfitを試みた場合は、代わりにBone Proxyコンポーネントを使って配置してみてください。\n以下の名前を含むボーンを(大文字・小文字を区別つけずに)探しました:", "move_independently.group-header": "同時に動かすオブジェクト", "scale_adjuster.scale": "Scale調整値", "scale_adjuster.adjust_children": "子オブジェクトの位置を調整", @@ -260,6 +260,7 @@ "ro_sim.header.override_gameobject_state": "GameObject のアクティブ状態をオーバーライド", "ro_sim.header.override_menuitem_state": "MenuItem の選択状態をオーバーライト", "ro_sim.affected_by.title": "以下のルールに影響されています", + "ro_sim.effect_group.component": "Reactive Component", "ro_sim.effect_group.controls_obj_state": "オブジェクトのアクティブ状態を次に設定する➡", "ro_sim.effect_group.target_component": "コンポーネント", "ro_sim.effect_group.target_component.tooltip": "Reactive Componentに影響されるコンポーネント", @@ -272,4 +273,4 @@ "ro_sim.effect_group.rule_inverted": "このルールの条件は反転されています", "ro_sim.effect_group.rule_inverted.tooltip": "このルールは、いずれかの条件が満たされていない場合に適用されます", "ro_sim.effect_group.conditions": "条件" -} \ No newline at end of file +} diff --git a/Editor/Localization/ko-KR.json b/Editor/Localization/ko-KR.json index 6194b873..0278dbb7 100644 --- a/Editor/Localization/ko-KR.json +++ b/Editor/Localization/ko-KR.json @@ -96,7 +96,6 @@ "worldfixed.quest": "이 컴포넌트는 안드로이드 빌드를 대응하지 않습니다.", "worldfixed.normal": "이 오브젝트는 Constraint 을 사용하여 아바타에 고정하지 않는 이상 월드축에 고정됩니다.", "fpvisible.normal": "이 오브젝트는 일인칭 시점에서 보일 것입니다.", - "fpvisible.NotUnderHead": "Head 본(Bone) 내의 오브젝트가 아닌 경우 작동하지 않습니다.", "fpvisible.quest": "이 컴포넌트는 오큘러스 퀘스트 단독 버전과 호환되지 않으며 영향을 미치지 않습니다.", "fpvisible.InPhysBoneChain": "이 객체는 Physics Bone 체인에 의해 컨트롤되므로 체인의 세부적인 선택이 불가능합니다. 대신 체인의 시작 부분을 선택하세요.", "blendshape.mesh": "메시", @@ -144,4 +143,4 @@ "control_group.is_synced": "동기화됨", "setup_outfit.err.unknown": "알 수 없는 오류", "ma_info.param_usage_ui.other_objects": "이 아바타안의 다른 오브젝트들" -} \ No newline at end of file +} diff --git a/Editor/Localization/zh-Hans.json b/Editor/Localization/zh-Hans.json index ec0bce70..4b5d56a8 100644 --- a/Editor/Localization/zh-Hans.json +++ b/Editor/Localization/zh-Hans.json @@ -94,7 +94,6 @@ "worldfixed.quest": "此组件未生效,因为它与 Oculus Quest 不兼容。", "worldfixed.normal": "当前对象将会固定于世界,除非您使用约束将它绑定在 Avatar 内。", "fpvisible.normal": "当前对象将在第一人称视角中可见。", - "fpvisible.NotUnderHead": "此组件未生效,因为它需要放置在 Head 骨骼下。", "fpvisible.quest": "此组件未生效,因为它与 Oculus Quest 不兼容。", "fpvisible.InPhysBoneChain": "当前对象由 PhysicsBone 控制,可能无法在第一人称视角中可见;请指定 PhysicsBone 链的起点。", "blendshape.mesh": "网格", @@ -227,7 +226,6 @@ "setup_outfit.err.no_avatar_descriptor": "在 {0} 的父级中找不到 VRC Avatar Descriptor。请确保您的服装放置在 Avatar 内。", "setup_outfit.err.no_animator": "您的 Avatar 没有动画控制器 (Animator) 组件。", "setup_outfit.err.no_hips": "您的 Avatar 没有 Hips 骨骼。Setup Outfit 只能用于 humanoid Avatars。", - "setup_outfit.err.no_outfit_hips": "无法识别服装的 Hips,已搜索包含以下名称的对象:", "move_independently.group-header": "要一起移动的对象", "scale_adjuster.scale": "调整比例", "scale_adjuster.adjust_children": "调整子级的位置", @@ -237,4 +235,4 @@ "ma_info.param_usage_ui.other_objects": "此 Avatar 上的其他对象", "ma_info.param_usage_ui.free_space": "未使用的参数空间 ({0} bits)", "ma_info.param_usage_ui.bits_template": "{0} ({1} bits)" -} \ No newline at end of file +} diff --git a/Editor/Localization/zh-Hant.json b/Editor/Localization/zh-Hant.json index 465eb62b..21cd5a61 100644 --- a/Editor/Localization/zh-Hant.json +++ b/Editor/Localization/zh-Hant.json @@ -99,7 +99,6 @@ "worldfixed.quest": "此元件未生效,因為它與 Android 環境不相容。", "worldfixed.normal": "當前物件將會固定於世界,除非你使用約束將它綁在 Avatar 內。", "fpvisible.normal": "當前物件將在第一人稱視角中可見。", - "fpvisible.NotUnderHead": "此元件未生效,因為它需要放置在 Head 骨骼下。", "fpvisible.quest": "此元件未生效,因為它與 Android 環境不相容。", "fpvisible.InPhysBoneChain": "當前物件由 Physics Bone 控制,可能無法在第一人稱視角中可見;請指定 Physics Bone 鏈的起點。", "blendshape.mesh": "網格", @@ -239,7 +238,6 @@ "setup_outfit.err.no_avatar_descriptor": "在 {0} 的父級中找不到 VRC Avatar Descriptor。請確保你的服裝放置在 Avatar 裡。", "setup_outfit.err.no_animator": "你的 Avatar 沒有 Animator 元件。", "setup_outfit.err.no_hips": "你的 Avatar 沒有 Hips 骨骼。Setup Outfit 只能用於 humanoid Avatars。", - "setup_outfit.err.no_outfit_hips": "識別不到服裝的 Hips 骨骼,已搜尋含有以下名稱的骨骼物件:", "move_independently.group-header": "要一起移動的物件", "scale_adjuster.scale": "調整比例", "scale_adjuster.adjust_children": "調整子級的位置", @@ -275,4 +273,4 @@ "ro_sim.effect_group.rule_inverted": "規則的條件已反轉", "ro_sim.effect_group.rule_inverted.tooltip": "這條規則將在未達成其任一條件時套用。", "ro_sim.effect_group.conditions": "條件" -} \ No newline at end of file +} From 3f5d5a2013a2cc31998dafdacf021413cd2042a9 Mon Sep 17 00:00:00 2001 From: bd_ Date: Fri, 27 Sep 2024 18:34:45 -0700 Subject: [PATCH 40/85] 1.10.0-rc.9 --- package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index 472a247c..bf79dd83 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "nadena.dev.modular-avatar", "displayName": "Modular Avatar", - "version": "1.10.0-rc.8", + "version": "1.10.0-rc.9", "unity": "2022.3", "description": "A suite of tools for assembling your avatar out of reusable components", "author": { @@ -16,6 +16,6 @@ }, "vpmDependencies": { "com.vrchat.avatars": ">=3.7.0", - "nadena.dev.ndmf": ">=1.5.0-rc.9 <2.0.0-a" + "nadena.dev.ndmf": ">=1.5.0-rc.10 <2.0.0-a" } } From 1fe8255f52a4b980faf93b191ef22d65d40c0fa3 Mon Sep 17 00:00:00 2001 From: bd_ Date: Fri, 27 Sep 2024 18:55:10 -0700 Subject: [PATCH 41/85] docs: update mesh settings docs --- docs~/docs/reference/mesh-settings.md | 16 ++++++++++++---- .../current/reference/mesh-settings.md | 13 ++++++++++--- 2 files changed, 22 insertions(+), 7 deletions(-) diff --git a/docs~/docs/reference/mesh-settings.md b/docs~/docs/reference/mesh-settings.md index b506fb1f..b7c255e1 100644 --- a/docs~/docs/reference/mesh-settings.md +++ b/docs~/docs/reference/mesh-settings.md @@ -23,10 +23,18 @@ designed for a specific avatar. ## Manually configuring Mesh Settings -When you add Mesh Settings to a game object, initially it is configured to do nothing. By setting either -"Anchor Override Mode" or "Bounds Override Mode" to "Set", you can configure the anchor override or bounds -for all meshes under that game object. Alternately, by setting the mode to "Don't set", you can exclude -these meshes from the influence of Mesh Settings higher up on the hierarchy. +When you add Mesh Settings to a game object, initially it is configured to do nothing. In order for the settings +component to have any effect, you need to change the "Anchor Override Mode" and/or "Bounds Override Mode". These +support the following options: + +- Inherit: This component does nothing for this setting; it will inherit values set in parent Mesh Settings. +- Set: This component sets the corresponding setting on any meshes on its GameObject or its children. +- Don't set: This component _blocks_ any parent Mesh Settings from having an effect. Meshes will remain at their default + settings. +- Set or inherit: If there is a parent Mesh Settings in Set mode, it will be used. If no parent Mesh Settings applies, + then this component's settings will be used. This is useful for outfit prefabs, to ensure that any avatar-wide + settings + take precedence. When configuring bounds, the bounding box will be determined relative to the transform you specify as the "Root Bone". Note that bounds only affects Skinned Mesh Renderers, but Anchor Override also impacts other diff --git a/docs~/i18n/ja/docusaurus-plugin-content-docs/current/reference/mesh-settings.md b/docs~/i18n/ja/docusaurus-plugin-content-docs/current/reference/mesh-settings.md index e0d96bf7..12459d0f 100644 --- a/docs~/i18n/ja/docusaurus-plugin-content-docs/current/reference/mesh-settings.md +++ b/docs~/i18n/ja/docusaurus-plugin-content-docs/current/reference/mesh-settings.md @@ -21,9 +21,16 @@ Mesh Settingsコンポーネントを使用すると、特定のゲームオブ ## Mesh Settingsの手動設定 -ゲームオブジェクトにMesh Settingsを追加すると、最初は何も効果がありません。Anchor Overrideの設定モードまたはBounds Override -の設定モードを「設定」に設定することで、そのゲームオブジェクトの下にあるすべてのメッシュのアンカーオーバーライドまたはバウンズ -を設定できます。また、モードを「設定しない」に設定することで、これらのメッシュを階層の上位にあるMesh Settingsの影響から除外できます。 +ゲームオブジェクトにMesh Settingsを追加すると、最初は何も効果がありません。効果を発揮するには、まずは「Anchor Override +設定」あるいは +「Bounds 設定」で「設定モード」を変更する必要があります。以下の選択しがあります。 + +- 継承:このコンポーネントはこの設定に対して何もしません。親のMesh Settingsで設定された値を継承します。 +- 設定:このコンポーネントは、そのゲームオブジェクトとその子にあるメッシュの対応する設定を設定します。 +- 設定しない:このコンポーネントは、親のMesh Settingsの影響を受けないようにします。メッシュはデフォルトの設定のままです。 +- 親が継承された時は継承、または設定:親のMesh Settingsが設定モードにある場合、それが使用されます。親のMesh + Settingsが適用されない場合、 + このコンポーネントの設定が使用されます。衣装プレハブなどに、アバター全体の設定が優先されるようにするために便利です。 バウンズを設定する場合、バウンディングボックスは「Root Bone」として指定したトランスフォームに対して相対的に決定されます。 また、バウンズはSkinned Mesh Rendererのみに影響しますが、Anchor OverrideはMesh RendererやLine Rendererなどの他のタイプの From 7e5c227867f9a4993509e9b190752564473531c3 Mon Sep 17 00:00:00 2001 From: bd_ Date: Fri, 27 Sep 2024 18:55:38 -0700 Subject: [PATCH 42/85] docs: update Visible Head Accessory docs --- docs~/docs/reference/visible-head-accessory.md | 2 -- .../current/reference/visible-head-accessory.md | 2 -- 2 files changed, 4 deletions(-) diff --git a/docs~/docs/reference/visible-head-accessory.md b/docs~/docs/reference/visible-head-accessory.md index c755e5f2..e6383ce1 100644 --- a/docs~/docs/reference/visible-head-accessory.md +++ b/docs~/docs/reference/visible-head-accessory.md @@ -22,5 +22,3 @@ Just attach a Visible Head Accessory component under a child of the Head bone. T The component will automatically generate a clone of the Head bone, which is connected to the real head bone using a parent constraint. Only one constraint will be generated, even if multiple Visible Head Accessory components are used. As such, the performance impact of this component is the same whether you use one or dozens. - -Due to technical limitations on the Quest, this component has no effect when building for Quest standalone. diff --git a/docs~/i18n/ja/docusaurus-plugin-content-docs/current/reference/visible-head-accessory.md b/docs~/i18n/ja/docusaurus-plugin-content-docs/current/reference/visible-head-accessory.md index 6fbf09a6..8f2d2dcf 100644 --- a/docs~/i18n/ja/docusaurus-plugin-content-docs/current/reference/visible-head-accessory.md +++ b/docs~/i18n/ja/docusaurus-plugin-content-docs/current/reference/visible-head-accessory.md @@ -22,5 +22,3 @@ Headボーンの子にVisible Head Accessoryコンポーネントを付けるだ このコンポーネントは自動的にHeadボーンを複製し、Parent Constraintで本物のHeadボーンに追従させます。 複数のVisible Head Accessoryコンポーネントを使っても、Constraintは一つだけです。なので、複数のボーンを指定しても、その分重くなることはありません。 - -技術的な制約により、Quest単体では動作できません。Quest向けのビルドはつけたままにしてもいいが、効果は発揮しません。 From b866628b2490b15e82b2a1e6f40bf69785ee45bf Mon Sep 17 00:00:00 2001 From: bd_ Date: Fri, 27 Sep 2024 19:24:19 -0700 Subject: [PATCH 43/85] chore: fix compiler warnings --- Editor/Inspector/LogoDisplay.cs | 2 +- .../MaterialSetter/MaterialSwitchObjectEditor.cs | 3 +-- Editor/Inspector/Menu/ToggleCreatorShortcut.cs | 2 +- Editor/Inspector/ShapeChanger/ChangedShapeEditor.cs | 2 +- Editor/OptimizationPasses/GCGameObjectsPass.cs | 6 +++--- Editor/ParamsUsage/ParamsUsageWindow.cs | 2 +- .../AnimationGeneration/ReactiveObjectAnalyzer.cs | 2 -- Editor/ReactiveObjects/RemoveBlendShapeFromMesh.cs | 3 +-- Editor/SetupOutfit.cs | 2 -- UnitTests~/Animation/AvatarMask/AvatarMaskTest.cs | 8 +++++++- 10 files changed, 16 insertions(+), 16 deletions(-) diff --git a/Editor/Inspector/LogoDisplay.cs b/Editor/Inspector/LogoDisplay.cs index c583b297..43b55051 100644 --- a/Editor/Inspector/LogoDisplay.cs +++ b/Editor/Inspector/LogoDisplay.cs @@ -18,7 +18,7 @@ namespace nadena.dev.modular_avatar.core.editor { return (EditorStyles.label?.lineHeight ?? 0) * 3; } - catch (NullReferenceException e) + catch (NullReferenceException) { // This can happen in early initialization... return 0; diff --git a/Editor/Inspector/MaterialSetter/MaterialSwitchObjectEditor.cs b/Editor/Inspector/MaterialSetter/MaterialSwitchObjectEditor.cs index f789cc29..95013d55 100644 --- a/Editor/Inspector/MaterialSetter/MaterialSwitchObjectEditor.cs +++ b/Editor/Inspector/MaterialSetter/MaterialSwitchObjectEditor.cs @@ -3,7 +3,6 @@ using UnityEditor; using UnityEditor.UIElements; using UnityEngine; -using UnityEngine.UI; using UnityEngine.UIElements; #endregion @@ -148,7 +147,7 @@ namespace nadena.dev.modular_avatar.core.editor.ShapeChanger { return targetObject?.GetComponent()?.sharedMaterials; } - catch (MissingComponentException e) + catch (MissingComponentException) { return null; } diff --git a/Editor/Inspector/Menu/ToggleCreatorShortcut.cs b/Editor/Inspector/Menu/ToggleCreatorShortcut.cs index dfd18712..e549d319 100644 --- a/Editor/Inspector/Menu/ToggleCreatorShortcut.cs +++ b/Editor/Inspector/Menu/ToggleCreatorShortcut.cs @@ -30,7 +30,7 @@ namespace nadena.dev.modular_avatar.core.editor createInstaller = false; } } - catch (MissingComponentException e) + catch (MissingComponentException) { // ignore } diff --git a/Editor/Inspector/ShapeChanger/ChangedShapeEditor.cs b/Editor/Inspector/ShapeChanger/ChangedShapeEditor.cs index 8b17c58a..bb3c84cd 100644 --- a/Editor/Inspector/ShapeChanger/ChangedShapeEditor.cs +++ b/Editor/Inspector/ShapeChanger/ChangedShapeEditor.cs @@ -64,7 +64,7 @@ namespace nadena.dev.modular_avatar.core.editor.ShapeChanger .Select(x => mesh.GetBlendShapeName(x)) .ToList(); } - catch (MissingComponentException e) + catch (MissingComponentException) { shapeNames = null; } diff --git a/Editor/OptimizationPasses/GCGameObjectsPass.cs b/Editor/OptimizationPasses/GCGameObjectsPass.cs index 2dae8023..0214494a 100644 --- a/Editor/OptimizationPasses/GCGameObjectsPass.cs +++ b/Editor/OptimizationPasses/GCGameObjectsPass.cs @@ -2,7 +2,7 @@ using System.Collections.Generic; using UnityEditor; using UnityEngine; - +using Object = UnityEngine.Object; #if MA_VRCSDK3_AVATARS using VRC.SDK3.Dynamics.PhysBone.Components; #endif @@ -123,7 +123,7 @@ namespace nadena.dev.modular_avatar.core.editor } } } - catch (MissingComponentException _) + catch (MissingComponentException) { // No animator? weird. Move on. } @@ -194,7 +194,7 @@ namespace nadena.dev.modular_avatar.core.editor { if (!referencedGameObjects.Contains(go)) { - UnityEngine.Object.DestroyImmediate(go); + Object.DestroyImmediate(go); } } } diff --git a/Editor/ParamsUsage/ParamsUsageWindow.cs b/Editor/ParamsUsage/ParamsUsageWindow.cs index 4d8f58ee..a7943a77 100644 --- a/Editor/ParamsUsage/ParamsUsageWindow.cs +++ b/Editor/ParamsUsage/ParamsUsageWindow.cs @@ -109,7 +109,7 @@ namespace nadena.dev.modular_avatar.core.editor { return uxml != null && EditorStyles.label != null; } - catch (NullReferenceException _) + catch (NullReferenceException) { return false; } diff --git a/Editor/ReactiveObjects/AnimationGeneration/ReactiveObjectAnalyzer.cs b/Editor/ReactiveObjects/AnimationGeneration/ReactiveObjectAnalyzer.cs index 42f11821..b7482b27 100644 --- a/Editor/ReactiveObjects/AnimationGeneration/ReactiveObjectAnalyzer.cs +++ b/Editor/ReactiveObjects/AnimationGeneration/ReactiveObjectAnalyzer.cs @@ -157,9 +157,7 @@ namespace nadena.dev.modular_avatar.core.editor if (condition.ReferenceObject != null && !toggledObjects.Contains(condition.ReferenceObject)) condition.IsConstant = asc.AnimationDatabase.ClipsForPath(asc.PathMappings.GetObjectIdentifier(condition.ReferenceObject)).IsEmpty; - var i = 0; // Remove redundant active conditions. - int retain = 0; actionGroup.ControllingConditions.RemoveAll(c => c.IsConstant && c.InitiallyActive); } diff --git a/Editor/ReactiveObjects/RemoveBlendShapeFromMesh.cs b/Editor/ReactiveObjects/RemoveBlendShapeFromMesh.cs index 25a268df..c1105a64 100644 --- a/Editor/ReactiveObjects/RemoveBlendShapeFromMesh.cs +++ b/Editor/ReactiveObjects/RemoveBlendShapeFromMesh.cs @@ -128,7 +128,7 @@ namespace nadena.dev.modular_avatar.core.editor n_nrm[i] = o_nrm[newToOrigVertIndex[i]]; n_tan[i] = o_tan[newToOrigVertIndex[i]]; } - catch (IndexOutOfRangeException e) + catch (IndexOutOfRangeException) { throw; } @@ -250,7 +250,6 @@ namespace nadena.dev.modular_avatar.core.editor { List n2o = new List(toRetainVertices.Length); List o2n = new List(toRetainVertices.Length); - int i = 0; for (int j = 0; j < toRetainVertices.Length; j++) { diff --git a/Editor/SetupOutfit.cs b/Editor/SetupOutfit.cs index 6c263c89..922fbc74 100644 --- a/Editor/SetupOutfit.cs +++ b/Editor/SetupOutfit.cs @@ -385,8 +385,6 @@ namespace nadena.dev.modular_avatar.core.editor private static bool ValidateSetupOutfit(GameObject gameObj) { - Object obj; - if (gameObj == null) { errorHeader = S("setup_outfit.err.header.notarget"); diff --git a/UnitTests~/Animation/AvatarMask/AvatarMaskTest.cs b/UnitTests~/Animation/AvatarMask/AvatarMaskTest.cs index aec7e15a..897e323f 100644 --- a/UnitTests~/Animation/AvatarMask/AvatarMaskTest.cs +++ b/UnitTests~/Animation/AvatarMask/AvatarMaskTest.cs @@ -1,4 +1,5 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; using System.Linq; using nadena.dev.ndmf; using NUnit.Framework; @@ -28,6 +29,11 @@ namespace modular_avatar_tests return transformMaskElements.SequenceEqual(other.transformMaskElements); } + public override int GetHashCode() + { + return HashCode.Combine(humanoidMaskElements, transformMaskElements); + } + public static ExtractedMask FromAvatarMask(AvatarMask mask) { var so = new SerializedObject(mask); From f3f2de333727faaf2ca9f99c9e712e0073efac5d Mon Sep 17 00:00:00 2001 From: bd_ Date: Sat, 28 Sep 2024 18:17:50 -0700 Subject: [PATCH 44/85] feat: add tracing points for the NDMF preview tracing system --- .github/ProjectRoot/vpm-manifest-2022.json | 2 +- .../AnimationGeneration/PropCache.cs | 78 ++++++++++++++++--- .../ReactiveObjects/Simulator/ROSimulator.cs | 22 +++++- package.json | 2 +- 4 files changed, 91 insertions(+), 13 deletions(-) diff --git a/.github/ProjectRoot/vpm-manifest-2022.json b/.github/ProjectRoot/vpm-manifest-2022.json index cdf4ad72..d4a80444 100644 --- a/.github/ProjectRoot/vpm-manifest-2022.json +++ b/.github/ProjectRoot/vpm-manifest-2022.json @@ -19,7 +19,7 @@ "dependencies": {} }, "nadena.dev.ndmf": { - "version": "1.5.0-rc.8" + "version": "1.5.0-rc.11" } } } \ No newline at end of file diff --git a/Editor/ReactiveObjects/AnimationGeneration/PropCache.cs b/Editor/ReactiveObjects/AnimationGeneration/PropCache.cs index e0063697..ec87a881 100644 --- a/Editor/ReactiveObjects/AnimationGeneration/PropCache.cs +++ b/Editor/ReactiveObjects/AnimationGeneration/PropCache.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using nadena.dev.ndmf.preview; +using nadena.dev.ndmf.preview.trace; namespace nadena.dev.modular_avatar.core.editor { @@ -13,6 +14,7 @@ namespace nadena.dev.modular_avatar.core.editor public Key Key; public Value Value; public string DebugName; + public int Generation; } private readonly string _debugName; @@ -20,6 +22,8 @@ namespace nadena.dev.modular_avatar.core.editor private readonly Func _equalityComparer; private readonly Dictionary _cache = new(); + private static int _generation = 0; + public PropCache(string debugName, Func operatorFunc, Func equalityComparer = null) { @@ -30,41 +34,97 @@ namespace nadena.dev.modular_avatar.core.editor private static void InvalidateEntry(CacheEntry entry) { - var newGenContext = new ComputeContext("PropCache/" + entry.DebugName + " key " + entry.Key); + var newGenContext = new ComputeContext("PropCache/" + entry.DebugName + " key " + FormatKey(entry.Key) + " gen=" + _generation++); var newValue = entry.Owner._operator(newGenContext, entry.Key); - if (entry.Owner._equalityComparer != null && entry.Owner._equalityComparer(entry.Value, newValue)) + if (!entry.ObserverContext.IsInvalidated && entry.Owner._equalityComparer != null && entry.Owner._equalityComparer(entry.Value, newValue)) { + TraceBuffer.RecordTraceEvent( + "PropCache.InvalidateEntry", + (ev) => $"[PropCache/{ev.Arg0}] Value did not change, retaining result (new gen={ev.Arg1})", + entry.DebugName, entry.Generation + ); + entry.GenerateContext = newGenContext; entry.GenerateContext.InvokeOnInvalidate(entry, InvalidateEntry); return; } + var trace = TraceBuffer.RecordTraceEvent( + "PropCache.InvalidateEntry", + (ev) => $"[PropCache/{ev.Arg0}] Value changed, invalidating", + entry.DebugName + ); + entry.Owner._cache.Remove(entry.Key); - entry.ObserverContext.Invalidate(); + using (trace.Scope()) entry.ObserverContext.Invalidate(); } public Value Get(ComputeContext context, Key key) { + TraceEvent ev; + var formattedKey = FormatKey(key); if (!_cache.TryGetValue(key, out var entry) || entry.GenerateContext.IsInvalidated) { - var subContext = new ComputeContext("PropCache/" + _debugName + " key " + key); + var curGen = _generation++; + + var subContext = new ComputeContext("PropCache/" + _debugName + " key " + formattedKey + " gen=" + curGen); entry = new CacheEntry { GenerateContext = subContext, - ObserverContext = new ComputeContext("Observer for PropCache for key " + key), + ObserverContext = new ComputeContext("Observer for PropCache/" + _debugName + " for key " + + formattedKey + " gen=" + curGen), Owner = this, Key = key, - Value = _operator(subContext, key), - DebugName = _debugName + DebugName = _debugName, + Generation = curGen }; + + ev = TraceBuffer.RecordTraceEvent( + "PropCache.Get", + (ev) => + { + var entry_ = (CacheEntry)ev.Arg0; + return + $"[PropCache/{entry_.DebugName}] Cache miss for key {entry_.Key} gen={entry_.Generation} from context {ev.Arg1}"; + }, + entry, context + ); + _cache[key] = entry; - - subContext.InvokeOnInvalidate(entry, InvalidateEntry); + using (ev.Scope()) + { + entry.Value = _operator(subContext, key); + entry.GenerateContext.InvokeOnInvalidate(entry, InvalidateEntry); + } + } + else + { + ev = TraceBuffer.RecordTraceEvent( + "PropCache.Get", + (ev) => + { + var entry_ = (CacheEntry) ev.Arg0; + return $"[PropCache/{entry_.DebugName}] Cache hit for key {entry_.Key} gen={entry_.Generation} from context {ev.Arg1}"; + }, + entry, context + ); } entry.ObserverContext.Invalidates(context); return entry.Value; } + + private static string FormatKey(object obj) + { + if (obj is UnityEngine.Object unityObj) + { + return $"{unityObj.GetHashCode()}#{unityObj}"; + } + else + { + return "" + obj; + } + } } } \ No newline at end of file diff --git a/Editor/ReactiveObjects/Simulator/ROSimulator.cs b/Editor/ReactiveObjects/Simulator/ROSimulator.cs index e34a7a40..c6bee26a 100644 --- a/Editor/ReactiveObjects/Simulator/ROSimulator.cs +++ b/Editor/ReactiveObjects/Simulator/ROSimulator.cs @@ -5,6 +5,7 @@ using System.Linq; using nadena.dev.modular_avatar.ui; using nadena.dev.ndmf.localization; using nadena.dev.ndmf.preview; +using nadena.dev.ndmf.preview.trace; using UnityEditor; using UnityEditor.UIElements; using UnityEngine; @@ -14,8 +15,8 @@ namespace nadena.dev.modular_avatar.core.editor.Simulator { internal class ROSimulator : EditorWindow, IHasCustomMenu { - public static PublishedValue> PropertyOverrides = new(null); - public static PublishedValue> MenuItemOverrides = new(null); + public static PublishedValue> PropertyOverrides = new(null, debugName: "ROSimulator.PropertyOverrides"); + public static PublishedValue> MenuItemOverrides = new(null, debugName: "ROSimulator.MenuItemOverrides"); internal static string ROOT_PATH = "Packages/nadena.dev.modular-avatar/Editor/ReactiveObjects/Simulator/"; private static string USS = ROOT_PATH + "ROSimulator.uss"; @@ -106,6 +107,14 @@ namespace nadena.dev.modular_avatar.core.editor.Simulator private void UpdatePropertyOverride(string prop, bool? enable, float f_val) { + var trace = TraceBuffer.RecordTraceEvent( + "ROSimulator.UpdatePropertyOverride", + (ev) => $"Property {ev.Arg0} set to {ev.Arg1}", + arg0: prop, + arg1: enable == null ? "null" : enable.Value ? f_val : 0f + ); + + using (trace.Scope()) if (enable == null) { PropertyOverrides.Value = PropertyOverrides.Value.Remove(prop); @@ -123,6 +132,15 @@ namespace nadena.dev.modular_avatar.core.editor.Simulator private void UpdateMenuItemOverride(string prop, ModularAvatarMenuItem item, bool? value) { + var trace = TraceBuffer.RecordTraceEvent( + "ROSimulator.UpdateMenuItemOverride", + (ev) => $"MenuItem {ev.Arg0} for prop {ev.Arg1} set to {ev.Arg2}", + arg0: item.gameObject.name, + arg1: prop, + arg2: value == null ? "null" : value.Value ? "true" : "false" + ); + + using (trace.Scope()) if (value == null) { MenuItemOverrides.Value = MenuItemOverrides.Value.Remove(prop); diff --git a/package.json b/package.json index bf79dd83..96eaaecc 100644 --- a/package.json +++ b/package.json @@ -16,6 +16,6 @@ }, "vpmDependencies": { "com.vrchat.avatars": ">=3.7.0", - "nadena.dev.ndmf": ">=1.5.0-rc.10 <2.0.0-a" + "nadena.dev.ndmf": ">=1.5.0-rc.11 <2.0.0-a" } } From 7040e3992b257105674987cd4d411d0e87f69a09 Mon Sep 17 00:00:00 2001 From: bd_ Date: Sat, 28 Sep 2024 19:56:01 -0700 Subject: [PATCH 45/85] fix: ROSimulator UI refresh sometimes gets wedged Closes: #1219 --- .../ReactiveObjects/Simulator/ROSimulator.cs | 30 ++++++++++++++----- 1 file changed, 23 insertions(+), 7 deletions(-) diff --git a/Editor/ReactiveObjects/Simulator/ROSimulator.cs b/Editor/ReactiveObjects/Simulator/ROSimulator.cs index c6bee26a..3aaf3237 100644 --- a/Editor/ReactiveObjects/Simulator/ROSimulator.cs +++ b/Editor/ReactiveObjects/Simulator/ROSimulator.cs @@ -65,27 +65,41 @@ namespace nadena.dev.modular_avatar.core.editor.Simulator private void OnEnable() { - PropertyOverrides.Value = ImmutableDictionary.Empty; - MenuItemOverrides.Value = ImmutableDictionary.Empty; - EditorApplication.delayCall += LoadUI; - Selection.selectionChanged += SelectionChanged; - is_enabled = true; + EditorApplication.delayCall += () => + { + PropertyOverrides.Value = ImmutableDictionary.Empty; + MenuItemOverrides.Value = ImmutableDictionary.Empty; + EditorApplication.delayCall += LoadUI; + EditorApplication.update += PeriodicRefresh; + Selection.selectionChanged += SelectionChanged; + is_enabled = true; + }; } private void OnDisable() { - Selection.selectionChanged -= SelectionChanged; is_enabled = false; // Delay this to ensure that we don't try to change this value from within assembly reload callbacks // (which generates a noisy exception) EditorApplication.delayCall += () => { + Selection.selectionChanged -= SelectionChanged; + EditorApplication.update -= PeriodicRefresh; + PropertyOverrides.Value = null; MenuItemOverrides.Value = null; }; } + private void PeriodicRefresh() + { + if (_refreshPending) + { + RefreshUI(); + } + } + private ComputeContext _lastComputeContext; private GameObject currentSelection; private GUIStyle lockButtonStyle; @@ -102,7 +116,9 @@ namespace nadena.dev.modular_avatar.core.editor.Simulator _refreshPending = true; - EditorApplication.delayCall += RefreshUI; + // For some reason, this seems to get dropped occasionally, resulting in us being wedged with _refreshPending = true. + // Instead, we'll trigger this from EditorApplication.update... + // EditorApplication.delayCall += RefreshUI; } private void UpdatePropertyOverride(string prop, bool? enable, float f_val) From cc93c7e5ed0a197c60e82bc5c70ebf90a44b02c8 Mon Sep 17 00:00:00 2001 From: nekobako Date: Sun, 29 Sep 2024 19:06:28 +0900 Subject: [PATCH 46/85] feat: replace checkboxes in ObjectToggle with dropdowns --- .../ObjectToggle/ObjectSwitcherStyles.uss | 12 ++++++++---- .../ObjectToggle/ToggledObjectEditor.cs | 18 ++++++++++++++++++ .../ObjectToggle/ToggledObjectEditor.uxml | 3 ++- 3 files changed, 28 insertions(+), 5 deletions(-) diff --git a/Editor/Inspector/ObjectToggle/ObjectSwitcherStyles.uss b/Editor/Inspector/ObjectToggle/ObjectSwitcherStyles.uss index e304365a..d4bdedc5 100644 --- a/Editor/Inspector/ObjectToggle/ObjectSwitcherStyles.uss +++ b/Editor/Inspector/ObjectToggle/ObjectSwitcherStyles.uss @@ -39,14 +39,18 @@ margin: 0; } -#f-active { - justify-content: center; -} - #f-object { flex-grow: 1; } +#f-active { + display: none; +} + +#f-active-dropdown { + width: 60px; +} + .drop-area--drag-active > ListView ScrollView { background-color: rgba(0, 255, 255, 0.1); } diff --git a/Editor/Inspector/ObjectToggle/ToggledObjectEditor.cs b/Editor/Inspector/ObjectToggle/ToggledObjectEditor.cs index cdb3e622..3bd1719e 100644 --- a/Editor/Inspector/ObjectToggle/ToggledObjectEditor.cs +++ b/Editor/Inspector/ObjectToggle/ToggledObjectEditor.cs @@ -15,6 +15,9 @@ namespace nadena.dev.modular_avatar.core.editor.ShapeChanger private const string UxmlPath = Root + "ToggledObjectEditor.uxml"; private const string UssPath = Root + "ObjectSwitcherStyles.uss"; + private const string V_On = "ON"; + private const string V_Off = "OFF"; + public override VisualElement CreatePropertyGUI(SerializedProperty property) { var uxml = AssetDatabase.LoadAssetAtPath(UxmlPath).CloneTree(); @@ -24,6 +27,21 @@ namespace nadena.dev.modular_avatar.core.editor.ShapeChanger uxml.styleSheets.Add(uss); uxml.BindProperty(property); + var f_active = uxml.Q("f-active"); + var f_active_dropdown = uxml.Q("f-active-dropdown"); + + f_active_dropdown.choices.Add(V_On); + f_active_dropdown.choices.Add(V_Off); + + f_active.RegisterValueChangedCallback(evt => + { + f_active_dropdown.SetValueWithoutNotify(evt.newValue ? V_On : V_Off); + }); + f_active_dropdown.RegisterValueChangedCallback(evt => + { + f_active.value = evt.newValue == V_On; + }); + return uxml; } } diff --git a/Editor/Inspector/ObjectToggle/ToggledObjectEditor.uxml b/Editor/Inspector/ObjectToggle/ToggledObjectEditor.uxml index 0705c9b5..d3498e82 100644 --- a/Editor/Inspector/ObjectToggle/ToggledObjectEditor.uxml +++ b/Editor/Inspector/ObjectToggle/ToggledObjectEditor.uxml @@ -1,6 +1,7 @@  - + + From 0f28cf7abacd4106393ba7830a7e6b1ecf2e953d Mon Sep 17 00:00:00 2001 From: bd_ Date: Sun, 29 Sep 2024 12:43:07 -0700 Subject: [PATCH 47/85] fix: warning is shown when using FPV on Android --- Editor/Inspector/FirstPersonVisibleEditor.cs | 8 -------- 1 file changed, 8 deletions(-) diff --git a/Editor/Inspector/FirstPersonVisibleEditor.cs b/Editor/Inspector/FirstPersonVisibleEditor.cs index 91052b28..b9646ddb 100644 --- a/Editor/Inspector/FirstPersonVisibleEditor.cs +++ b/Editor/Inspector/FirstPersonVisibleEditor.cs @@ -19,12 +19,6 @@ namespace nadena.dev.modular_avatar.core.editor { var target = (ModularAvatarVisibleHeadAccessory) this.target; - -#if UNITY_ANDROID - EditorGUILayout.HelpBox(Localization.S("fpvisible.quest"), MessageType.Warning); - -#else - if (_validation != null) { var status = _validation.Validate(target); @@ -47,8 +41,6 @@ namespace nadena.dev.modular_avatar.core.editor } } -#endif - Localization.ShowLanguageUI(); } } From cd4cadf23fd4d18cc5dc85d7654cd4173e076eb4 Mon Sep 17 00:00:00 2001 From: bd_ Date: Sun, 29 Sep 2024 12:40:28 -0700 Subject: [PATCH 48/85] docs: add discord link --- docs~/src/css/custom.css | 20 ++++++++++++++++++++ docs~/src/pages/index.tsx | 29 ++++++++++++++++++----------- 2 files changed, 38 insertions(+), 11 deletions(-) diff --git a/docs~/src/css/custom.css b/docs~/src/css/custom.css index c7fa3eb1..4ce92276 100644 --- a/docs~/src/css/custom.css +++ b/docs~/src/css/custom.css @@ -64,4 +64,24 @@ img { aspect-ratio: auto; height: auto; +} + +.discordLink { + display: block; + height: 2em; + object-fit: cover; + padding: 0.1em; +} + +img.button { + /*aspect-ratio: auto;*/ + + height: 100%; + object-fit: cover; + padding: 0; + margin: 0; +} + +.button-group + .button-group { + margin-top: 1em; } \ No newline at end of file diff --git a/docs~/src/pages/index.tsx b/docs~/src/pages/index.tsx index 50dd02de..88796298 100644 --- a/docs~/src/pages/index.tsx +++ b/docs~/src/pages/index.tsx @@ -29,7 +29,7 @@ function HomepageHeader() {

Drag-and-Drop Avatar Assembly

-
+
Tutorials
+
+ + Discord + +
); } export default function Home(): JSX.Element { - const {siteConfig} = useDocusaurusContext(); - return ( - - -
- -
-
+ const {siteConfig} = useDocusaurusContext(); + return ( + + +
+ +
+
); } From 01d75fb284edf03ee275d532466f2ca14b837fd1 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 16 Sep 2024 05:05:16 +0000 Subject: [PATCH 49/85] chore(deps): bump nathanvaughn/actions-cloudflare-purge Bumps [nathanvaughn/actions-cloudflare-purge](https://github.com/nathanvaughn/actions-cloudflare-purge) from aa1121a867565ea71b60f445f441544df0c7b0b9 to cd4afdf666c2e6a6720048f27ac9cbdd664a673a. - [Release notes](https://github.com/nathanvaughn/actions-cloudflare-purge/releases) - [Commits](https://github.com/nathanvaughn/actions-cloudflare-purge/compare/aa1121a867565ea71b60f445f441544df0c7b0b9...cd4afdf666c2e6a6720048f27ac9cbdd664a673a) --- updated-dependencies: - dependency-name: nathanvaughn/actions-cloudflare-purge dependency-type: direct:production ... Signed-off-by: dependabot[bot] --- .github/workflows/deploy-pages.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/deploy-pages.yml b/.github/workflows/deploy-pages.yml index 82bb1ed1..2ee06ea0 100644 --- a/.github/workflows/deploy-pages.yml +++ b/.github/workflows/deploy-pages.yml @@ -122,7 +122,7 @@ jobs: workingDirectory: docs-site~ - name: Purge cache - uses: nathanvaughn/actions-cloudflare-purge@aa1121a867565ea71b60f445f441544df0c7b0b9 + uses: nathanvaughn/actions-cloudflare-purge@cd4afdf666c2e6a6720048f27ac9cbdd664a673a continue-on-error: true with: cf_zone: ${{ secrets.CF_ZONE_ID }} From 848f857728ec1e12cd28e7cdf1a1339a6f72fad9 Mon Sep 17 00:00:00 2001 From: bd_ Date: Sun, 29 Sep 2024 13:15:10 -0700 Subject: [PATCH 50/85] docs: updates to outfit creator documentation --- .../for-outfit-creators/index.md | 28 +++++++++++++++--- .../for-outfit-creators/menu-item-group.png | Bin 0 -> 185713 bytes .../for-outfit-creators/index.md | 28 ++++++++++++++---- .../for-outfit-creators/menu-item-group.png | Bin 0 -> 196799 bytes 4 files changed, 47 insertions(+), 9 deletions(-) create mode 100644 docs~/docs/distributing-prefabs/for-outfit-creators/menu-item-group.png create mode 100644 docs~/i18n/ja/docusaurus-plugin-content-docs/current/distributing-prefabs/for-outfit-creators/menu-item-group.png diff --git a/docs~/docs/distributing-prefabs/for-outfit-creators/index.md b/docs~/docs/distributing-prefabs/for-outfit-creators/index.md index fbb609d3..d814fbd0 100644 --- a/docs~/docs/distributing-prefabs/for-outfit-creators/index.md +++ b/docs~/docs/distributing-prefabs/for-outfit-creators/index.md @@ -5,6 +5,15 @@ compatible with Modular Avatar. Generally, Modular Avatar has been designed to w seen in outfits designed for avatar use, but there is the occasional outfit which does something a bit different. This page may help you understand what Modular Avatar expects, and how to ensure that your outfit works with it. +## tl;dr + +For "modular avatar compatible" outfits, just make sure Setup Outfit works. For "Modular Avatar Preset" outfits, +run "setup outfit" ahead of time, and also consider setting up: + +- Blendshape Sync (to sync body-shape-altering blendshapes from the base avatar) +- Shape Changer (to shrink or hide parts of the base mesh when parts the outfit is enabled) +- Menu Items and Object Toggle (to allow users to toggle parts of the outfit on/off) + ## Compatible vs Preset Before we get started, we should clarify that there are two different levels of support for Modular Avatar. At the @@ -243,6 +252,12 @@ Guidelines](../logo-usage.md) for detailed requirements. You can however go a step further and set up additional things to make things more convenient for your customers. Here's some examples. +### Blendshape Sync + +Some avatars have blendshapes which change the size of various portions of the body. You can use the Blendshape Sync +component to automatically adjust the outfit's blendshapes to match those of the base avatar. This can be useful for +breast size blendshapes, for example. + ### Shrink/hide shapekeys Many avatars have shape keys which can be used to shrink and hide parts of the base mesh, to avoid clipping into the @@ -252,8 +267,13 @@ shrink or hide shape keys when the corresponding object is enabled. This will also respond to animations which turn on/off parts of the outfit, and can even outright _delete_ portions of the mesh, if the Shape Changer object is always enabled. -### Blendshape Sync +### Object Toggles -Some avatars have blendshapes which change the size of various portions of the body. You can use the Blendshape Sync -component to automatically adjust the outfit's blendshapes to match those of the base avatar. This can be useful for -breast size blendshapes, for example. +Many outfits have different parts that can be turned on and off. You can set up a menu for your users to use ahead of +time by configuring `Object Toggle`s. Take a look at [the Object Toggle tutorial](../../tutorials/object_toggle/index.md) +for details on how to set these up. + +You can then combine these into a single submenu; to do this, set up an object as the parent of your toggles that looks +like this: + +![Menu item grouping](menu-item-group.png) \ No newline at end of file diff --git a/docs~/docs/distributing-prefabs/for-outfit-creators/menu-item-group.png b/docs~/docs/distributing-prefabs/for-outfit-creators/menu-item-group.png new file mode 100644 index 0000000000000000000000000000000000000000..2498ee1d4276d673515722fa46d8c0726608bb7c GIT binary patch literal 185713 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%0A0m?Y|G12?~YIuzLI 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�G*caCcczzV#n?x&?+Rsn^_iR}K2BKEzUwYX{=UMMFt9>> zZ(&;xaUQh4+~aX*qQ(lx?1NBOp%xg1@4 z0U2fg?B`58-2GkFnWHFZHXdxk(c|%r8=QG}4wp2hNX#{qy@r&Fn59P_6|UXcWxOg%OBDXDuohHBp368#s7tx* zWMTZ%H`Z`*i@e!8AlNRx?QVJux?sCE&$m6e;pC9vP>0vi@5J8$@jXv@{&Ht*jb2dB z>nzmr`$6}Gc;>{9>+~c|PLMd$|BRzRD5OonbGq%3-DN0=9M9-{eSuADI)QMKF@auP z;@^PCcYhJX>n5rZFUCK1&vDf@d_Y1>(W2yJ)Y&%(hfpSLGpsYyQAl)pSkVK3)<{v9 zF!%B284{!q5cH0gDNtKoxlLN+ZealQ=`td}Sb=?V2_hVXZxj{r-w{xc4mtw=4Sh@% z0RA))gs*hn=&(WbVJP25VB4IIHhHIh(G)V5wwR$q80KsJ3$-9(7`8s6TKk^ zSmv=dGlOH#klLZ~B-Fo&k0=Ymc=JRGbPa|XVFt~3#hlHMW)b8!K^N!}P>(va!He0K zhk2}F!uj_FDQW}@Gej}CadzEjTzqYot0`3p9c^It`HLo z9}Y2=H6}9@UwYF4(K@#_52gPCfb;8u#3=~>Kx}OfhDa2O4Kd!SqU1=FV94X@(x93i zl!XPjU<-6XQ&_;&kWvWZw#MNWi8W_l{U!&pEtAWF3nL(ZCbHZB>dJQxA%W$0sod4;G$W^|}A)0Zlo?Y1NrYC%qL?U8>;{h!;cJhkSM zaB6c$^M)S`z-LeWsjuB3Nq?@&xnG~i@|dQhS>R9H30LPud&>9VUrQgbFJ2S-bv;(8 zW!Ta_T0`N6Oxe~zsc%^f!?B`?5TSfp%c48=F|`SqcC%R-Ue_2Eo$7MuzV@iRcFMh8 zx>fwM#JBcES_tncrLPb}l5FL*Ci)@uK0v|Z{&l{v2}MYrc_LEz@Rje%s2v!(V!j@N zB6LeU2)a`Ib*(FNNLnGel6&;_!b`_jBGYu9uI24w6H&tPQ96wfLN9*JiGfdDxfoW3 ziS+v2t6YlLPN^@4(8;18h`<~VoBEWS@pC6Cm4}T2ks|**z0^6~rZ3hCfgBi^co!Xe zc8gkdf(y=0wI(E-Im6}gr0^K5OUjqSBU->>#q$pLjRjWrT)2L6U98)QM=#U~w5|kg zy_XNzUR_PNvn%{n@e2%thiu@JUj>tF>(KSYDfk!nNKFsTSj(+nb!LuQgkZ0%BQ1WJ zOs(#iZQ!~$sPwB%W#A54^DT*iv>LbF%gN90>cn4@Zxb~B`RsfMZ-6m;wu9|2R}^Tw z(tjXp=VHbeKz2Eh)KE~5Z8-MSoVWI9UWMGD*`;1+q!mFjf<2zoGLV(V@`RgSxOnyc zb``W|xZ^?hF%_6Rdta^%(i@$K*DpiVhIhHRRtPVJhGl!yZDozyKcc?80JE|5@y*6x zcR=9T;?hKnW_7s6uG3n-J0r(%ro(yaNh^AI`~g(y97lq$7)VpVIT;B_&I*4%Ko04o zizWbIP2ibDucSYseEBehcj>+Nf{&QeJD;Wh#nxLuRnkT{e` zNr{ru($XDDa|r2>LmUJI1PKvDq`O2Ar9mu81qAV~&HH`-{qGoejCTwXc{%%>y`Se< zYtFgmL_IL#Be{mge7Pa>1bz0&1@6&i$osm~xTZ!~l*vyjBfapel!2o$P%-tBPT2~4 z?m6qhFCgQxtAK!g$K~`{3NmQO0|wvrzDiO(6&4S8R`)t#UIkze@;+(3YlY8MFY~?( zOT-v#_ExYevpa#cjwJ~C&cXDomvjBa+};Om&M@h2nPr>t$ix)sD#^6IL6qjU=@wwE zJ=RF(4VC4i=d?gYe1(3q4p`|?+pX!6%yuPgJlX&5$R(#CL# z4**?b)f1gyYe`?l8ub^Z(MiCOM^j7XGI`$NHPD8>S6tN0Z67doC`o^VSe4FYPXn1i zD=M~ABwPbhnx6BPr8T2&@8KOSdDP7$;6x{BlG9jb4591rAAEu&X>`sX|8C4w>F`UB zGnLGpX61{IuM+zjukaQO=orghQF7z;=+b3+rsBzlW2mHG!DQ(hEIM^bnBWo%X!iFT zc@hT*Mg8L8;}dJ*P`<}|HKbsDQQpXDVN>Dk!!+M;w)jh%pnzNig{&*LasS@3sZ$j-Y0@}uNf@zf zeSfgD=^-iO7;lgSnA!0wgOMFukI+Jb0r`v0toF@2{d_&Fi{SW&!l$wE(9KNS74E9P zpeh0$w#~lP?qpBvuoHa>K1AMLQX|dq_la)lX&(RnZZYvXx!!L4X~jBCiH}|rbPB62 zDKrY{SjW4UVmQ$*gV7AGbcxbynN1jy;>upZWsS0!1$;cpa7t|MJvBRe=l4K2cY?<5 zd|AUvXRwTg*Ne813w)5)a4Xka==D2lwx++@9m;%Uxd+I30osr8&{Or&WE?EM;`|*+CeUd(jjm z#cco}eV2`TL3eOB>sD!P4S}2DbT_ z%70fQrY1@>T82fZmH)p`N${%-_-T$tIJn4OqGtu~M3un57z6SO2V#>5Mhv#XNK=sl z-N1DxnM36}smOC8Ey@*ciP6k+-;HDAB{G6KgePY$Tg*^%y-zxBtkFJ;nC3uFVPON+ zxs}3+#(3y@rNtB1Ju$toaB4yi5aBr0vd3;@Bag4V#w)GbHYIaY*IOp@P{(lM1XH>c zUC7XSyY5T^Y1ECZbSuf6XuaE3{zUW)gfg5szouXhChf;Bo)Nx-e=!ty@=&kfjK$aI zD;^a)kJhuaaid%)6!Ngec>>sLaQC@Bu$cdA^z@x z6G;+OYK>zGF%yRHi?Jje5uK-EIMWlq+Cl5^22NYXXT|0>o<_lCU^u6^O3UdMlCf*n z-Djr99J6=sB`YJ>!(6>uRpncG0F@djozFOyDxnvtqO@kM8aHGO7R=d&2-I$s!@HT%SiBidi$utI@Ldb1^jsSxhDy+)?p`q1K$611 zrL!+M9Cd;vFskh^-?eV*9qfx#kc~Xx2BYWEV4@R+L};~LK_?u7G22q$j%oL=M?O1% zq2+wTU7I{zxMk_-{@3FEt6xjrw;TuPoOx_EN*+@n{sd(9x}0g@Pt47lx<`EudafOx zS50KhVw8IZzWH@AI;txbo=hVQS(Y?y&7h-M(O3>q#PtE@_AQe^TC{Je=BCM@0e@{_kCI-Ae z=};f$VU3V!j81TsDEO8#o3ErufzNpD-@!;H)D-7OP7gn(QcQyQ*q-0rFnNfP9KGqH zNCA%<#sE)Ku-S&p7)zvp?T85^3jPLRGQy)UV(@@7K$%X`)!Y|6qIO-8fkcl0n)e*w zX;H%J;KL8|(NI3HNjp}vDM!C;fBc2~JAsH4k((^|2ksI`y>|KS8Irwm^Ei~bCu`v#Whs|;@Q@AgGvzCA%!CN)yK7=(&g^yjZX-5jLMc9LL%WB{BK2l)%E(RY(AIFX?2ma%1&O_Bl2JE#YI1wD_kO@x%AtM_6Lr4yH*<{=B8 zH*_%GtAdClUrXAOlQYgh3q?A)P8=SySGclId*dRmo!m9>)%S7rJ>aOOj?~&_P zvAsNHxfcXsr*wloAPT8s?5J%bPQ$R4BVv4QCDB2AIhWFDCl~a>yHq5XPWkQhU5)`u z6mCYKgN4=mJUtV*Bd1kDE#KEz_T?{${|W?WdWwI4=l?MQKf3PAKtK)Npz*$gP`#m^ zGy9%v|1W9>p!ZV{&*) zx(nT3_cz*4`mwBIuzQSG{`AFVRDn|3ofj>`t#o%8>1Cw8*H0{sh>dpqW$f9W8b*$4 z>et+>P`*=#xI(K`E1XX#^qKDFN}}o!A%im|n9b%JUn|CBK$|ATi)55v4&W4DgT^;$ zcQEA7M8TziH6()W?O4dLt%S^H0x|T)FiOhpZZ5k!IBLArk)OfOajrvqY|bg1qNkYr zvp|P`*^3hr&m5XpGvbOXZ1U17aO)iEf519OoKU))^tysAq<$snD{*@uwkSQ$M6p54 zK#wkh;vg>MRwYD#Nct3VXK39{TWbyZ!gJGJx~m}r$J=GGj409$z6fla{Qf$9rI~B$ zETM_ix;_Du^g1zWC-nnQBA>*Bv!VzzM0#hEhvh8aL`uo@K3qoJ^5#SvEzTx5t%Xk9 zL~0{U0B=NLKNL+4r~*~9b%vS1)?u&q#8=WmR8yz7P5!b@+VomrNb`GnN|gOt5? zj+Ae;M&wAozXIM_nDlgR0fB6JR*F1D-gji>`xQt+SHEXx8$x{;2xcv+t#-O*4+lx> z%z8t)&sGP4!Erxy}pkXvDwg1swS69}EQ|$D& zj|RzM+O|RTC9G2t@5l#|;wTv)U+NKg-?=0(@b6?)o1o8;zPLnk^~m$?sZvV}=Q5tV(!S52~SO z%*5;dNhNZ%pDQP9Y;LcBJtxZff|0!xG-uX5m2?D8JWpSr)A@HB>#sPP9!5LNG8J;)N#BbpG9n%5+kr#cKYzXQHNBM{`j1Xk+j_XE-Q)WJh@W-f!wFNRfWx>)p zl=!l!kUxMC01Hu1%w{nml2tSPP;A^K&+=5bcBc<12uLr3k&|Eklu>W? z0^%n2^=MKr z-r8=WGgiR24)6Ov_Z>>FPT@2xPT^3Ch9j8MPNjtJQZ4U=Yt2K!$n6@f224(vsxz?3 zF+(7l9bLiVaGSK$!T>)C-;<%sgo=2u>h&F>gdo+62RVA%$Diqt6wJQ-=JCpeZmi~% z$b(?;5!)80`p|*-LjOzD!%3*7?kpY|>Swc#%m&ssKb7l@2m^)8=R!Kl1=&?|&aYwL za9;JPwl|6WZJd^bex2FyA`3qwI}D~=V{XIem}JCg1cpoF*8dFM555?|C-lO@R^ww{V8|_)oDlyV81U5qHlPoS)&ZY*k_no6=|+ zt`i~M31S}d`xodlx!4<{B~cyLYEdWgx?QbBi(fz4L;r^#KXdAILEAN4l|x01prY!q zcQ}esQz#YJxRI8j1nGVE+p;cG=Ekkw^ZZ~||9B^_N0w$fY>j{82)1Viq#AEDC4q8W z;2@lFNbzceS`xFnHzhvjP}ef$-NMdMV>jqdCJ_~#xd~QUBd9G9;(MvCa(HRzQCV;; zC>It}t@_FhsmQ>P%rln9f6`|wG%A^|E2QxFPf@M7wZuZXJc+N>%oeT|NT1Ok(pCxeOvWTGjjKQb)XROKq@-p`wDsvQum)G{7)G!LgDD=NV~Dj zzy0}VYz7;{Dv0G1v*a+boeil|4~gt|u1-%lTAmc=-jC81#tHqatPC$0`QO}4kyfgr zz*SlE8aGRnmSd-H1l!#*G99h#V?$RsLN{W77MnDYsBb7!SJyLBAUung2&T)I0(PEn z*)#udTfvF0aG_yNM+$#5Z%P)@TG?HS!D?99hC&rC?j%l$u6O`;mt?mgNTaU(hgZ5R z6jypdaERdah};l>tO%mGYEuN!yyS{Y05C=U`1n$C_TGb&kH^4LY?vIHsa^NKD>D7R z>P?aM2^S3_Hy#N=Xia!{38gr3woQpf6KU6w^*vP%5gjowlPbdxEwv@=LpOeFz_+iQ zEPnbK>h}GvD{n4n@~3>``SkzxB+HO7%e3A^!63meUxv*vvy7sC!*aY86aE1~pjLX{ zc|#y*G~Q`K&PGmjl(DY?fG>`hId9Ei&ggWw@$E@%GR%=6CCBIQm1AebR}L5T6iA;V zIRVR{E9Z;>gPl#{wSb?W&xd4uKq?iQ+g@WU?~aW9ENi=HG+n9hz5Mpu@oor!8Vx&I_XnQ*93CfvJ56iqHe5e z|1H`_UqQ+EJv;q8Owk%6P5l=mCq)X?(6cb94)%B5TTsqKfd`zFD}mJh`0!(wv9_SY z8i+uNQK2#6oC5%6TWZwuNvENGF+~sT1@sIQ7>&nQdQ;*S-oWtxvR`hT)-psniG70_ z&ax!kh~$IwbM0K!?&cdA)b_7aiy9C(USPkfM)&iTr5 z^a8KS!+9`U^AqXi#EBc|CwFF_oI)JWyu|3XR|n+d#@-2AcXKwj^*lZVXpypP8PRQ= zQ48}FZirfVNY6MP-dQgejzapKPVn$K4?y>Plr3}v`7JWY5kwY!v?kg9=mQK3(?Ie= z?%dT|a1pb>Ojw;|4RZYwMQLA4REu3>E%%419jdvecB7L;qy^b|&-ZuXPRBmY$8ykU z-D3NG^n64;KVvnj9+2JDq;L z>Z?eEv&8$m5pk~5QhNU8pl~zM!xI_+YLGaNqQbUbq>+T#&OBc; zjD|Z>o|4rCz90G9@a6>cLVDqDd=sQ1)Y89~y^2r*FXlW3PB7Ny9jetQ*4Nh~7YLb( z;Mu<{3$SWmG1W70o7f#1dOYc$iF)Iwv)IaC+TfNiI+Q>rh@VX$PzS=Q^dkw$fu}fY zkDKL5>zAxoAj`}CeN*X{FUEjZM483^bJ2n0pVH2DgyYRy*-@WPQL)xd4YFCY$nWLS+5M_o_(X%b_zCxsHQ_@K6<1x(9 z_`=+0>a|s3U%I@ci8UzgygF5Bh<}B0;-u{dkm)CK@u>Yim*3MDPBth!hqY#XHRDH% zP$@iAQ8K|h6ThPu5HW?yHe*a~VZnAiuPniyiCFT9cUu!w9MI4pkTHphvd%P8)fIUf z^6$9sz9&l=yiegL{oYYHUMdzH$qaih9tX65;vr|AV9yQLX%zB8hD0U|RObSLRzR%{ zH4<>V1(4Gvx55LU_U7>L`cvm^3QyO7G^QtB0H7{vz0B}#BJKvC-q~5G4>}=Jm-;k4 z71?T&0X%B#O*_D!^rRa~B^nZC%J1$L{F6oc|Gt};Nm*o`qzMdKmqtu&kiwCquowaF zx(St}QN)#P9`7w+9XeiuV0*b<*oe6a5VcMaJ+VYnFrg-1>JvyKlgPf> z@8Kc0su5`ny#ufNB>$Y|lwRC2NGxLcDwC;|P8ncKc^h?f1soulsX&VC`qZA|yZ5cv z(Rv?#ZHD~2dW=oILrg$wjKfmKlISTH8_x$l>qaqB5!!h9AYG+g)XkbSvIH=!kem^v z_5A6_uj+{Gnk;eWm*6ntQd4&%Hsb8da~)>{8vzpN>yz}~^=|d5jI!q~CxY}?6mfH2 zgyA{u-&7B@0}KM?ze5OM?zkSe8!Tpw zK|*ddJDl_aci}{LZs57Ab&t*dgYnjrOlwZutQ*s+zp23gqMqW4cf(qw1pD~WC5tV6 zzfu?Yp$u8{qK517Y>9;efdDf|O!`1WZ-YB?ki<>$D7TXTLpWnO;*cSDyJrZty6+IzV1`)s%x)i8bz0_UNdVYwbDL=p$ zK>tC4>@7>s2?#G2r>#Ey0J%GdU3^vbdY>WBtgcZa6Urw&hU=X+aG)pPF`#&VVSz^V zd;GZAUEhgZyn*T60#sH})xu;o;FuwP3566YD)$*j=C}7sSet5Kv0Q45RWplnmdtph zT~+gj#PE*O+mr3F`|&l03Y-e*d*58ra9i zKx^&GxZ7t)FCO&jZPd<{5(b2gLtcmNX=R;8CK#n;O1PNTmHDaTZd*O#TKc*qUdo`D zlOZdynHNuvFIz83G>2sE-nu>fGwItg?CNr@AV=uCGaPgqF^lwFPLO;9wqMLh*S-bf z@NNlJnJT*oatR{vpLJ~w&ai?CWVfNw-g=e682y2u9<2e~v@wA8mH0lCn1QyDWgwsJ)`@k9w8~9GI|%7bqbisO6UmBD6Ca34p&u+B_uvXXlk1q8whp0 zpO3JOHa8x6y3E+yY~R;fJ_{&UV$LKAc=6}4HiGC2bgXw5IHqA(*?2td93hFlB$l3$ zOjXE*lcm}LP%96_b@>gDznE9M)?1$ev^WR!uutpI-e0&JrjWCE(NJTH%XTBCai^Ki zGW*{3T}e^15(?Y=YE?FD3{O86)%{sZB0X&$En4EPU|raZM-hI;=7EhcMwz3c1dpOl z;5~QbZ`hqBoyD-G7(>NNm%^A(%JG@cAoa=pT3A8DJ5xS+iPHjq5BJU?SaUJnW#E~I z3Kb*XfbAb+1Zl~_VfqWjB7wb^c`y2y9?YFbVsM(yzxIXmXlWBFwEJW-&d}>@zs%j- z1pGpfF>tG+@6IjS|B86r6ERjjF;0?%_qsPCC_;(^auPLA8<3{OQr3tiq6BxJOU+ZV zHjZ0O0LA97dq+&mLBp_Ov{A0CR2Z?>v1@bfZ0Rl;gG8mJ^;_U*h8o6H8KQs+mDicy z|2c6Z^;H)=80(N-rjVhAqwn>!*3sZ|N+ z4-pb)=fBp|SBQ@yy(d zjuYvF$~9u&T(5ETc0lH-vwXQ?JxFKvT%OcLOMfWl#n}<^aDHc=FLotaO!aaV4Z2N8 z^V}c#nm}Kux4Ks)L#d5qDTsEVpGvu2~*6i%Fx(CBN{(*tc6wxr;hU)tHRxsL=H_T4P8 z)^M^mb7k|?y%#Zsro$F$D|d6vk5F-*nJ}A}W!35!qWElZ@#O9iCtSckUCD`w3);}& z&|Z|vD6(~Em^08N@zo=WZ?3m78Kq-`VE_}#Nj%HQnDySOHVYkWXPwRMmK1hAw4R(F zoJ@$b7Q<;mHI^VRGI`yQWmpyk_xl}r@<9_$SI=E92dHCTil?x>$lceWQsU_eTI90~ zN5em}yt2QYunqT6nnfGsq}eB*P-u5YQt;2>@Tk_z&i+aA($Ez?h3qAFxCu1ZCE~)n z2|2j2nLCUdL0b1L{n0W(B_;OeRWD{8g&9g}ahC+TG=#OjvW=#=YUQE7h5)B>B|mVd z&ke~%n~x!*zW~lGtY%X_Sy*+N#NO{cF360b(!T z2GUH|lS{m3wYyUZRKuA@q!?_AMua)XOfKY(?xUBiUPsKbezVr#A5mdg1c?PH_|nHu z-1a3C(cy73B_p)<01T>jhuU`iuW*xc4%WbC_{HImGu<>)3Du4nRbO}kyW_Ve#6Oj; z@H$kBj=x^ns2~USng`XnO@F;t@B}qWyTcs@*>^VkM47!3P z?#uWJV(;yJu_o*Zi|>^NhBa2NztC$Ve8HK1dj2b!)yk7(NxaB4_7ABzj)Ua${xEL$ z*7hF5q5S2-T2MoEIS4O!Uua_82m9{HeYwFxvJPSqtpkdCl#zy$bTtdXBD%3mX{--Z zKYV(Ukp9eqJ_)T&S=yf#>(Gj9j)qmBpTamM!84U^z}?%SVfXVs{abG82qv;YCdCtU1y*UA?u)K)dQ=N7fk5m>sr>fkO~Xv&i9~qkEa5#fOn-utW>E`f zvUNdTM5Nc0+h^JLSa5#l*`Iu*wlf^s;KlGp;lHk=Qn>nD_uh4khDvBeD8WFt*_^MS zlgA3ODSb&ruIGAT1beVU*>#L5J9)OA@#LwVJ+lAn-!a%(yTzL)g(&s{uoUro2DD&4|u?_>=p;95GT)lY}K8oG+nd=Cvzm zm-F5+AWEV%y6rthw`ENEUs-KPXTk`Dwb*Mmoc1zGP4Dz{tN-2q0q(|zfSbSE$cg*D zWZEPCjQOO6PxspVBD5uKvn@AKd!cUUAb`dBeXWl3@)hkB3=Y0V!3qFsKS2j2N zgxh_fKO`RzXfy}sE9Jn=jqWr&5DH{C&ci^W=z*;wH7gHI0+hdhvt<1|j%MKa-G4rZ zcn#J3r!Ct9d02O$3J-z+(7i z=4=qpEGIK_(Tb2{h7-WUJE?Ld9LhF;btGjm0z+s9mZPd3BXiRs04&5XxHho`f|{|< z0_UANC&mio0(^XdHP2>Rcn^5e^3Ht|M2bK* zSuggw(twsDUx#=p^|+_W7sIe*Fdc#qx`gK`HT?4Ly$U z1JOQ_^MDRkV8F65o0NAl5L&Wg7n0VZ82rabpxW0Q*B(5XckJH>6xh6(RY;SEzG^~2(=poej6F5u? zgq}r_L}PfipWgY)YYt_)B_t)d-w`GvYz42gMffbVe-ElqhQ|}tDI=DYh;I(pUS!S5 zhIv^VvDkbABl1f>X+>0#jzTIua`3|1>z!8pQY~UcLP=}kYssH!`o(&komDx-P<})y zfh+uKa{?bu4^VhqK9yN&LaH-YIwK8zSe$WX zY9Snk#HB&H>rdz^_uYU~i3X*du-)~QSrEf5^9oj0DE;A1poA^sRrwTqZ~3XGPsbki z={&QH?N7Y=gYFuwhyXJXV@>UoJvzcw(S~M3rK7KTsooZLfr(}zJ z;M49a?U$rRzRFtbfJ zw9<|P)y3dr>aq5ae@)>7kRr#DWDT0S$WSdJl(4o74?e|_HqG8{F8|m5&)WVWxTK*6 zdx$U*-azB~loijFZKQnIf*o$8F@;MhdtNXz^OO+Ft$kyyN zMS2+#$b42fvKpRdz01NB^u<{$%9Kuvf$eD+wMiXa7_{iO-ynetq&}D~#ZokGU``@h zh84zx6N@Fq6td&GiRq<~H9NQO45}>`)`=%Hprzu(k%8MVwZtdiWn(STJ8~p?SMK<& zrq@7T(TadVHoMC%q;~2R_$~mc}ha7LfDqeIXmP-L|NjZ3Ew<@g`1vA<;7MJOdBBN$5Shd-;Y&lmT`AhnL9u(o;o3y&|KD#x;x#NSc$g1iiARB#Z4AJV5}@*KH;NmFLw^77i*XIUC}5f{ z2XHmmT3o??S(2WSG4=dkaUrQ9g#|}KF#^k|-l(a9A>ukoy_H&;@P$yr>GNB&WJRNktKNF()pp- zG{U(UfzSsiAphUr=qcoWjsm<$`}PAO;(8D4!}4bHr5pK-%!uM(0^2=91OwSNFb zj=dDbIh}|TS{`gNpYR^t^u@R0bCE`D`!^!`0J^t!|LPA=jqjU$hkdIEs8dU@-*8Vm zv#~50ZG8jGaNXddW5B-ia=`jD6j7tFDQvwnyPuvWk=y0O0wV)Z%+O-w=8G*&%O|?; zjlFkD?JpXij+=xZV*1y<`%h+G-2t|_{MdC;segK{-2jiSZyy~)!;|`IS3|9iVfmok z@z#bX#?u|NeLAk<-@$K}9JFy(N3Xc%m!tU0J;yhA{oqN!{+XnSU<@p}7_ZK7DGH@7 zd+G2c3>hHn8_Cgq`xkm%2gadAcaWaPxB-gO{WpHL8bq)sA}Vl9AqP6*Uhd^wA6L5&V+5h@p+PJx-s+rBNZ*{LJYn~M0t^OSkIsdjmCoKBr05Cd zoQ6;yO2l;;k$WNHy=c-atwL@0FNq4GOr7S|{S`VZ!^Ge)>`}#`iP3PAq%QxPg2o4!cS|L2#0`S)NcMqUK zSej3k+lJfQ^TrWTLhnx$98>+v=<$d0$(keje37A%30LdSan0I?vp}|<&`i+@C;I&w zcz(NjmOP7v>t`LGc8#&31mmT&GlkfkK}2;TjM}{N(tQpFG3DojK{TKh;{evi3FPHa zRb7!kMzDm_41ub1BdVR4Zy9ilgnoXVzTcK`lUttjQ$R}+;RGaLEze(IMK{8zZdbQJ zh;l@2Ek&LIMS6>cjk{p#_Af~Nj1qrm%wchjD6w>1x5Ztqa9J_tQ4bOlzNESyvwI9^ z>p7q+eLIim1cJ29V`NzjpYjIj?7ULd4O^y*XT6(zp8=GVvNwF4hX*nOlWr|bqYqhu zO)!hbOE3>KvMJqaPK(_`wm^faS-s?lY$`+_dZdE{yIYT*f(Khn0sx_z8sR4$4<`U2 zpxRu&Z!a{qg_l4X&UnHzYqN$@P>{2Tu)mjzCOnTvg;I;BtSwNb=oyoGQlv7<_Hx^l zxXBIVu&hKK%iwpmYuQD8D?T9wp;;yBe6__0{p1o{T50RNh#ZrDw{;LQyxo(5gf+UR zqM{y8(b-P<7f2UWI%~&ZHRFOS$%qYk08=57--^dl;|Qr7UK8B2Z!O`l)#Eb!;-9kg z?-ytjFQ|!1-L+7U79PIcssu>Lsv5Vk;wUiRM>j4qe;mKI-F7V z?7Rb`+JgLi_d&N`I-&IF+~&5U>}502UQ48nGsTNiz9IK(a^H5?>w>D9rlOAuBqv!Z zu-&dmED+1q6C)a*9H%O7Kx|Xz#=$P#|IVxl8kW4pB9w%#?}_Y_i?&CV&vB^@=6z9C zi1a%YtM?7W7X=3zhrw=Ex)fJ28KS#Fx4B*xOe4oLqDAiN;VisvT|-6iI#a?EIM_%~ zW=cq$%2DD-ueUgsgM!#jE#A=3)Z-N^okkBU`S7?2>zVv|pW&&CI#O)M!`;j47NT?? zZ$mj{eK}F*Rcaufcw~m7^{&?l-gN|T{a8}&U z2Pl?-O`-6Vr$4ueY!F<_-I2sB+YQ)ox>)iw*=i!q^u6Z(3& z7blz8_Iru0m;e&x1J3wwzdfZYt|XAkip30%-4HED(C_!#MGx8c{sFtFb?j)7pHu&Zj!b1nlH@5eG`RJgK0xiDWR?&7B4xp=_N^1cZyxc{lhf;G$8MQh; ziKGB5&6$m>0$X>uFGV2A{VrWwv1|;(uu?eD>EY?Dbq-xypg@3o?%d3SZ9P}C@q* z1iBmQt7gJcUdIs>GTg`%*=7Y9+~q31J?X5tO-p2S_T%LyGt&1+kw=c{ho5pl$u#hf50lZ^4t>u} zKGrZ5VA!a^)w{p#C1cP>*TK=AxCKJj5=-mrdoai!%hA%B@5PzfeeTRa=3znH`hxd8 zVVShj{^zwV%DhZC_E*eaEksYY+DO<~mHK6iwHKb3-t3uQd*ZI%nO^aW%3zT2;r`tF z5l?+BL%8Ry7NP86pjWZ+aB@vf^OxRG9ZfOtb|kRb^Q;z8Sp}yGho(}uzeUFiE$)Kh zm37~ORRi?lUVE>~U*26jOpCAZ8qm2qRMtGdTt4kN{-zii<#38pLvPp>|AEppYeb_n z(rY_VAFWUvb~DrbTXFAYaz+_e0($O#^g`$#MlT&ADJ(aIDrIDI^JMScsSEOwG7^<( z3T08#%2VDbND{mQeO|5g^`ZEB-mB%Eim^YC4umBx%?D-Wj2P`W6OA`5d5@)7QOB6e zUh~{PAnWU8{Sbk>0&J`~zgE9$$8#!jVUz=v*2;WTeSn_Zgl**RqG(AbeH4vfRp6yc zdF4|N3rt#lN(Z)lxyWginTm z+;}aoz(#-TRj(?WZt271D3uq4>v#>4rhnuT9c3;H$nqli0*I(isehM;R&{B!4**vj4fjVLeXb!t9In|0?>bu1pYPAL^ z1Feq5Uz;G+w*>j@jl|5Ww9+36Q+cb*r{lUQYdG!IMkFRsi z=Rnw~ai^-?b(zA{sqxKi1G)TE1iGj=H7>*RrN`i$Drf&AeA{>|R5lH?ag6-R{#g=TTEu9V2Yq;&bg!>^>Z6N@uB35QbKmGlPd;3(>ybC z)P}=eNJblVHIGW~JH6bR`6A;b&*k#s#8{5@)itQ3Zs9yJp`9?dbm27hj6hC$7Vr9= z@2k92WT*&6sB)??Dwo6kskI$=r_xX1O(T0ew-t0lDDt3*abS<{>yGGD)WRERx|eG~@E<#(X&qx=TAG*4^XB0e z(&m>9)g%pHZo0bIHryU(}(5NFn0XC{|A7T|uZ z+D$Zq_vvZ^fB4mS-|g%=JZ1~pXVw6`#gf-R#U@UuNwO%uV=Q~`&#_;E*zxBhaS1t9 zN1Vo;E3dt%hdoOly9v56E%NkGrIm8{Fp4D5o^X7nNj)JPveQ#wA}f!eqEX?`>Nihit*>QwG=HQUQJc!vC`hIHS`w|&W;@Xlia+1UN{1$= ztP?T&BbQ&1;fYxvcDX;+Z8fVcID5+GX|lH-@2vWN_&ZHFBcpOm{`n+56k1H(UUu}9 z!#8nt$E&Rt>Qh~wb>8*=1Hd;>Iuwf~(hV)fHUFmwu+R(I@@F%o9qD_~^Pid|3jV-w zQiII%q=VLbgdkDyB~}6%=SG@p$BW3fCJA`UH35hAs`{9CGBd!z9rzLBy$Ew_U+BM= zzcW`qQ8gqW(hWM$lVr+xSI{%T|E}`n!Cc-H^wp6YLAMK9<);n6F`FIqXpcQ81Mc#bj%2eD)=OML*?&+_g^P_9RCH-52t-I6gZjXxDzmt%?LLSCunG$ z9C7MwNYC6j!T|(uq4k=Fvc>s)z><~WbNOvT>7D+!LUjuk1# zoIvjZ27-5jei_oq2l@_bl<3;mmNzQ01Rrd)nj*YNl3@3FZ_Z{*?>F-w~d4m4*xTrqv0=dCq%lbdswr_{2 zTfdgBSklh1wDXqVY{qs!EzdYy>`dj*w^(;@3n4qIJcqA%A>5ehe z3o1%fC@GyoH-zIZF}T#&obVOhsngtZ`?o_eWYY=TC$2;DIoB>&V$Bh9wer&0LsY%u_Y<`KXfR z;+3ArD7&E?(?ji~w#6Kk!?*JvhVtoUZtRQIYogA=P@=!Fb%MCn-*YcOrg@3*jBn7O z_L=!8WG0MJ8q6TI=6dG0|3IV@?frHALE-f4x^@tQK!(TyHlwCHyIs~y)}KSXXm@iH z5{6V)c0h9{a9ao>lo1KA&5a2Jn0W8@bfx7O7!(U*00SAm3>)AV$c5EvVEr0@w_8hZ z`3Hca8M2)i?%&$k?OWPi^jx?+eGd0&OKw0s>1!9FcOB^f_@xI&F=<=)q7xhpQSD_U zw$5((KENt98_FXibaN6jHmQCup#8au#O(InTNt7bY&`uYG#~=D4;) z5RDqf^vlaDOEXL%l(R$m)G|Th!h=6*+%i9jmn9p$jC#}f(LaV_qAV)PF8JbUHWLEv z{W>Vprk8&sP64VE#b!Vd$MtNL{DVe466g-@PlO@UlL`vLJqF|Bnpc<@s!}g$$2R)O z5jc`i2bOdIHB?YX%~a-Vf=lXhsClfIg>5S_61Vj87v(>5De~GKForWdW z_zn(M{(vl`6SNqabC@q@^9;iS3j%l0N5}n42kR1t%>~QZIfkR==1KHYO#sKN&mc4O zD-U-To3mRk?Yz>}7%ie~+ne~U+)RcN;|`WUR5x{HGXEjTc2_3Z2&H9$<#_6IM6YUX z&hibKd_L6K8H{=vMV}WCov7av^INoy`1yyC`Cc~4*X1-HfLEr0VUY%@FPcVbjsX1l zspUCPiEu?G=mg1kF)E*qKc9tYoMCgUUsPEyu(p?_o}lCEO-alxqr+PYT0IQ-eQ}fr zTRWY()G!t{G_AW5G&(c1B)m~089m+4%|4R%EG0WwURGiTKS5lNm`n@QS&5UYgv7qz z0?G9)SVmH&-a9S%exjw5(+p8-{-h~=%)}6I+iv3zl?4k!kIg@czc1%T z;ypuO-*C0doP2lw+se_9-IYg+8VZRYZh|7Jnw~0dG-1M#k%(paqVQQ zefnsFcV67c&gTbx+ikDDnl0>2HvUQZ!6U`#tq9!m8zs^8(vNy>Xt_jY|)r+3tF}}a`orMBS!JTj*!@xrK)(EV<=YrU!p2`0xwEiEc~+q^5m(o zbnfxvn&Y30;cQW7Tu#f_ZIm-WT!x(~d4g`~)Yc4TGCHYGB_f&1CZlYijrsVt-~FRp z(6h~*lWCxO!V#2p2=*48EBQ+n9MA5r;neBno59g zkzY6g)_=nO7y-?`ms(uh3>$eklAtO{?xo5%@XNw^H^!@`Y}09;Pvt|P;*!!K+V5B^%0$GlK4up=l%^Jz0~{_zWex8 zkiUgTqC16qqT8@g6xXX`_v4+sT%Eqbib<&btn>dt5rzIenB>4>&H;?sGv7pHaCZ9_ z%;degbiQVPW+a$~w8F#1(w}Ej{HmcykYH)2Ti*KBgpJ%l7VLMX>XErMPrT_jU=(x( z8SCBlf4l4<7YH=y(%%LDAOKV&U0%#wV(z5UuHG=u0o1Q{rTi#1tNP7Xd1O%Y9s*iN zgAXisa}QDxG?>6Da$!v_8FTp3MAw^{Us)%z{_?Q&!R@1$hiw#0ZFw55u9b^pRBa0m zy`xgjWQwHWtO(vYx1VQ9Bv!4b&7{m49*UPx1n8NVEL7sPo-K$Q#-YB~r+f%}^Bsgv zj45fcmJ}VK-@F;t&HF4Y(T9eqyZ&PK)68l0o-_)Hy>rmh50_nPn$Qz7b|8`m5%?mg z>CS;EnuoLOn#Azuw+P-*i>DqT$a1XhkUVZ#Cak(HdDWwDmr|&3yWoi>ngdg)Sb>{< ztG}7)h;gJIUzGKGNP!pc+267J`M4QO3&>3_0*{|qGg$0C-)E?nJega7 zzMlRx7jVgLfy04_3jm!P5;eH&1O7-oPNZQNDm=>L{ORuB$cSzJVO-ZQo;_2wngiH% zljhqI0*4c(#sK4{GhJ>vIi>lK2ta)INPh{8NsZ{O-hi?QG^4!cFqvUj236P2;)Pz9hD@`=7YH<|j#xvF0!iX3_bd zv^as~e?c(5x=Aoh9lS=UFz)$Gd@SWg1kuI|SRR-6hE=rrs~;~MT~ZccD7;ke4zdNY zR+hGxeo4(ULAhkKhWd$!w58oH5xST}xUIqxNwEb`IhL@@5*ruc{*3gv*sM|o5!i9sS+;9M9t_p zS@(>d=TJ`$AmbPlYwcxMUp0DFCj8i?bZYT_qUKOuw5Hegn7qZ_eYxYAdX|C|T>nLVEtD+8Q`4|MO zJsHJ0^n7;Orrmb?m{?=$V?o@kp1CM8i|PjR++xm%Q_qac!ePXE?@;bQP`(xAsdX9e zQN^=ep*^6Ap>7Z9{nP}-AEvnC&hmUXv@qPlceih=#qg7tmUv}Lv|0A|#}CUX9o{dC zqL>eyR#?hxs{fW7%_GR8dXLV}vbadGjQ7K~0H=$T-RcjgZ<+NGMxXDGALc}KGjQBI z$Y-&^!-9{1`rSW-^eAvNPVnNLn1AlUkXf>{x$$}D&*#BZo;Os{^_CVSrJqW}LOh4kD3K~o zs1mP|6PjP0*sQ7inSGsx7_Z37T4N4|`B0mh{{;6ocja#ABXp1(Ox1T!1E#6g^O|%5 z1sms1D}B~f|A|Om;nLX|`pTMd*LRhpi(i{(2F9AfRITj&qULUg>}&c2pGPN5 zhRa|Jk4Q`TIfrlGyj$eZYP%k|d!$9p8#zeu0$QzZ2T}*7gf%f%Vw< z(#o2f3WA55qjS>+!+RLR{&tQLH5!7DR96Bo4W?HDzvgS{Rs(|$C|8Urar@)p*VX=l z`Xv!h*Ad^n+Ri=aFMMncJ#873ukF6{BSIKa1EP2jrp1>Mx3Yg_EXk-w-)UQ*m=3P? zwn^EV!7?;lBhribda*~BNIY)jxinFrzB$z-qs$4w*YMvQfr9(krm0<@Bd@1b*i8}1 zwvFRX;{Xmpft<-D``(q_tZGbL3%%FqbI;&iwonCsIePpf9cnKby%`-7Sh2Wb{rl6XE%w03Tnl@h1)$Szhb(6m`_;&<&^dYT4yk6Td)UNswUux!047{D#a&llak_ zqTznyvNSVP3EFI|O|O?l8wkWq{a!Vb{{rSpls99jSG_g~$1}r9k>@1h*ZZ^gZ;sWS ziv>I!k%1JlAy8#j>m4&?b-!_My_Nr1i(0QWOWz_^@Bg9gz2mX&`~UxpY@)2J>=8mC zWS6}UBP24iLS`wlrR<$e*&-v7lD)G>M#{{Hl2j=1eZG#)^SZ9j_4!=i@9+1${eJ&+ zE+>xTc)#DT=XgBsj|1kd?%%#WyFb6qd3}A6f4lW2PP1YEMI$4&0G&-uKX-Tov(Ir= z)==8dO2xkO)@q;kN>Ed%ATWD*6J#YjKBu01hreDXyB%K%>N1}WR)WAdGkhU1N#tW4 zP)?Fh)bPK?fEnG`iQ25Qs|j|%%=2qYX&uYznQ=?($3o|esfGJ&-;R=?&bVeUV}pVD z>03ZDrJeEl{3El@OOpHUBs1Oq=bHs3y_XFSllEn$H%Qq%+*R?eO3{{Ac@XVuovABz zRkSGO={fH&vl9W2p4*6f)f8LPQ$31hc-=pw%l;u*o1b5|8b4E6`O&bpmu$T_!_~b! zJabi%@=e%kM|nvZzmKsd@~#kyuyV7hsNm#}QCg^~jONL8i_ECJO%T(4^p2>#hVu@U z)7lz64>V1MJ_?wNiGjyG+yQdtpKD7+$yZZ>~B=_?nHgIST)j_Ur$GIq2LG|f5Jj=lClF2?YYe^j)8MI- z9v!F-b6P{DzxBI6d>DI9i#4J*U|rg3(ACoOtdic)L2130vHjB7hvS4g+&<@b3YIaJ z?lWWOm)%Z;J+YRH)Hi9OPTu@2PV%mU?8rOW>n5Fi5pldyZIceN6+y14wYze4jr#rpq-kV_YE_5s2HMe@ifbUea68fk4ChtJdqhsHE$ZAsaV? zmTbn7!sQ!~m8^!cIpW~9zv{~Oxe@U4(`JcEee>Ix8~hY;gaManr#VqbF}wCN@w<-t z>~+2)42Po*OAL;Rczzvzf&W2~7B}Y76PzR~(64AjJCw$CE+h_%EbZExohr(amxY)0 zdEmzEOZd1NVerfLS zXGsoAG;N>jq-LBw)NIC*zQ*f+alK=6kJ;bC8C4Vpk9;RXMefCE8ajNr%#oA#+nG9w zt)OGDIQb)$LNss@1f!p*JF=Yl#UE^{XVXR{ZONL4=0*Svn>l6wXL{}kYTGx$teKa= z+(?^h=vhQcQ)%=atY)C;iQ7ys3hhPaIM(-lPz;nV+VBM|cn`CbE5*w9OX ziD0BabT$09Vox(UwUpU^n(9PwC&AXWm<;C8=h5ymWwhAUM-G~ULM94p-I$bj|Mzi= znGZkUcYRlh1%r)Yw4y=7)kkN%0*1c{Kz6o5QSmzML!!ju9y{YL6SKJjNzuZKLcV%h{eIrakn}XSD(eMILq~k z%1v?qvkt>~SZUDPU22a=&ap?1B<@%@)oIHY-5?u2JMavO#7?1))4!cGukwY#&^rvN zZV+;G4q`*nc$%7De21n;2O+qCd7#8jsc=5^6TA^*bQZpDPLbE)o$RJ!%hIVku0QL` zBm4qzXPplA@Z-pqy&zJ`I!AOI6gJ24MDWi7@UA`Ol@j*@&Ti1l<(<5EEtRQmC5H)W zraACtYeP@2O)&!IH5hzP)J=l=uoZ=*sw6_|Y)_Iq=ov)hilsz>U|V}%9aEyqO&HjM zuub5MT^2E6M%tzNJD?g1LEUwh&+G=#ZQt={E<{qgUK-+p}jI&0HB<-&nUU{XGm_QAbkz?aSuc5Nch;Ul@w@3|M7b;npHnG38P?+p8;8s z4c1i{!y+?3;GWxB`A1FOxwmVDOX;gNGRMjq|BhF=M_zHcKXdtIOw_gtt3SX+NnZ;* z?e%>NM)zZQT%PybH*($NuPlHEjSRwmZutrU{>_N#1L7B3FI?%0W!v;q+v3noNmr{x z!j)p1$tKp<9I!uc5TR7SW5`Gsof?s1-eZ1?PNP#VRvrQ8?MT}iZD;`GR#(#d@-C&c z9+8vIn$e7^1A$Tt$gLR>w$ykfaf?y@#=rMm^*>Sons=SF0(H&v&sFAY~=7JmNt#E8^u}fk44}# z!yUyb$u8GlEBe$LfB;dE->MlxNqqv(@gQ%E-#7ZB7N~J#8v@2 z)wKzSkh6BF2Fasy)MO*QOTii-(wA9!L|J8pdPw25OWt%jc>lXC)Ox~JPk<9uc^a7! z=x2962>Bn!i;qGBfrObQtJ}oQnpKZ6QOxIs69ZISkV*5dQ?x6>0WY9%V@ z(RlLMX--uoo+)f}h6v~XG!d1gGB2RRix~HPYswQ#$ zB+uyl+@4LidP$`7zzD!wllHionOqSYyP9JLc205yT^?~ZwN z8=pVbRB`qzT4vXHRJHpvp1Yf5^!#qcH_>(#;=8&zDNRekM`Y=*d8@`VAQEKW=_`pe z_yWVLoTFXzfHNa=L`Z{9caD2 z9FGcB`33t*`>mq=3ciFtx z${^b=IDK+#2TwjOjh`;j$?K`bAOCaj_w97@bqWDXKDsSsSK|KeHXw@Ip4QS+zrr~Z^3Eu;I=p7xhPyY+q^O_LzGh~55 z&v+Ch{8=XxX0^!qLjmGT-zpVHA9|I?qlE;DUzq2z=v=J7Q1LGZtgwu)uLl2aI)^j%Dl?T-x((<%izWFX`-J}AGhG{#h z5dvW-95+awKO+OcmZUgGLXpZH<)9~ zOe473?VCvcxDg3x7EzYgMy_%1=v$yOSm+XEE`cYS#1o=Tc;h-2n!bA?3l|P$aaj-f z#~{`Y$Q3+BsL2BC7@LiHdkfdHY4}aQ65vW^ON4Z@ z``+8y7(6D{=Nl?-RmXp|HZj3e6W^fD1-8UP0KZrQLP`fp?5i{mZ3$kLU{7d|>s4Il zifOHTYdk9ka8Xgp^MA;qh1LLCAg`T)>>h73qle2JO;3AIzwSLl9x|>O8+OeE7V8T$ zRWS=Y%=H(mhN_+mG4g850W(B5{?lyY*Zo@?*ermhR68qiVrHSB*1y1_Id1<37DY14 z7H|)wGtta1cX|1MUr+Ui>UT@T7Fu?fdXD=9hphL@nf8AnY09^2mC?Slv#R5t zww^izSxrY(4kW`SS8_a_Y=Gjmo619^Y#r47&YHx92|CXXjhJKbal2e|-Vk!&RrTI>lH(94=ajSvB3E#3yKg%$*9LI~NN zo9(8c47Mf=mr~TMbm;$8_?c4d9>(S_a_P-MUkb=a)VZaXzdxFNwbAc4l5XVuZkEhu zU+I$6VGPZl)^;3O?!J{v%M z?D&2cH%^Up;Pc#n+NH^QC|3-JQjGW*4a1%- zq!JgA==pEFQIc@9pH!l|w8W6f$U1-H=LY*2Y0#5uwc*uLvuy0<4tx}y+0z6dHSN53 z4$U$R5Am(7eyzoqs)F*|?NOEgGh1b@!7DsoS>w9vM1^@9B7Kn_$;H%@Y2prcX#zo| z)zKF!Ge3P}kpEBQ(NueU{VsLTgi5B}zSDQ-fbZjRz?@N-@Nx7~2lf$UH~Tng&#IPO zwefamu`PV+euqsWoj{`LH`7JZ;}5YV{h4I9tBI}(F*kI(5^v+?rC}^`CbS>qZ44Fh zEQBXXq})!na>QSz#px4p{1Qvm^tHM@hhC)p^r~(}i1iDYK=W~g#_}o4=a0^wuN+Wu zoktbz<7C~o6sP;s0opEyg2|%R)lW|Altp!jZvPHWW78x@f@<|1jP;9II1D9bM4LtN zbV_*47E*3>*0mk|R<|rxJ2~*1=>Y-vq}1_NL`dY!9eF}^VPYIoT?&Q zo33~U@vYZ+5qxf|w>ZfF0u;v0Jhay73s+L)5DiQt&Ry31^C#rg4J2f_Cngi#T-S{$ zqMlpaxW(kSQW4(`1phcDF}W&A@964hDwW}PWJzeAekInx=<63j!0%S+GsQRf$5{|~ zrFZAhq=Ue#m#}*89B==~7geSm4CK^;r?L4rKylRew$wJs#iZWl2bHfmGH6Cok+cCz zIdk*7?PeOk%pKhlWe$~SvIl1FYQ5p=7d5R6IkEHf0k@i*-#6*<&+Ky5e$lS!ro9fn z#Te1wDc`5~14kD-AmcG!{)SDJNNHkARX954y&z!hY+i|1?Icka_I+j%M`GQa$;Vv zB75>YW-G#!(nfRW_-wt6DSfIwAEtg)!tUBlG!5JLMa~+XC&$h3kQLgSoXy$>s7-Uw z9JmX?8k3T=Omg}_5C zsMx<4aSPE(eaz5NOwRhzJ2p;%;Q06?B6rK)Y#7Lu+{hkRITXrDI{s?Cqw&bN%)THW z(`(rvakJb>q#WsNQl~wL#xF8f;Jz9DaMVcD$m1^52$cO7gMy$eyubV!{9crJnNeDV z9LC*sX=O@@5!aNVT@W{Fkmrp_B9PWVVK{@IU(%hpBuo9f*mg3!9FQ1sZ)&c5RN|^& zQ2g9wLCep!cL0Lyiy|E+mWr&#n_u80Fq0B#^8(?^s)oY1o=&eG$oW(wtY zC_H-asu$&H>9mMWwkCNy_H%R%lty+_05DqUVeixXxb6OOXNs(|RTeEPoMFq?udpe#~PGblok*fpS&&HB*33kCXIj^ zEMoQFn5d3Xv7Z!P;i%;ocZef;80%c7RgCSigdHG`Z| zr0mg~Gug&TAxY+=zBbX|DCX%FRBNA|Qu|F&^=v0|&7lS>8ii&{Z>~D<6l^$Z&h*q& z2ASRdy=YgdG<7K$g)bPEC6mOcm&k~Y7XO@?@?r%91Z!~cAr<|{HP3(;0nblpz@QW6 zEPhspWtl=Vb04^3knsSsW5c8Tc$(?rWhNR~>X=t+&_|&eW5RE*!pHx@rcex60E;~t zgtdo9d8%O?h>pg9MIKqWhh$&=mC}&w<^pY1TFe^HKies>QpgFYbYm;_)YKCJEvR6t zS9My!9#(Ls?DctC(g`5jmfc(r$k1*Fx;M^ZKkR?(?RxSr#D~o{pfalfRUdaP!#K!e zB|5!eqOd8+RWnV(UrGslR5|KtKR_Jts62aux)$sdnoI3u+aF^_M5xL|aP6bGz%a0W zhkzA+-01?FAc+;tFc2eL0atJrT#3^4V3FB$gHd73;`=?@fh=Z({X;YIFED)L_Ti#g zfX;^qvca9)ubmox^1#%wc+rRmJxY;&Zj_+|Z91v7-J(W#}mv`W?q$XS;Y7z&ZZ`SJBx+is%{ck0sECaPQ^n zNMRTnw!1`92mwd~Thm0R(P>m5kE_JODE$jxQP^$$hq~nYsqD*Enr`HqYW;Q8Ti0yo@*w_9uM z;ArZ78D|)0Tm3;_>n~k0cVzwW(3Q3aLcau*0Yq^;VfrVF#b-h$SNV)+j}fi2G)#y4 z+ec}GIBZ>2NhwB#i5&NS)HagaWwT_s>8T!vFpG0|1Ackga zW98&$6)B6f9^OhXjm5Hpq5%}DByR&ZCn*v=F%cjBu7to%6$lglHr{}QKnpdTy9KX6 z7f>TwWQCoy8G~5I`s6awNsNr9+TH?PL>LOkLF3iRIC;HOQp#X^av7w00gXxv;8Rki z)i)sy@9fO9uUc7HF`80GR00`ZOtSy3n8AE~k~X zCFVlzMqML`;Zf^rPJ9m2g*?j_%s?97H~sT_=IH)>M(MQGca*@M~X{rvg#~Fn6cGWCivj8SVfAp zd;Wmdn+dG9DNadIhE>h+6p3JAs?FZwjWQ9K4`GhS+Gd^e3Q3|z9ltSWB8_enuTafd zdr{F^305yT)d)Ki4K-4N_D@}dJ(q)$lM;zMt4K&Yh07vyY>Z%K0<&aUZGAwPI%lkr z=o|9NX1E9ptzd@ZO~bFQUk7jS&eK1<2gR>(HHT3BfrOe(~jP#{LELbGnP291a2sUUtdg)uV; zT`&#}SUrQySApkj5)+qN--C0ZPm-}xc-)mD#E5XC&ST59OZvQrQS>mLf4eciR6-e+D;hJQC~D>;}1Dh#5wl#1}ZpO(d|B=pK~Vp7uzP@eonT z?zGB#2Ggm{N_w^|khr>ss{tmtR#(I?i5veUF- zqhO=s2G)0vr-~!+bPG2RG6kyB{6~Rnmx)GJu{bPyp%3$>9b$1m^ooh3(-Bznc%1k? zI88%fev(&oh%lw6<$?dH;R!Vje;7!#K#(}){_cQ3!)$B`F@&)O=X#R5hv=(bqEs4*7Bz)oFx$6N z=@?n30g-YDHdJDd3p5eT0(-b)@~f30LCSLQ)a4g#e1f64bnQ$K6xD^D+79Esf#=#=?}61;dG(4FagR5?2I{!F94Pb{4F2=IJt^CM2{X&xwD|f z0Aw_Z9r^u6J5vg=)v@&JN&f#@XIu&PsJ~R}@=S~?i5zDHoDXe34&xj-zS#9zh~-b_ zlwr?ecS0+GB^6<+n;;W!z=Fnj2w8!U5D?k(x4(q!ZemrHK9ISs8omEvFnL3O+$GQj zEAzA+0z5oxQ?nTN2?ApjM0kuG#hg7l8@;@-<3oc=raYsTmDh+n@f1TJRm=ldQ2)z% zCJu=jafbY7tqkxAiwDK-7P||)QfCd3zgEfExpi~z4qsQ!1n^B0F16>D4Fh;#C!?6g z$oS#MYf;!6s(0tBUEdCMafuTe%4GPRL7pFYi@YtsePhkjIB29PY=hDWqhgaE;ne)i zP8I$TwmkyLYPX)Dp$Ot|uze`iYw={AT#Kw96n=PYz*pbMD`yVTxl&eRucrfO z0@0*=GZc+rD<}*rXkq86Y8#y`gsQc?&y{?yJYqb>1>f29>qPy{)8a&52H)odCcF6l z@TJZBR`82{*FEHNSzt>5?cqcNK41SWnKal-5lDu&-{hT17^TE*+{(;6(j1AL$SCxU zoDq-2_ksQb`%8a#xF10jrmqh?EXEN_06l^$!2J*gk(lDBqN|LGBQQc}a8$*0tl9DX z9m8nU5SUc0B@c`{;B|??bG*c*hJJC@yPB3en8}1E_wcx*Z1*ImB|K-cr<)m$1_;7&g zP%N)OUW5Rl)L!Vbbyac>Ih#wuueg)~0yOU>U#Sl1yqd`U>jk{*)<<<+r`66VdS|UK zH+ixsrw&JfSw5b6-XI<#3B+urKzBfc)a*K+`OrGSn)T7(GeDtmtN6wI9{n&|cRaP=yAnLB@$fv1iQeQUS@Uw4I;4+9)2>+U;*1g{DvJ#e9&r{1CBw#tSzBu$$jh~E+mc)7jJdA(qvuZB7*}- zryz`}-EP(XpOLB=W-saz3ptBfWWYr+ht~X!$hDCH>BgJe$xxB=SPecJ`~luK9+m#~ zobCV|y!lZB@zY}V*Yh-b3Px7P3TIfMel=jYRi~Z9&Wo2(#aysDQ`=&yK<^yai9G+{v4FDyXAMIiNEv@1* z0<2y#?4D|QneAi{4-AbILa$TG7lpu9M9wYRfz3vrGR2-mjEjDVmwNF~Gx?ijyEL^M z?MF}ZbPckm2i~g43&T(gWUlp8Jr+IH^)ZM2Hdley7Y5!N%CVu#+!}diDca}H-|I9( zsfvj5MC`4aq|7R0p>Rd*Bw@oqig{WD!^P0#WFZ1PHXFmmRDCH&HO>bvjn@(kjRzB7eI_TN0ZVRK<#5$fEm@%em)l(t{t=BUiiF z`Dl(mL9<~jWmHqdvP4}!sl&lwk!1v`0Eu@Y9h9kLb@~@}7#VQt-xRPk*4YnI+NfP~ zOFX7;Q8d<^m?;YQ5T;A^lP1L(@KFJMRDmMgcck&duU7`uc=kM^MiSp3(1{48h~~~L zla(OMf8`HC?@YAuA&W+;62Bv7iWCEa$@CjqkLO*XsX-Xf_XDEoR)wYXi(TlZg`8_* z_~tV3n;K#svJyIzhKHY)$EfFkw^!e!$a2j1Z9c>Qz(FktrJQBu2&TA$Epv8_l!vze zIYlBVo`?(|c8JY$S1%XTJe-8&pK6$PJ>8hNp~IE&fqBm&u91uA-|;s zSxxa+NQ3^48I8z=Isp9CH4bJAs*ba17muJD22JW-{H1pUN$J}2r7=9Tl&FbEMJ$N8 zq`^#CfM4J5U+M3PDrj$R%&-m6@36$FUgdVS};ZsIbb zj;{9UhFgM``2E0`Z(H%EqzB{V6>24PNMJX!N{Z{8g?7@V(6FG)nYFxkgBc2RQ~ZcF zTH;vq`~`_V24x|+!0Yw)f%7>sFdl8!ORI;~EvKp-$TuG6@9gixa*<&l9vf%zL(@X^PC|8BYN3mC)EqxK~3#$q}ZSJju4^|{$0ghf$D8*Dir~dkR1R5(C=bsH3ko_ev z$zMZJRU#mDve;ZVAs8p>a5Jz1)k-WQ)njYo=5I>zziJ z%Z28E-bfxGnkF!8ik(B9B==JL0s9K$utg#NT@BwdG?YSG+w%mSaB0qp!fjO2guwSt zwYDtfw#RYNRh)Euk`z_m#+1(hW(*L zPVGJk<+33@M9Gwskd>a_bO%o08}w41_Em*$D9NJKK?JhFcB|Nbg75C4YaNJy7u*E4 zdJ-vPi4`~spb}~dZ0w%*%SyO<`S>ff4WaLqyPwTrn%IIsis#~eqov=&$nH2wiP#md zy1+Y}CRD^>7z95ZelOsyF7e^Q*pn_Xcg41nYeRU#VUDw1z zggBJCv)^Fj7VVJpK|U%P!lH!V;B=QA#+1P0A`EWnr?w_*mGsqf)2K)J@sXcy0i5jiNHv_4{s$2RoGiLboyeaAdT(!z7b+Hdy7M^A} z$!c!TZ57Cd{dJ)bNR~vxC0e3W^9(|6rT{U5ktu$_8iu8gz{#BcH_uxjdV1A5ew5a& z?D2zMG4$>N3Kfv>Wbm969>fB`J8Pn^nafmQRs1mJ!EkA1O4SS*`g0b)iTeve(w+6j zZf@uwiF)8mcq;%{CvA@i@6bQabe$`FJHiib{Fkz z9Q9z2K-V~fM7)ELG;dR$_pEm<)Zj93^;E8%`U}6}$kx?-EzfNfhF%jZzyU7?)J5CI z^N#lxQ};l*Q5!GQZUPBCif|Fl`^bZ`y9KcsWFgza`(+Jw69P|*h$y;ZbHksv<4j?$ z*=iLbNQ-905RZaD6ev1A48A?LPu{b_n*Q#kqGubM$--TK@lE}X0E3S+M$!OY{}jAs3kNs%Etc0ViQTyFliFNP6oJlwWtmF@&r$3TDx8BpS=8)gh=HazixK}Jv zm&#t>31CikWRaT#mUT?_CGoCiJJqF51Y5_RVIacb@}I1R=f0#FI0!b+u%(<&Uj%;F zy%^BPueC>0zwJ#uV;vlkUB3jyqTsENTOuUwo6_bVAvcb9qG?eQ5%v+eUc$XJ{PE~_ z_G^e|x_oqbAL+q@gEH{yp0l9T^GdvAr778MHx_qtryj@xnAx?&^mwbj*}?0T21~!^7TuO z#rg9y@1R;D|Mhi@nziOZ2S=2uavMqhqQ(b<;x(o4gK>0hI<0uTca8P~RRQ@Q7%Ald zjdJKyZ*$!6J?0wEm8K6ao{W_rWUrk)~{Ag;bLmasw0tv9%LP*k>)mpioSnCsR%z6bSFbIjEFlMblV7z*xE5Gvem zXeD)C-M;c<$uFkx<7S2^+S~CPgZyJbl!Ae5v=>z(2|j7c|3s2z^tkoJV&HrnnH=VqAXrJ<>$n>*T}r{{)9RbGqzBw zE6TycpOCw4Vei0Ii zWq1Wf`k&Vh;}8}2QAOh8U<#`98OO;^3s?P`c+Ns8$`zola&jh|FK_DvRC$(Qmb!KE zY5-j3m+J<)&3um>bIpnMez7T|9rai-?UzjSZ5bYNXyOf&@d=F^oRO8V)K*2UhsD6W@xi7QPfd^ib3=D{71xv#Lr{+>|q- zL>anmNQ6U$Svu~FOD@XbwdZ__A#CrZ?%*eASF(BJ+m<{0vR>*|iWg7!+1N{5de%Vs?? zQ)pw5f9b}QgKXb#7L`|72`CsDxQ_hN>O6N)M;>)ZYDezZj)!6so06Mw5NmH=zH$ewCurpWRBE7HIHFkMjLd$m z;T!v?IlB>Al-lgJYJbE_g8mhtN^9n=>OGK1O3;2+JzHje^x?u5Rx2&Mlwe zx-QRl|dqaoB^9wzK8tXrD7#~VICoZfJlN9*#?XxYbFjR4Vd?+uZZup&dRzl)d7&!A3>8)ka@_^9 zK5JA!*SGVSzFcj(4D3H15wzYIN4ChY4{2dWS1`ocP`^TKY8{X4l-Fsc4;a%njJncKZ}Es~l`9eOIvG%9|t`vAUL z3QSp?FbKinlJ&ds+V*Ne&#sL5_2oQl)>7GpN z6&=PT8;0i+J&LXOoJb3v4;tfmo!M#Np>Odui~jH{$!j)kdSSQ-91|``MCb(v2B0 z&UxH%-+N=dJw0HS9v0GXNZ}6@y4}!3`cPqW;lzPNUD64Usfa#yMFmp?YslfSdZv(1b_S} znl*7GJfg}Sk6b9(FTWC(!4BVigBf;2_s$u-AI{?tE*)=p_dIQTEw8sSM@nkH3A#%{by2k}{mE6})^P zo!dxFtL;WH+|62n6O>|R!RtvTg`t*TGHntI_IN1*_kmcFEDzrs4e|)z*9F1LOFs1Y z1}QA(jcosVYram`eG;59)_mEm#2Da2Q>Cr0#MlidW^u`wVr;N7(Tu)B*ehyLbt2u^ z`)tLZw*D|l-=K9X8hMN=+MLkMiyWe2kZyN@EYgwnkSDc_C{TO ze==7xQkME97G>hOq~7MA-_k=N1ROuYUi&7$jHa#F`*e}pTCle!^7JW@jD>QZki z80Jfa(4gA+3&f9b`z(F%!eI0nUPen?Mu^g}{KHg>IdlDV0y9w%n?n9+sz&2;T;9)E zS~4aeQ)Xynzg5_j;w$FUx~zg=2N-@!oA|pv5aQ(YT%$z8?ALPwcfsC^o|9{Nc?F_g z%*E7brtpFFds>_tumH?Rx3pBy|8E@ngd+(n3zKF_P0Z^k4>jlEqRFi(r$L(<7(qnq z2?c67Vu4bCI6@Rszw{G_=K<-FFx_(sM?4QAHpg;ayZ+)rs82V8SbWapZLX7e7vey+Ou|9H_d^Wl<< z%!zUi)4{2mYi~Yj`W63ZQ7A3v|L^+(F^kTG{MX1kHjSxyxOoTK@ebu(5FgOKB@)o+ z9Pqsa(iTYteP=dNA^Ra zehV_4qk(qNTNJ6)cK_JICZGAS%=-{R#pVlN*Zuz1(EZi7wb!MSS;?Anp~&U(%UZX# z-jz$nY3qvPXhp4~EYylSzGxPYMT1Txn}Hjg@%;w$u_v%|hnsv-){!kpK><@@G>PA7 zP|&>_P28M?l)j%wg2cd)w<|Sh&hwaXoV>pdbitw~({3<)6iI2i$M!%z&G<=)O_Wu-Li zUl!l*-hmEp&VPT|KmHPFKa#8AojN=1dLGQ-k>*H{S-Is6m#C;GQQ9>m)CDKTHXR1*d%x2VsP8jrf1I-X;)iB4jbo&>Ck%c1V%KQGWQje?_UqxvrW4xjK&Hkwx{g6I6R z9He^72ckX2ZING8j`*2y*ZR+ERQ3p--3X!mkl~38O%@TLsmwS~i}U#r}2bGIFn?i%gLmP0er( zwmFfx(V|%~(qFq!RCk9{Mr`%Y>m`Fb05WaL+dU93GAkjXFD0u=D>pq@qP zcgh2hp@KaZrmC9_W_foKKE%C4s?NJ`%JtUDF&4pW%gZW&_fuY;68mwrzDFMCc|vx# z5VB&S{)V#BY7XVz!!s?*eKQEMItR>%BPiVF>$r!Ape^**11~>3agtY;Og(E7-J=edjS%OD13v$MoU&s;_e-}G`}J{;qZv>)CK=JYE+b5S{UdJx$mc3zHC8DbgO z#UD|EP&9rJyN``}B3{gSYnihNP`>S`FgZ9m@{8V9-IQV2(@e57NJ_ebq29%2;0aPG zpDa$-3onp5k(Yhu_uVn_Dph@+u4dJ1;aBM;_rYLxFEblPI#RTOjG%GKSj#%cBYQ$h z#53N#7A8C{4gK914MCa{=agc3YexVC!24wfb^UXQ0`^!|q%U~tLfs^T87YxpMVkI8 z-0I0Eek#C1Kpr&t2?A@#W2#FKJqeY@`f1 zYjfoZL&o$$6ZfW+`WmL0G2Q%pK(N8*Z@c;qwkpqJ`A7VofGTK$coL@I)^_)X%nPQd zdobPYB&y&E|LA+^bC+;T=SejV^K)hdWs0aty^zBsA;FY z)F$5vGVjdwU6$rWCswwIUP@dh(AwD5e}W6D0}W0}97_unPab zfvdfXAjJ=!pdI-aJZh)&ac{lToV2{k6x$O$UH3h{Cu~-sp_s|6Fonb&oDIDqN}2_%`$keS+*$7=iOXK!j}j$yTSYhq1Xec+0Zk+(s0YP8BTA zDq2XlD`Rf`G(lu*xe*6>WK;c0fLUp)U?jdJ7&1zjeC zvhN6PnKVnyg$Wez_FMim!8Q|sYu}C%`Z36-sAnXSh$uWe$4!~ zlTNVM88GS_PJlAlVmR9Bv%Pkm@XzzhA`yCg%JVg|=un=!*!a_MJ@Vjtxqp?)WE22NXq;C1!w@;MxAA2P`qBD4 zr2KeW*qOT>*u+FcmBXaX3@%UANtxLTrYTu1pU5a3KHi+4b8?yFwdB_qL=BX}>Ss^e zq!bP;4>aO9(BN>svE)8 z*U>$HE?x7)exFABLGF#2J9C}F^apw+$1OUb^k}s|YR_wkOMX&0vC975(CS!FtMppU z8&m!QjR)5poe zYrr6$7F~^D43Q^Qpz&LN;t*Bon4ohhH;D3JE1_c7c$#}iK>~Mtt%W3(i z4n1I90pZM)y)#Mw#h<>KcKp?fG|Oicf~MD4+hr#&_VyT=t0d|)taU*a(m^|W zO&yW%5Cv;`p@9tnQc)VBt!DKV_}fuT+3`iR$5gwOm#Y$QFu?GV_I75XLFAhTBXkz> z5sHzkmL=ug?yM2EaF#Alhz~bhk;3qyTdSv;8Z|dLn_u|G-#t&s4j?SEUV) zdgY;@RCqX$KH?@!Iifzc;b|hJR&ut~QDL)dnuZDkU58kH<=VYa6&OciE}QBic@U>z zG;;8vH7Pa)!eCtL#yUN6T45WwlTpv;oGa9k39#fE5(ypS)`XobXnsiSJ%)ZfA~zy_ zgI-{b`uO4@r7e_iEDZgZO$>a$lYuCZlA5cp6ItNI%fuk}8XjI0XcUNk;Lm96F96@` ze;+~lfBRL6FJW~V6xmrR0lrZghZtCN& zc!S^1Z(MXtd-#v6ZW6ZqTd;-Ia_Pewu`+iGkg6N2BzE~w3*AH*GP`5|y#c}nkkrK6 z=_87#s)ZEw#%XK~z_xGQ2C=`n{?@v8bIOO>Wn(n)Bl*#OUy6#U3?&-*1v~9nDT9eRn zW_r;Z}9t}>uL_kFt%@g z9Od&|dm|WmLQeMmDIW7PnR&41JvYfQ7E=(!gik07cfHNP9*TuX$&V$#Lj*lxAc^ky z&^nBXKC^%p4c;O|@~c3!6y)#&jN2p~Jc{pcmjN&wn`w>CTleet0wX$t9wIyoXh>3) ze~wITtU-N7f-G#v-q*6>fA9jhVZX@0|e-0vUvS>n^KHyDd}Pk;UJ>u$49< zpD=1>BUlf%hb^bkzS#pdeGQc9o}v)vqsc%v0TpcP!7u-Va?3U7tLy!yp}*VoWseA+ znI!TSy=zL3tSHdW9*LLf8z0_ocaK3KAmeOm>deqNxb<9m81;)T1U#!m{fiF(E7`$3 z7Or>t?|k)CAtGHD6gQH=uTx^p<|!QwDZwc}wLb2`(sf=m5pDRT;Z500LBSjZk}K3s z;5W5IMfQks3d#9b(eRP;ytfU14R;d5!42@b-uqvroq0IaZTrR*X~LkAWUm>arm`fV zLXu=(qa=IwA{9z9qD2^EX;79d8QGVjM0hlaNEGr|lAW@oc$&=by1zZ|dmO*#ulGIP zKkGO!bI;uO_r9*{JU=I)y8b5LIa*=c@N6}*HPA|QCx4=9JBaRJtGMtb_mNbRai7^$wO`sblMh_^hj=f_?ms~{h&gA$_GSj|I8W>euFWbf0}3-Yc=oKmUv<~F~$Q2At| z(02Y)J0>?Fy{svx82f7eo=9H*JMs8#MwR~)grM;(Y1-cOV&MwN!0V9fvZhF71@7jz zf5Li>33cvAQsx6cU|=ZyUJT`=fBGeR)CzqWu|`AWo7!_Ns3pLTV=bt&Hkyq?b<&H8 zK6&-t!y1b1hP7Q%-2;M^rNENcdMHg~;l*X~=jIJnDGn(fh?|y3m^kZ?==pX!jx6!q zJrM4EH_;+&-{g!yUHKrSQbn$MUgpvOf-8PSIouPU;DW1(qSFL6#Ghf1I{4D8uYz{)Ocxf_J@&ZVz|+3Urt>~Bqnow9Dwq2!!@{% zrAogGVbc`MsCM%)caNp0P!0L)Ki|8~U8wT2Ke;r|$*k}Z4T3F*Y+AKl-xQs`je?y! zDmDKG>?LKFodUh{2HNamK?$K!r^ex8cl>)eZ3J_gPTvKbrf2or*YFHeVGi*HyLKa! zazVwXJ63FE?Uv(8vwag~Pi^vlRcjQ5Ef`WuaDym&0dH*we$oqTU7E4@sx6txXVqjq zC%)aXeG%ATSclqg=N^qW#*rCY4=SoYak$*) zco+4@8U?*(pM%uS?{YGA0taVfKmI1?C>$#$KHl~`YvNOn$(_7DJ595Wnn#4x`2IIR z%!I-6ti?S5VqV$fl8)>Q3oUbdUO`XsQ(NDU=3D2@N*UX@758Xj303k`IhC zTt_{w9drkE8;cc<5*l=+9|%0Mm8is?u39Byolue#8OLO0UE*Yc zNGaRg`6=pJRC{O$F5arB5xux@@~>)*xxv094Qiaj#MSEH<;pb7adQkIDIWN6%{p%? z&2xB?(KgJlpFXNBsMor|SoW;WL!;C~K8|;AW-2l(O&7-Wbk6ZCxNot}_IDT5)-3h^ zl_wM1yi3%wWlDCmvLl$g#0b@_MJ7|BpYk`1zg!4@+@2uflxC(5N=&3Z{)2S}Aytuu z)$vcE>=ScpBKUwWHBk1~ArM*Hq$V?X`_6}14d z9u{5hEEi9X*YH(_y6pyZ4*WVNj^&~3jVK*QnbnOsyBP{4deY>-HXPukPjjpma&w+s zqH#>XlTHJ+|qWdHi>Pu4DUvA)Ja|rNf~CMNKX33BMF>8%-TW^ zM^sgt%VS$&fc)?_YBVyZmv|EEe8J_dJoSt2r3yWcdT1n?oY$M0$wUsY088RlSDn+e zy~z;+Jtgn(y9)dZotYUW7~U<_5pgj|#6zv3_LdzUS9b`VlIHf%b0Jhnkg5>>K?ut!F~t8f4oP{oxVVg7lzj zKiyjK{je=nXJ8!;P<%8b9YB_S>%lh5ed*U_GxF(ujHXBJ9^0>cLLMYBDKg3LnZI~K zxU+hXH0g|PvEk<{yTvzm%C1tI*Qy-*1vel{-1kn4cF0Z7-1tnyl&{@YzYc%l+ ziXC~8@D-JBYp7Whf={40FW!M3|0{9?$@-q4lEueYH5bx_Nz>AbA@N!%AOWosVT~=T zTjv;`z0)gn-viQr%}b=!R|>0vb6T9j!}?)u8)GN)fhWP%S@_tq^|Xwf^NwT6t4!V) zB={Tby7fbQJ1!&%;;u+N1l?UH=u%D}7bo6Hk9K5bn0Gb1zkv~+YaT(_(N2@V9+JnS zy0alW>yg{%9&&JJVp_Yz&KvFNbb*wc8td^~s_Lx`Q*ACu?V51Pzo>J2^dMmxB3*%A zD8RK(03L}!0DhHK;4s2v=Ukipdb-80_~a$v&Af`ghg-cH=ag=e8ro%r6q8`-Ef)>x z_Iv_;Ml~-sPRj9ya+pX`iAwBle|Cn+IQJjayxX@4KR&oohVFEo{QzHv2=G)W^0o7^ z6EE3o6JfeKGP5*$NaS_4>*QkGyv+elmLTW;PC>Z6Sor9UtqB_>m8$`ZC3h3%D?VB7 z;@e5+T>WLaWd9(_e@gxh zT)BqEd8pi)P{WE4m=OIfyaoHn@4DoF`mgo^IFBwYjoegc+V`2{Uz-h;Al3j|yr~9= z)k~!?SA!Z0A_of)r_G6hd8HM`o>p@aDY^0kT z_wRZz&ba1N*T(;9pO{lAGQ=I+g#2JbjF>orP zy`ra}$AWIIoFdqQ1PhgOFaH-GWTxO`dwS>^2`M@k)@nC3Kp5(J*lw17lp%)tiVqr| zQ2Lq+X^y>5!Q}ynx!IostV2v_GV`J*!_{3uKffD985bbWJbY=To)YO8%a=%ZL68>v zcniyQdZgkbR$zCHeGy5RdI)iQP5DfS3b@{k$dH&^84|<8(Jc_sqU@0)7e+F8fN1;q zW|k}|s{);tdWvd(?RTME3TlKGvrt{B0ijZ4?#E%2Zh-oDMUC4ch*w5Ww8+!ZEECz# z?*qzh2;GYchoG2?2*ED$(@@_v#S9Q6OFrk?R35LN|8RtFk3^b9Nf=*8i z_)T}q_p?~Pf>~#3Jrf*Kk{J_FF)>AjuZX7XJj0elXIT5a)fVah0KI0VwkvU&zHUGM zY&gqX!vy5dUA5dUKKRaK3>%V&n<{qFKOfCZOq|{S$Z|q`=4qwFIJdbj^(CuLe zN@c@WVDQa|1AI~*QuKuPbQaIJV4-LyD$hNX(;5=g-d&B8)}T-pP} zbRCM~YMD+GLy7h`5mU+@xZuU5EI3ZXlD(hF0@#wU(h98Sk8+;fMRG99^G}wngFc2h z`znre{stA0QdkFbNYUW2b7)#w1U9UOF-eViQ13}|o_rN8ArUS6y>i`#e85`G?Q8pm zT(o0JN*hnd{CJwaTdu_eEg$bCw-9jp$G{t+pYlp#~$IuP*07KTeal5%#!Td zR;|4Gq-(nW3)wDs>teqLz}|i{y-Hv5EHinIL-=H*FIe0OumxLT`{ipIZ*?+7<~5iH zdE*dUrW@i29mWC>j%EE;LX0XYwB@$rZF^wEMkaDk3?t3BJsPw=CQtJr4LnAGLi4#g1R)U;KnVWfpHSsS)PWvU zaA427gG)cZokJDvEH;q=yn=kUmPTY+Bcha{rAoA|U+4>F{ThO477t+7w3cAzS&wxD z9lwJ+%fAK93zw?b#UVDYycq%iZ13WJs2OpnV}M5d7;g&3()ml5cc`zN=?yl`|8ynR zgS*E*OIYnv9%d3WPabbkbTDvP)x+UeRcdBQ>o11uB^h4g+#=!DorM1pVa3u=58Fnu^Ay>O_LKJLiTi7+cC`{a6!KS(Bi6`;$x*5yQK-`PhDS;O4@YLtnhC#{y>^slPOdvD z+c&q>mT_~PAJw9S)n#%Rbue0ks>&qKepyJ^F)-yM5q;_l*m#HOk5b&bX_gmWC@B#w zwm_Q-&S4e(RJ*`t1Un7b#}%FppFpyKkAdZ;CWnz|b9u(+1+a27j5sdjE0lnVjp2~S zvEKh`i9GEvRoe@%u)AYIwpIH<6e&BLpK0H0P?@6k>uzI5T9NBBlgl^aoxpdFdt;iM zAppW1?A$jsNVmHNa*ld17*Sy;6sDAziw&H457pj+(|XtY9LZ7#ut7%bOwEKhmWuTB zhWPaB+k1%mAJfK1Vc&`?>Y~fAzi92M1X|WD*Jpq1ER3W}95||{sDiWNH?~(@_s$4$ z2&~qIJ`)-V^gcvz4@HpjIUp@&7ok>TF`I{MPHLUUh+@I_Fh1h0{dwc&`hRASfK-Am zIYfFk|Mj%@?2pqvKRmkj;*JhaUNSy!(g*s1VQ547Sa-t=NU{Ikj!~M8zP0_P^{ct^ z-uQwvzd?TkSLnPD5&}>OS|s=5A?*mC02mah;*>RJ>Q)XY@R{OfD51nLEz z2lb28kA$z4C^el{?gNfc215nnRvp82gj;0agQ8NHJ7EPB29e3c5v`*~>4``QRXzoV zzx%h2{qa1>y66~n@*Q?bS@?bZ=n_^P7HH@sYsX*+o9T!$UY!DmsHU6KdSE3HOy7D2#c!`}~ zHJj#EM z?k%8h7!fmn0iFdu>OW!^Yv+(cik_=-TD$zs#Ex8nYyy}SgZO1%!#|uS{NnRK21K-- z!a2>x_KI+5EGs_#`z!DmtLzOC9qH7#hgO6&!m^DrUAb4obo5XxwRsoz2fLyZI92`?In&GW@5mX% zdrWSci%n$`m-CCjjIOo}encX@`S+`msML%?n*??H0#4wQAf*?zis~_Hw$I<qk$|s z7EU4t(1|la7ttzIwHkSss$&U_Xc@bZofS!S!-wi`0$278<6l1&=ycu&sto)Vv1RQ1 lgx};v{_h4JoHu4!>^y28j_6qPEy2rW)73USQgGOg{D1FW@Hqeg literal 0 HcmV?d00001 From 6dafe72c3b0afbd4f18bbc7a22362a57d70f75ab Mon Sep 17 00:00:00 2001 From: bd_ Date: Sun, 29 Sep 2024 13:53:07 -0700 Subject: [PATCH 51/85] fix: play audio path mapping is broken Closes: #936 --- Editor/Animation/AnimatorCombiner.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Editor/Animation/AnimatorCombiner.cs b/Editor/Animation/AnimatorCombiner.cs index 36ddf4de..674140dc 100644 --- a/Editor/Animation/AnimatorCombiner.cs +++ b/Editor/Animation/AnimatorCombiner.cs @@ -611,7 +611,7 @@ namespace nadena.dev.modular_avatar.animation { if (!string.IsNullOrEmpty(playAudio.SourcePath) && !string.IsNullOrEmpty(basePath) && !playAudio.SourcePath.StartsWith(basePath)) { - playAudio.SourcePath = $"{basePath}/{playAudio.SourcePath}"; + playAudio.SourcePath = $"{basePath}{playAudio.SourcePath}"; } break; } From a71af7ae0a7caa904cf67f04a70754ae2939a8bb Mon Sep 17 00:00:00 2001 From: bd_ Date: Sun, 29 Sep 2024 13:34:41 -0700 Subject: [PATCH 52/85] 1.10.0 --- .github/ProjectRoot/vpm-manifest-2022.json | 2 +- package.json | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/ProjectRoot/vpm-manifest-2022.json b/.github/ProjectRoot/vpm-manifest-2022.json index d4a80444..eaba4f86 100644 --- a/.github/ProjectRoot/vpm-manifest-2022.json +++ b/.github/ProjectRoot/vpm-manifest-2022.json @@ -19,7 +19,7 @@ "dependencies": {} }, "nadena.dev.ndmf": { - "version": "1.5.0-rc.11" + "version": "1.5.0" } } } \ No newline at end of file diff --git a/package.json b/package.json index 96eaaecc..c84e0cd9 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "nadena.dev.modular-avatar", "displayName": "Modular Avatar", - "version": "1.10.0-rc.9", + "version": "1.10.0", "unity": "2022.3", "description": "A suite of tools for assembling your avatar out of reusable components", "author": { @@ -16,6 +16,6 @@ }, "vpmDependencies": { "com.vrchat.avatars": ">=3.7.0", - "nadena.dev.ndmf": ">=1.5.0-rc.11 <2.0.0-a" + "nadena.dev.ndmf": ">=1.5.0 <2.0.0-a" } } From 838f1dac7ea3c500c2d9037e461cacc9989fb46e Mon Sep 17 00:00:00 2001 From: bd_ Date: Tue, 1 Oct 2024 20:01:03 -0700 Subject: [PATCH 53/85] fix: ignore blendtree-only layers when determing animator WD state --- Editor/MergeAnimatorProcessor.cs | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/Editor/MergeAnimatorProcessor.cs b/Editor/MergeAnimatorProcessor.cs index 50efd939..b0af81ac 100644 --- a/Editor/MergeAnimatorProcessor.cs +++ b/Editor/MergeAnimatorProcessor.cs @@ -246,6 +246,18 @@ namespace nadena.dev.modular_avatar.core.editor var stateMachineQueue = new Queue(); foreach (var layer in controller.layers) { + // Special case: A layer with a single state, which contains a blend tree, is ignored for WD analysis. + // This is because WD ON blend trees have different behavior from most WD ON states, and can be safely + // used in a WD OFF animator. + + if (layer.stateMachine.states.Length == 1 + && layer.stateMachine.states[0].state.motion is BlendTree + && layer.stateMachine.stateMachines.Length == 0 + ) + { + continue; + } + stateMachineQueue.Enqueue(layer.stateMachine); } From cb2afcc3d51114781f1fd99a5ac034405221d4bc Mon Sep 17 00:00:00 2001 From: bd_ Date: Tue, 1 Oct 2024 19:52:25 -0700 Subject: [PATCH 54/85] fix: Menu Installers on the same object as Merge Armature are not processed Changes to pass ordering caused Merge Armature to destroy menus before being processed by Menu Installer; fix this by hoisting menu generation to occur within the animation services context, before Merge Armature runs. This is safe because the menu installer pass does not interact with the avatar's animator controllers directly. --- Editor/PluginDefinition/PluginDefinition.cs | 8 +++++- .../VirtualMenuTests/VirtualMenuTests.cs | 26 +++++++++++++++++++ 2 files changed, 33 insertions(+), 1 deletion(-) diff --git a/Editor/PluginDefinition/PluginDefinition.cs b/Editor/PluginDefinition/PluginDefinition.cs index 69f179d7..2d258b23 100644 --- a/Editor/PluginDefinition/PluginDefinition.cs +++ b/Editor/PluginDefinition/PluginDefinition.cs @@ -59,6 +59,13 @@ namespace nadena.dev.modular_avatar.core.editor.plugin { seq.Run("Shape Changer", ctx => new ReactiveObjectPass(ctx).Execute()) .PreviewingWith(new ShapeChangerPreview(), new ObjectSwitcherPreview(), new MaterialSetterPreview()); +#if MA_VRCSDK3_AVATARS + // 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 + // to retain those objects? maybe? + seq.Run(MenuInstallPluginPass.Instance); +#endif + seq.Run(MergeArmaturePluginPass.Instance); seq.Run(BoneProxyPluginPass.Instance); seq.Run(VisibleHeadAccessoryPluginPass.Instance); @@ -73,7 +80,6 @@ namespace nadena.dev.modular_avatar.core.editor.plugin seq.Run(ConstraintConverterPass.Instance); }); #if MA_VRCSDK3_AVATARS - seq.Run(MenuInstallPluginPass.Instance); seq.Run(PhysbonesBlockerPluginPass.Instance); seq.Run("Fixup Expressions Menu", ctx => { diff --git a/UnitTests~/VirtualMenuTests/VirtualMenuTests.cs b/UnitTests~/VirtualMenuTests/VirtualMenuTests.cs index 81a9ffa3..5450dba0 100644 --- a/UnitTests~/VirtualMenuTests/VirtualMenuTests.cs +++ b/UnitTests~/VirtualMenuTests/VirtualMenuTests.cs @@ -698,6 +698,32 @@ namespace modular_avatar_tests.VirtualMenuTests Assert.AreEqual(4, virtualMenu.RootMenuNode.Controls[0].SubmenuNode.Controls[5].subParameters.Length); } + [Test] + public void MergeArmatureAndMenuInstallerOnSameObjectWorks() + { + var root = CreateRoot("root"); + var armature = CreateChild(root, "Armature"); + var installer = armature.AddComponent(); + + var merge = installer.gameObject.AddComponent(); + merge.mergeTarget.Set(root); + + var menu = Create(); + menu.controls.Add(new VRCExpressionsMenu.Control() + { + name = "control", + type = VRCExpressionsMenu.Control.ControlType.Toggle + }); + + installer.menuToAppend = menu; + + AvatarProcessor.ProcessAvatar(root); + + var realizedMenu = root.GetComponent().expressionsMenu; + Assert.AreEqual(1, realizedMenu.controls.Count); + Assert.AreEqual("control", realizedMenu.controls[0].name); + } + ModularAvatarMenuInstaller CreateInstaller(string name) { GameObject obj = new GameObject(); From f85d455c8f5f3d785f10959c2935ab9668ae7390 Mon Sep 17 00:00:00 2001 From: bd_ Date: Tue, 1 Oct 2024 20:04:12 -0700 Subject: [PATCH 55/85] fix: NRE issued when viewing Menu Item editor outside of an avatar --- Editor/Inspector/Menu/MenuItemGUI.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Editor/Inspector/Menu/MenuItemGUI.cs b/Editor/Inspector/Menu/MenuItemGUI.cs index c89c3817..30439a32 100644 --- a/Editor/Inspector/Menu/MenuItemGUI.cs +++ b/Editor/Inspector/Menu/MenuItemGUI.cs @@ -646,6 +646,9 @@ namespace nadena.dev.modular_avatar.core.editor var myMenuItem = serializedObject.targetObject as ModularAvatarMenuItem; if (myMenuItem == null) return null; + var avatarRoot = RuntimeUtil.FindAvatarInParents(myMenuItem.gameObject.transform); + if (avatarRoot == null) return null; + var myParameterName = myMenuItem.Control.parameter.name; if (string.IsNullOrEmpty(myParameterName)) return new List(); @@ -653,7 +656,6 @@ namespace nadena.dev.modular_avatar.core.editor if (myMappings.TryGetValue((ParameterNamespace.Animator, myParameterName), out var myReplacement)) myParameterName = myReplacement.ParameterName; - var avatarRoot = RuntimeUtil.FindAvatarInParents(myMenuItem.gameObject.transform); var siblings = new List(); foreach (var otherMenuItem in avatarRoot.GetComponentsInChildren(true)) From 8150e05dd04573be68bcf3e346eb1f8e1d2a0b09 Mon Sep 17 00:00:00 2001 From: nadena-dev-ci Date: Wed, 2 Oct 2024 10:44:23 +0900 Subject: [PATCH 56/85] New translations en-us.json (Chinese Traditional) --- Editor/Localization/zh-Hant.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Editor/Localization/zh-Hant.json b/Editor/Localization/zh-Hant.json index 21cd5a61..bdc8b921 100644 --- a/Editor/Localization/zh-Hant.json +++ b/Editor/Localization/zh-Hant.json @@ -251,7 +251,7 @@ "reactive_object.inverse": "反轉條件", "reactive_object.material-setter.set-to": "將材質設定為:", "menuitem.misc.add_toggle": "新增開關", - "ro_sim.open_debugger_button": "開啟響應除錯工具", + "ro_sim.open_debugger_button": "開啟 Reaction 除錯工具", "ro_sim.window.title": "MA 響應除錯工具", "ro_sim.header.inspecting": "檢視物件", "ro_sim.header.clear_overrides": "清除所有覆寫", From 2c9939dea8b4292273beec3aa31ebf820348645d Mon Sep 17 00:00:00 2001 From: nekobako Date: Mon, 30 Sep 2024 19:35:32 +0900 Subject: [PATCH 57/85] chore: remove ShapeChanger migration for beta only --- .../ModularAvatarShapeChanger.cs | 39 ------------------- .../InitialStates/SCDefaultAnimation.prefab | 28 +++++++++---- 2 files changed, 20 insertions(+), 47 deletions(-) diff --git a/Runtime/ReactiveObjects/ModularAvatarShapeChanger.cs b/Runtime/ReactiveObjects/ModularAvatarShapeChanger.cs index d8e1dea5..fd54e96f 100644 --- a/Runtime/ReactiveObjects/ModularAvatarShapeChanger.cs +++ b/Runtime/ReactiveObjects/ModularAvatarShapeChanger.cs @@ -60,11 +60,6 @@ namespace nadena.dev.modular_avatar.core [HelpURL("https://modular-avatar.nadena.dev/docs/reference/shape-changer?lang=auto")] public class ModularAvatarShapeChanger : ReactiveComponent, IHaveObjReferences { - // Migration field to help with 1.10-beta series avatar data. Since this was never in a released version of MA, - // this migration support will be removed in 1.10.0. - [SerializeField] [FormerlySerializedAs("targetRenderer")] [HideInInspector] - private AvatarObjectReference m_targetRenderer = new(); - [SerializeField] [FormerlySerializedAs("Shapes")] private List m_shapes = new(); @@ -82,40 +77,6 @@ namespace nadena.dev.modular_avatar.core } } - private void OnEnable() - { - MigrateTargetRenderer(); - } - - protected override void OnValidate() - { - base.OnValidate(); - MigrateTargetRenderer(); - } - - // Migrate early versions of MASC (from Modular Avatar 1.10.0-beta.4 or earlier) to the new format, where the - // target renderer is stored separately for each shape. - // This logic will be removed in 1.10.0. - private void MigrateTargetRenderer() - { - // Note: This method runs in the context of OnValidate, and therefore cannot touch any other unity objects. - if (!string.IsNullOrEmpty(m_targetRenderer.referencePath) || m_targetRenderer.targetObject != null) - { - foreach (var shape in m_shapes) - { - if (shape.Object == null) shape.Object = new AvatarObjectReference(); - - if (string.IsNullOrEmpty(shape.Object.referencePath) && shape.Object.targetObject == null) - { - shape.Object.referencePath = m_targetRenderer.referencePath; - shape.Object.targetObject = m_targetRenderer.targetObject; - } - } - m_targetRenderer.referencePath = null; - m_targetRenderer.targetObject = null; - } - } - public IEnumerable GetObjectReferences() { foreach (var shape in m_shapes) diff --git a/UnitTests~/ShapeChanger/InitialStates/SCDefaultAnimation.prefab b/UnitTests~/ShapeChanger/InitialStates/SCDefaultAnimation.prefab index f6431564..71de2608 100644 --- a/UnitTests~/ShapeChanger/InitialStates/SCDefaultAnimation.prefab +++ b/UnitTests~/ShapeChanger/InitialStates/SCDefaultAnimation.prefab @@ -46,10 +46,13 @@ MonoBehaviour: m_EditorClassIdentifier: m_inverted: 0 m_targetRenderer: - referencePath: test mesh + referencePath: targetObject: {fileID: 0} m_shapes: - - ShapeName: key2 + - Object: + referencePath: test mesh + targetObject: {fileID: 0} + ShapeName: key2 ChangeType: 0 Value: 100 --- !u!1 &2598725701317979415 @@ -98,10 +101,13 @@ MonoBehaviour: m_EditorClassIdentifier: m_inverted: 0 m_targetRenderer: - referencePath: test mesh + referencePath: targetObject: {fileID: 0} m_shapes: - - ShapeName: key1 + - Object: + referencePath: test mesh + targetObject: {fileID: 0} + ShapeName: key1 ChangeType: 1 Value: 10 --- !u!1 &2845086157653980983 @@ -150,10 +156,13 @@ MonoBehaviour: m_EditorClassIdentifier: m_inverted: 0 m_targetRenderer: - referencePath: test mesh + referencePath: targetObject: {fileID: 0} m_shapes: - - ShapeName: key3 + - Object: + referencePath: test mesh + targetObject: {fileID: 0} + ShapeName: key3 ChangeType: 1 Value: 100 --- !u!1 &6385483934583485188 @@ -204,10 +213,13 @@ MonoBehaviour: m_EditorClassIdentifier: m_inverted: 0 m_targetRenderer: - referencePath: test mesh + referencePath: targetObject: {fileID: 0} m_shapes: - - ShapeName: key1 + - Object: + referencePath: test mesh + targetObject: {fileID: 0} + ShapeName: key1 ChangeType: 1 Value: 20 --- !u!114 &2918390808850211981 From 4b9d1128c6f8b8fb233669ad7eb86e99a2078bde Mon Sep 17 00:00:00 2001 From: bd_ Date: Tue, 1 Oct 2024 20:09:47 -0700 Subject: [PATCH 58/85] chore: set harmony ID on UnpatchAll call --- Editor/HarmonyPatches/PatchLoader.cs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/Editor/HarmonyPatches/PatchLoader.cs b/Editor/HarmonyPatches/PatchLoader.cs index 0ce7ffa4..b368fca7 100644 --- a/Editor/HarmonyPatches/PatchLoader.cs +++ b/Editor/HarmonyPatches/PatchLoader.cs @@ -11,6 +11,8 @@ namespace nadena.dev.modular_avatar.core.editor.HarmonyPatches { internal class PatchLoader { + private const string HarmonyId = "nadena.dev.modular_avatar"; + private static readonly Action[] patches = new Action[] { //HierarchyViewPatches.Patch, @@ -19,7 +21,7 @@ namespace nadena.dev.modular_avatar.core.editor.HarmonyPatches [InitializeOnLoadMethod] static void ApplyPatches() { - var harmony = new Harmony("nadena.dev.modular_avatar"); + var harmony = new Harmony(HarmonyId); foreach (var patch in patches) { @@ -33,7 +35,7 @@ namespace nadena.dev.modular_avatar.core.editor.HarmonyPatches } } - AssemblyReloadEvents.beforeAssemblyReload += () => { harmony.UnpatchAll(); }; + AssemblyReloadEvents.beforeAssemblyReload += () => { harmony.UnpatchAll(HarmonyId); }; } } } \ No newline at end of file From 1c29af20fbceda1643d0c2872e97044e98789e3d Mon Sep 17 00:00:00 2001 From: bd_ Date: Tue, 1 Oct 2024 20:14:26 -0700 Subject: [PATCH 59/85] docs: fix incorrect docusaurus directive --- docs~/docs/reference/reaction/debugger/index.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/docs~/docs/reference/reaction/debugger/index.md b/docs~/docs/reference/reaction/debugger/index.md index 6cbfbf47..2eae1191 100644 --- a/docs~/docs/reference/reaction/debugger/index.md +++ b/docs~/docs/reference/reaction/debugger/index.md @@ -1,5 +1,4 @@ - ---- +--- sidebar_position: 900 --- From 6c551858959a2ea88d9c3ecdf3745b8a0532a916 Mon Sep 17 00:00:00 2001 From: bd_ Date: Tue, 1 Oct 2024 20:11:57 -0700 Subject: [PATCH 60/85] docs: fix reactive component help URL link --- Runtime/ReactiveObjects/ModularAvatarMaterialSetter.cs | 2 +- Runtime/ReactiveObjects/ModularAvatarObjectToggle.cs | 2 +- Runtime/ReactiveObjects/ModularAvatarShapeChanger.cs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Runtime/ReactiveObjects/ModularAvatarMaterialSetter.cs b/Runtime/ReactiveObjects/ModularAvatarMaterialSetter.cs index 0a919dd0..dfe2cf7d 100644 --- a/Runtime/ReactiveObjects/ModularAvatarMaterialSetter.cs +++ b/Runtime/ReactiveObjects/ModularAvatarMaterialSetter.cs @@ -38,7 +38,7 @@ namespace nadena.dev.modular_avatar.core } [AddComponentMenu("Modular Avatar/MA Material Setter")] - [HelpURL("https://modular-avatar.nadena.dev/docs/reference/material-setter?lang=auto")] + [HelpURL("https://modular-avatar.nadena.dev/docs/reference/reaction/material-setter?lang=auto")] public class ModularAvatarMaterialSetter : ReactiveComponent, IHaveObjReferences { [SerializeField] private List m_objects = new(); diff --git a/Runtime/ReactiveObjects/ModularAvatarObjectToggle.cs b/Runtime/ReactiveObjects/ModularAvatarObjectToggle.cs index 93b1421a..74cc69a8 100644 --- a/Runtime/ReactiveObjects/ModularAvatarObjectToggle.cs +++ b/Runtime/ReactiveObjects/ModularAvatarObjectToggle.cs @@ -21,7 +21,7 @@ namespace nadena.dev.modular_avatar.core } [AddComponentMenu("Modular Avatar/MA Object Toggle")] - [HelpURL("https://modular-avatar.nadena.dev/docs/reference/object-toggle?lang=auto")] + [HelpURL("https://modular-avatar.nadena.dev/docs/reference/reaction/object-toggle?lang=auto")] public class ModularAvatarObjectToggle : ReactiveComponent, IHaveObjReferences { [SerializeField] private List m_objects = new(); diff --git a/Runtime/ReactiveObjects/ModularAvatarShapeChanger.cs b/Runtime/ReactiveObjects/ModularAvatarShapeChanger.cs index fd54e96f..4fff480b 100644 --- a/Runtime/ReactiveObjects/ModularAvatarShapeChanger.cs +++ b/Runtime/ReactiveObjects/ModularAvatarShapeChanger.cs @@ -57,7 +57,7 @@ namespace nadena.dev.modular_avatar.core } [AddComponentMenu("Modular Avatar/MA Shape Changer")] - [HelpURL("https://modular-avatar.nadena.dev/docs/reference/shape-changer?lang=auto")] + [HelpURL("https://modular-avatar.nadena.dev/docs/reference/reaction/shape-changer?lang=auto")] public class ModularAvatarShapeChanger : ReactiveComponent, IHaveObjReferences { [SerializeField] [FormerlySerializedAs("Shapes")] From 36e035c8c70be094e41550e1f8fa2b253204430b Mon Sep 17 00:00:00 2001 From: nekobako Date: Thu, 3 Oct 2024 11:03:03 +0900 Subject: [PATCH 61/85] =?UTF-8?q?fix:=20inverted=20reactive=20components?= =?UTF-8?q?=20on=20inactive=20objects=20didn't=20set=20defa=E2=80=A6=20(#1?= =?UTF-8?q?246)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fix: inverted reactive components on inactive objects didn't set default states * chore: use `InitiallyActive` helper --------- Co-authored-by: bd_ --- .../ReactiveObjectAnalyzer.cs | 2 +- .../ReactiveObjectPrepass.cs | 6 +- .../InitialStates/SCDefaultAnimation.cs | 19 +- .../SCDefaultAnimationInactive.prefab | 668 ++++++++++++++++++ .../SCDefaultAnimationInactive.prefab.meta | 7 + .../SCDefaultAnimationInverted.prefab | 668 ++++++++++++++++++ .../SCDefaultAnimationInverted.prefab.meta | 7 + 7 files changed, 1372 insertions(+), 5 deletions(-) create mode 100644 UnitTests~/ShapeChanger/InitialStates/SCDefaultAnimationInactive.prefab create mode 100644 UnitTests~/ShapeChanger/InitialStates/SCDefaultAnimationInactive.prefab.meta create mode 100644 UnitTests~/ShapeChanger/InitialStates/SCDefaultAnimationInverted.prefab create mode 100644 UnitTests~/ShapeChanger/InitialStates/SCDefaultAnimationInverted.prefab.meta diff --git a/Editor/ReactiveObjects/AnimationGeneration/ReactiveObjectAnalyzer.cs b/Editor/ReactiveObjects/AnimationGeneration/ReactiveObjectAnalyzer.cs index b7482b27..defcc3c1 100644 --- a/Editor/ReactiveObjects/AnimationGeneration/ReactiveObjectAnalyzer.cs +++ b/Editor/ReactiveObjects/AnimationGeneration/ReactiveObjectAnalyzer.cs @@ -287,7 +287,7 @@ namespace nadena.dev.modular_avatar.core.editor } var deletions = info.actionGroups.Where(agk => agk.IsDelete).ToList(); - if (deletions.Any(d => d.ControllingConditions.All(c => c.IsConstantActive))) + if (deletions.Any(d => d.InitiallyActive)) { // always deleted shapes.Remove(key); diff --git a/Editor/ReactiveObjects/AnimationGeneration/ReactiveObjectPrepass.cs b/Editor/ReactiveObjects/AnimationGeneration/ReactiveObjectPrepass.cs index 37e0de57..82c5faa8 100644 --- a/Editor/ReactiveObjects/AnimationGeneration/ReactiveObjectPrepass.cs +++ b/Editor/ReactiveObjects/AnimationGeneration/ReactiveObjectPrepass.cs @@ -14,11 +14,11 @@ namespace nadena.dev.modular_avatar.core.editor protected override void Execute(ndmf.BuildContext context) { - var hasShapeChanger = context.AvatarRootObject.GetComponentInChildren() != null; + var hasShapeChanger = context.AvatarRootObject.GetComponentInChildren(true) != null; var hasObjectSwitcher = - context.AvatarRootObject.GetComponentInChildren() != null; + context.AvatarRootObject.GetComponentInChildren(true) != null; var hasMaterialSetter = - context.AvatarRootObject.GetComponentInChildren() != null; + context.AvatarRootObject.GetComponentInChildren(true) != null; if (hasShapeChanger || hasObjectSwitcher || hasMaterialSetter) { var clip = new AnimationClip(); diff --git a/UnitTests~/ShapeChanger/InitialStates/SCDefaultAnimation.cs b/UnitTests~/ShapeChanger/InitialStates/SCDefaultAnimation.cs index 13be9ca7..8a3f9ad6 100644 --- a/UnitTests~/ShapeChanger/InitialStates/SCDefaultAnimation.cs +++ b/UnitTests~/ShapeChanger/InitialStates/SCDefaultAnimation.cs @@ -14,7 +14,24 @@ namespace ShapeChangerTests [Test] public void SetsCorrectInitialStatesAndAnimations() { - var root = CreatePrefab("SCDefaultAnimation.prefab"); + SetsCorrectInitialStatesAndAnimations("SCDefaultAnimation.prefab"); + } + + [Test] + public void SetsCorrectInitialStatesAndAnimationsForInactiveSC() + { + SetsCorrectInitialStatesAndAnimations("SCDefaultAnimationInactive.prefab"); + } + + [Test] + public void SetsCorrectInitialStatesAndAnimationsForInvertedSC() + { + SetsCorrectInitialStatesAndAnimations("SCDefaultAnimationInverted.prefab"); + } + + private void SetsCorrectInitialStatesAndAnimations(string prefabPath) + { + var root = CreatePrefab(prefabPath); AvatarProcessor.ProcessAvatar(root); var fx = (AnimatorController) FindFxController(root).animatorController; diff --git a/UnitTests~/ShapeChanger/InitialStates/SCDefaultAnimationInactive.prefab b/UnitTests~/ShapeChanger/InitialStates/SCDefaultAnimationInactive.prefab new file mode 100644 index 00000000..e7640290 --- /dev/null +++ b/UnitTests~/ShapeChanger/InitialStates/SCDefaultAnimationInactive.prefab @@ -0,0 +1,668 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!1 &1307328145036867423 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 7471115643889882934} + - component: {fileID: 2015798673852064281} + m_Layer: 0 + m_Name: AlwaysOffDelete + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 0 +--- !u!4 &7471115643889882934 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1307328145036867423} + serializedVersion: 2 + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 8936933457054072598} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!114 &2015798673852064281 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1307328145036867423} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 2db441f589c3407bb6fb5f02ff8ab541, type: 3} + m_Name: + m_EditorClassIdentifier: + m_inverted: 1 + m_shapes: + - Object: + referencePath: test mesh + targetObject: {fileID: 0} + ShapeName: key2 + ChangeType: 0 + Value: 100 +--- !u!1 &2598725701317979415 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1861262250770563182} + - component: {fileID: 8866671501173891171} + m_Layer: 0 + m_Name: Toggled + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 0 +--- !u!4 &1861262250770563182 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2598725701317979415} + serializedVersion: 2 + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 8936933457054072598} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!114 &8866671501173891171 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2598725701317979415} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 2db441f589c3407bb6fb5f02ff8ab541, type: 3} + m_Name: + m_EditorClassIdentifier: + m_inverted: 1 + m_shapes: + - Object: + referencePath: test mesh + targetObject: {fileID: 0} + ShapeName: key1 + ChangeType: 1 + Value: 10 +--- !u!1 &2845086157653980983 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 110069860838053623} + - component: {fileID: 8218581995269956798} + m_Layer: 0 + m_Name: AlwaysOffSet + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 0 +--- !u!4 &110069860838053623 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2845086157653980983} + serializedVersion: 2 + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 8936933457054072598} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!114 &8218581995269956798 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2845086157653980983} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 2db441f589c3407bb6fb5f02ff8ab541, type: 3} + m_Name: + m_EditorClassIdentifier: + m_inverted: 1 + m_shapes: + - Object: + referencePath: test mesh + targetObject: {fileID: 0} + ShapeName: key3 + ChangeType: 1 + Value: 100 +--- !u!1 &6385483934583485188 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 569625391371299408} + - component: {fileID: 3841502665919975468} + - component: {fileID: 2918390808850211981} + - component: {fileID: 664065153831629983} + m_Layer: 0 + m_Name: InitialOffToggled + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 0 +--- !u!4 &569625391371299408 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6385483934583485188} + serializedVersion: 2 + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 8936933457054072598} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!114 &3841502665919975468 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6385483934583485188} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 2db441f589c3407bb6fb5f02ff8ab541, type: 3} + m_Name: + m_EditorClassIdentifier: + m_inverted: 0 + m_shapes: + - Object: + referencePath: test mesh + targetObject: {fileID: 0} + ShapeName: key1 + ChangeType: 1 + Value: 20 +--- !u!114 &2918390808850211981 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6385483934583485188} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 3b29d45007c5493d926d2cd45a489529, type: 3} + m_Name: + m_EditorClassIdentifier: + Control: + name: + icon: {fileID: 0} + type: 102 + parameter: + name: + value: 1 + style: 0 + subMenu: {fileID: 0} + subParameters: [] + labels: [] + MenuSource: 1 + menuSource_otherObjectChildren: {fileID: 0} + isSynced: 1 + isSaved: 1 + isDefault: 0 + automaticValue: 0 +--- !u!114 &664065153831629983 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6385483934583485188} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 7ef83cb0c23d4d7c9d41021e544a1978, type: 3} + m_Name: + m_EditorClassIdentifier: + menuToAppend: {fileID: 0} + installTargetMenu: {fileID: 0} +--- !u!1 &6855505756433160176 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 8936933457054072598} + - component: {fileID: 6580323041906195452} + - component: {fileID: 146169679456758165} + - component: {fileID: 5146811121193962360} + m_Layer: 0 + m_Name: SCDefaultAnimationInactive + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &8936933457054072598 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6855505756433160176} + serializedVersion: 2 + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 1.0024816, y: 0.25853348, z: -0.63345385} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: + - {fileID: 1861262250770563182} + - {fileID: 7471115643889882934} + - {fileID: 110069860838053623} + - {fileID: 569625391371299408} + - {fileID: 1326682634762807916} + m_Father: {fileID: 0} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!95 &6580323041906195452 +Animator: + serializedVersion: 5 + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6855505756433160176} + m_Enabled: 1 + m_Avatar: {fileID: 0} + m_Controller: {fileID: 0} + m_CullingMode: 0 + m_UpdateMode: 0 + m_ApplyRootMotion: 0 + m_LinearVelocityBlending: 0 + m_StabilizeFeet: 0 + m_WarningMessage: + m_HasTransformHierarchy: 1 + m_AllowConstantClipSamplingOptimization: 1 + m_KeepAnimatorStateOnDisable: 0 + m_WriteDefaultValuesOnDisable: 0 +--- !u!114 &146169679456758165 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6855505756433160176} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 542108242, guid: 67cc4cb7839cd3741b63733d5adf0442, type: 3} + m_Name: + m_EditorClassIdentifier: + Name: + ViewPosition: {x: 0, y: 1.6, z: 0.2} + Animations: 0 + ScaleIPD: 1 + lipSync: 0 + lipSyncJawBone: {fileID: 0} + lipSyncJawClosed: {x: 0, y: 0, z: 0, w: 1} + lipSyncJawOpen: {x: 0, y: 0, z: 0, w: 1} + VisemeSkinnedMesh: {fileID: 0} + MouthOpenBlendShapeName: Facial_Blends.Jaw_Down + VisemeBlendShapes: [] + unityVersion: + portraitCameraPositionOffset: {x: 0, y: 0, z: 0} + portraitCameraRotationOffset: {x: 0, y: 1, z: 0, w: -0.00000004371139} + networkIDs: [] + customExpressions: 0 + expressionsMenu: {fileID: 0} + expressionParameters: {fileID: 0} + enableEyeLook: 0 + customEyeLookSettings: + eyeMovement: + confidence: 0.5 + excitement: 0.5 + leftEye: {fileID: 0} + rightEye: {fileID: 0} + eyesLookingStraight: + linked: 1 + left: {x: 0, y: 0, z: 0, w: 0} + right: {x: 0, y: 0, z: 0, w: 0} + eyesLookingUp: + linked: 1 + left: {x: 0, y: 0, z: 0, w: 0} + right: {x: 0, y: 0, z: 0, w: 0} + eyesLookingDown: + linked: 1 + left: {x: 0, y: 0, z: 0, w: 0} + right: {x: 0, y: 0, z: 0, w: 0} + eyesLookingLeft: + linked: 1 + left: {x: 0, y: 0, z: 0, w: 0} + right: {x: 0, y: 0, z: 0, w: 0} + eyesLookingRight: + linked: 1 + left: {x: 0, y: 0, z: 0, w: 0} + right: {x: 0, y: 0, z: 0, w: 0} + eyelidType: 0 + upperLeftEyelid: {fileID: 0} + upperRightEyelid: {fileID: 0} + lowerLeftEyelid: {fileID: 0} + lowerRightEyelid: {fileID: 0} + eyelidsDefault: + upper: + linked: 1 + left: {x: 0, y: 0, z: 0, w: 0} + right: {x: 0, y: 0, z: 0, w: 0} + lower: + linked: 1 + left: {x: 0, y: 0, z: 0, w: 0} + right: {x: 0, y: 0, z: 0, w: 0} + eyelidsClosed: + upper: + linked: 1 + left: {x: 0, y: 0, z: 0, w: 0} + right: {x: 0, y: 0, z: 0, w: 0} + lower: + linked: 1 + left: {x: 0, y: 0, z: 0, w: 0} + right: {x: 0, y: 0, z: 0, w: 0} + eyelidsLookingUp: + upper: + linked: 1 + left: {x: 0, y: 0, z: 0, w: 0} + right: {x: 0, y: 0, z: 0, w: 0} + lower: + linked: 1 + left: {x: 0, y: 0, z: 0, w: 0} + right: {x: 0, y: 0, z: 0, w: 0} + eyelidsLookingDown: + upper: + linked: 1 + left: {x: 0, y: 0, z: 0, w: 0} + right: {x: 0, y: 0, z: 0, w: 0} + lower: + linked: 1 + left: {x: 0, y: 0, z: 0, w: 0} + right: {x: 0, y: 0, z: 0, w: 0} + eyelidsSkinnedMesh: {fileID: 0} + eyelidsBlendshapes: + customizeAnimationLayers: 0 + baseAnimationLayers: + - isEnabled: 0 + type: 0 + animatorController: {fileID: 0} + mask: {fileID: 0} + isDefault: 1 + - isEnabled: 0 + type: 4 + animatorController: {fileID: 0} + mask: {fileID: 0} + isDefault: 1 + - isEnabled: 0 + type: 5 + animatorController: {fileID: 0} + mask: {fileID: 0} + isDefault: 1 + specialAnimationLayers: + - isEnabled: 0 + type: 6 + animatorController: {fileID: 0} + mask: {fileID: 0} + isDefault: 1 + - isEnabled: 0 + type: 7 + animatorController: {fileID: 0} + mask: {fileID: 0} + isDefault: 1 + - isEnabled: 0 + type: 8 + animatorController: {fileID: 0} + mask: {fileID: 0} + isDefault: 1 + AnimationPreset: {fileID: 0} + animationHashSet: [] + autoFootsteps: 1 + autoLocomotion: 1 + collider_head: + isMirrored: 1 + state: 0 + transform: {fileID: 0} + radius: 0 + height: 0 + position: {x: 0, y: 0, z: 0} + rotation: {x: 0, y: 0, z: 0, w: 1} + collider_torso: + isMirrored: 1 + state: 0 + transform: {fileID: 0} + radius: 0 + height: 0 + position: {x: 0, y: 0, z: 0} + rotation: {x: 0, y: 0, z: 0, w: 1} + collider_footR: + isMirrored: 1 + state: 0 + transform: {fileID: 0} + radius: 0 + height: 0 + position: {x: 0, y: 0, z: 0} + rotation: {x: 0, y: 0, z: 0, w: 1} + collider_footL: + isMirrored: 1 + state: 0 + transform: {fileID: 0} + radius: 0 + height: 0 + position: {x: 0, y: 0, z: 0} + rotation: {x: 0, y: 0, z: 0, w: 1} + collider_handR: + isMirrored: 1 + state: 0 + transform: {fileID: 0} + radius: 0 + height: 0 + position: {x: 0, y: 0, z: 0} + rotation: {x: 0, y: 0, z: 0, w: 1} + collider_handL: + isMirrored: 1 + state: 0 + transform: {fileID: 0} + radius: 0 + height: 0 + position: {x: 0, y: 0, z: 0} + rotation: {x: 0, y: 0, z: 0, w: 1} + collider_fingerIndexL: + isMirrored: 1 + state: 0 + transform: {fileID: 0} + radius: 0 + height: 0 + position: {x: 0, y: 0, z: 0} + rotation: {x: 0, y: 0, z: 0, w: 1} + collider_fingerMiddleL: + isMirrored: 1 + state: 0 + transform: {fileID: 0} + radius: 0 + height: 0 + position: {x: 0, y: 0, z: 0} + rotation: {x: 0, y: 0, z: 0, w: 1} + collider_fingerRingL: + isMirrored: 1 + state: 0 + transform: {fileID: 0} + radius: 0 + height: 0 + position: {x: 0, y: 0, z: 0} + rotation: {x: 0, y: 0, z: 0, w: 1} + collider_fingerLittleL: + isMirrored: 1 + state: 0 + transform: {fileID: 0} + radius: 0 + height: 0 + position: {x: 0, y: 0, z: 0} + rotation: {x: 0, y: 0, z: 0, w: 1} + collider_fingerIndexR: + isMirrored: 1 + state: 0 + transform: {fileID: 0} + radius: 0 + height: 0 + position: {x: 0, y: 0, z: 0} + rotation: {x: 0, y: 0, z: 0, w: 1} + collider_fingerMiddleR: + isMirrored: 1 + state: 0 + transform: {fileID: 0} + radius: 0 + height: 0 + position: {x: 0, y: 0, z: 0} + rotation: {x: 0, y: 0, z: 0, w: 1} + collider_fingerRingR: + isMirrored: 1 + state: 0 + transform: {fileID: 0} + radius: 0 + height: 0 + position: {x: 0, y: 0, z: 0} + rotation: {x: 0, y: 0, z: 0, w: 1} + collider_fingerLittleR: + isMirrored: 1 + state: 0 + transform: {fileID: 0} + radius: 0 + height: 0 + position: {x: 0, y: 0, z: 0} + rotation: {x: 0, y: 0, z: 0, w: 1} +--- !u!114 &5146811121193962360 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6855505756433160176} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: -1427037861, guid: 4ecd63eff847044b68db9453ce219299, type: 3} + m_Name: + m_EditorClassIdentifier: + launchedFromSDKPipeline: 0 + completedSDKPipeline: 0 + blueprintId: + contentType: 0 + assetBundleUnityVersion: + fallbackStatus: 0 +--- !u!1001 &1577363430154308999 +PrefabInstance: + m_ObjectHideFlags: 0 + serializedVersion: 2 + m_Modification: + serializedVersion: 3 + m_TransformParent: {fileID: 8936933457054072598} + m_Modifications: + - target: {fileID: -8679921383154817045, guid: cd28f61dacdc2424d951194ff69ba154, type: 3} + propertyPath: m_LocalPosition.x + value: -0 + objectReference: {fileID: 0} + - target: {fileID: -8679921383154817045, guid: cd28f61dacdc2424d951194ff69ba154, type: 3} + propertyPath: m_LocalPosition.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: -8679921383154817045, guid: cd28f61dacdc2424d951194ff69ba154, type: 3} + propertyPath: m_LocalPosition.z + value: 0 + objectReference: {fileID: 0} + - target: {fileID: -8679921383154817045, guid: cd28f61dacdc2424d951194ff69ba154, type: 3} + propertyPath: m_LocalRotation.w + value: 0.7071067 + objectReference: {fileID: 0} + - target: {fileID: -8679921383154817045, guid: cd28f61dacdc2424d951194ff69ba154, type: 3} + propertyPath: m_LocalRotation.x + value: -0.7071068 + objectReference: {fileID: 0} + - target: {fileID: -8679921383154817045, guid: cd28f61dacdc2424d951194ff69ba154, type: 3} + propertyPath: m_LocalRotation.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: -8679921383154817045, guid: cd28f61dacdc2424d951194ff69ba154, type: 3} + propertyPath: m_LocalRotation.z + value: -0 + objectReference: {fileID: 0} + - target: {fileID: -8679921383154817045, guid: cd28f61dacdc2424d951194ff69ba154, type: 3} + propertyPath: m_LocalEulerAnglesHint.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: -8679921383154817045, guid: cd28f61dacdc2424d951194ff69ba154, type: 3} + propertyPath: m_LocalEulerAnglesHint.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: -8679921383154817045, guid: cd28f61dacdc2424d951194ff69ba154, type: 3} + propertyPath: m_LocalEulerAnglesHint.z + value: 0 + objectReference: {fileID: 0} + - target: {fileID: -3887185075125053422, guid: cd28f61dacdc2424d951194ff69ba154, type: 3} + propertyPath: m_DirtyAABB + value: 0 + objectReference: {fileID: 0} + - target: {fileID: -3887185075125053422, guid: cd28f61dacdc2424d951194ff69ba154, type: 3} + propertyPath: m_AABB.m_Extent.x + value: 1 + objectReference: {fileID: 0} + - target: {fileID: -3887185075125053422, guid: cd28f61dacdc2424d951194ff69ba154, type: 3} + propertyPath: m_AABB.m_Extent.y + value: 1 + objectReference: {fileID: 0} + - target: {fileID: -3887185075125053422, guid: cd28f61dacdc2424d951194ff69ba154, type: 3} + propertyPath: m_BlendShapeWeights.Array.data[0] + value: 5 + objectReference: {fileID: 0} + - target: {fileID: -3887185075125053422, guid: cd28f61dacdc2424d951194ff69ba154, type: 3} + propertyPath: m_BlendShapeWeights.Array.data[1] + value: 6 + objectReference: {fileID: 0} + - target: {fileID: -3887185075125053422, guid: cd28f61dacdc2424d951194ff69ba154, type: 3} + propertyPath: m_BlendShapeWeights.Array.data[2] + value: 7 + objectReference: {fileID: 0} + - target: {fileID: 919132149155446097, guid: cd28f61dacdc2424d951194ff69ba154, type: 3} + propertyPath: m_Name + value: test mesh + objectReference: {fileID: 0} + m_RemovedComponents: [] + m_RemovedGameObjects: [] + m_AddedGameObjects: [] + m_AddedComponents: [] + m_SourcePrefab: {fileID: 100100000, guid: cd28f61dacdc2424d951194ff69ba154, type: 3} +--- !u!4 &1326682634762807916 stripped +Transform: + m_CorrespondingSourceObject: {fileID: -8679921383154817045, guid: cd28f61dacdc2424d951194ff69ba154, type: 3} + m_PrefabInstance: {fileID: 1577363430154308999} + m_PrefabAsset: {fileID: 0} diff --git a/UnitTests~/ShapeChanger/InitialStates/SCDefaultAnimationInactive.prefab.meta b/UnitTests~/ShapeChanger/InitialStates/SCDefaultAnimationInactive.prefab.meta new file mode 100644 index 00000000..d37cf9c1 --- /dev/null +++ b/UnitTests~/ShapeChanger/InitialStates/SCDefaultAnimationInactive.prefab.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 4744d7b0db7db0d459f3aa7e6a0cf7db +PrefabImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnitTests~/ShapeChanger/InitialStates/SCDefaultAnimationInverted.prefab b/UnitTests~/ShapeChanger/InitialStates/SCDefaultAnimationInverted.prefab new file mode 100644 index 00000000..daa2600d --- /dev/null +++ b/UnitTests~/ShapeChanger/InitialStates/SCDefaultAnimationInverted.prefab @@ -0,0 +1,668 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!1 &1307328145036867423 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 7471115643889882934} + - component: {fileID: 2015798673852064281} + m_Layer: 0 + m_Name: AlwaysOffDelete + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 0 +--- !u!4 &7471115643889882934 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1307328145036867423} + serializedVersion: 2 + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 8936933457054072598} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!114 &2015798673852064281 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1307328145036867423} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 2db441f589c3407bb6fb5f02ff8ab541, type: 3} + m_Name: + m_EditorClassIdentifier: + m_inverted: 1 + m_shapes: + - Object: + referencePath: test mesh + targetObject: {fileID: 0} + ShapeName: key2 + ChangeType: 0 + Value: 100 +--- !u!1 &2598725701317979415 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1861262250770563182} + - component: {fileID: 8866671501173891171} + m_Layer: 0 + m_Name: Toggled + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 0 +--- !u!4 &1861262250770563182 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2598725701317979415} + serializedVersion: 2 + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 8936933457054072598} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!114 &8866671501173891171 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2598725701317979415} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 2db441f589c3407bb6fb5f02ff8ab541, type: 3} + m_Name: + m_EditorClassIdentifier: + m_inverted: 1 + m_shapes: + - Object: + referencePath: test mesh + targetObject: {fileID: 0} + ShapeName: key1 + ChangeType: 1 + Value: 10 +--- !u!1 &2845086157653980983 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 110069860838053623} + - component: {fileID: 8218581995269956798} + m_Layer: 0 + m_Name: AlwaysOffSet + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 0 +--- !u!4 &110069860838053623 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2845086157653980983} + serializedVersion: 2 + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 8936933457054072598} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!114 &8218581995269956798 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2845086157653980983} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 2db441f589c3407bb6fb5f02ff8ab541, type: 3} + m_Name: + m_EditorClassIdentifier: + m_inverted: 1 + m_shapes: + - Object: + referencePath: test mesh + targetObject: {fileID: 0} + ShapeName: key3 + ChangeType: 1 + Value: 100 +--- !u!1 &6385483934583485188 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 569625391371299408} + - component: {fileID: 3841502665919975468} + - component: {fileID: 2918390808850211981} + - component: {fileID: 664065153831629983} + m_Layer: 0 + m_Name: InitialOnToggled + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &569625391371299408 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6385483934583485188} + serializedVersion: 2 + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 8936933457054072598} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!114 &3841502665919975468 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6385483934583485188} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 2db441f589c3407bb6fb5f02ff8ab541, type: 3} + m_Name: + m_EditorClassIdentifier: + m_inverted: 1 + m_shapes: + - Object: + referencePath: test mesh + targetObject: {fileID: 0} + ShapeName: key1 + ChangeType: 1 + Value: 20 +--- !u!114 &2918390808850211981 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6385483934583485188} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 3b29d45007c5493d926d2cd45a489529, type: 3} + m_Name: + m_EditorClassIdentifier: + Control: + name: + icon: {fileID: 0} + type: 102 + parameter: + name: + value: 1 + style: 0 + subMenu: {fileID: 0} + subParameters: [] + labels: [] + MenuSource: 1 + menuSource_otherObjectChildren: {fileID: 0} + isSynced: 1 + isSaved: 1 + isDefault: 1 + automaticValue: 0 +--- !u!114 &664065153831629983 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6385483934583485188} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 7ef83cb0c23d4d7c9d41021e544a1978, type: 3} + m_Name: + m_EditorClassIdentifier: + menuToAppend: {fileID: 0} + installTargetMenu: {fileID: 0} +--- !u!1 &6855505756433160176 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 8936933457054072598} + - component: {fileID: 6580323041906195452} + - component: {fileID: 146169679456758165} + - component: {fileID: 5146811121193962360} + m_Layer: 0 + m_Name: SCDefaultAnimationInverted + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &8936933457054072598 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6855505756433160176} + serializedVersion: 2 + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 1.0024816, y: 0.25853348, z: -0.63345385} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: + - {fileID: 1861262250770563182} + - {fileID: 7471115643889882934} + - {fileID: 110069860838053623} + - {fileID: 569625391371299408} + - {fileID: 1326682634762807916} + m_Father: {fileID: 0} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!95 &6580323041906195452 +Animator: + serializedVersion: 5 + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6855505756433160176} + m_Enabled: 1 + m_Avatar: {fileID: 0} + m_Controller: {fileID: 0} + m_CullingMode: 0 + m_UpdateMode: 0 + m_ApplyRootMotion: 0 + m_LinearVelocityBlending: 0 + m_StabilizeFeet: 0 + m_WarningMessage: + m_HasTransformHierarchy: 1 + m_AllowConstantClipSamplingOptimization: 1 + m_KeepAnimatorStateOnDisable: 0 + m_WriteDefaultValuesOnDisable: 0 +--- !u!114 &146169679456758165 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6855505756433160176} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 542108242, guid: 67cc4cb7839cd3741b63733d5adf0442, type: 3} + m_Name: + m_EditorClassIdentifier: + Name: + ViewPosition: {x: 0, y: 1.6, z: 0.2} + Animations: 0 + ScaleIPD: 1 + lipSync: 0 + lipSyncJawBone: {fileID: 0} + lipSyncJawClosed: {x: 0, y: 0, z: 0, w: 1} + lipSyncJawOpen: {x: 0, y: 0, z: 0, w: 1} + VisemeSkinnedMesh: {fileID: 0} + MouthOpenBlendShapeName: Facial_Blends.Jaw_Down + VisemeBlendShapes: [] + unityVersion: + portraitCameraPositionOffset: {x: 0, y: 0, z: 0} + portraitCameraRotationOffset: {x: 0, y: 1, z: 0, w: -0.00000004371139} + networkIDs: [] + customExpressions: 0 + expressionsMenu: {fileID: 0} + expressionParameters: {fileID: 0} + enableEyeLook: 0 + customEyeLookSettings: + eyeMovement: + confidence: 0.5 + excitement: 0.5 + leftEye: {fileID: 0} + rightEye: {fileID: 0} + eyesLookingStraight: + linked: 1 + left: {x: 0, y: 0, z: 0, w: 0} + right: {x: 0, y: 0, z: 0, w: 0} + eyesLookingUp: + linked: 1 + left: {x: 0, y: 0, z: 0, w: 0} + right: {x: 0, y: 0, z: 0, w: 0} + eyesLookingDown: + linked: 1 + left: {x: 0, y: 0, z: 0, w: 0} + right: {x: 0, y: 0, z: 0, w: 0} + eyesLookingLeft: + linked: 1 + left: {x: 0, y: 0, z: 0, w: 0} + right: {x: 0, y: 0, z: 0, w: 0} + eyesLookingRight: + linked: 1 + left: {x: 0, y: 0, z: 0, w: 0} + right: {x: 0, y: 0, z: 0, w: 0} + eyelidType: 0 + upperLeftEyelid: {fileID: 0} + upperRightEyelid: {fileID: 0} + lowerLeftEyelid: {fileID: 0} + lowerRightEyelid: {fileID: 0} + eyelidsDefault: + upper: + linked: 1 + left: {x: 0, y: 0, z: 0, w: 0} + right: {x: 0, y: 0, z: 0, w: 0} + lower: + linked: 1 + left: {x: 0, y: 0, z: 0, w: 0} + right: {x: 0, y: 0, z: 0, w: 0} + eyelidsClosed: + upper: + linked: 1 + left: {x: 0, y: 0, z: 0, w: 0} + right: {x: 0, y: 0, z: 0, w: 0} + lower: + linked: 1 + left: {x: 0, y: 0, z: 0, w: 0} + right: {x: 0, y: 0, z: 0, w: 0} + eyelidsLookingUp: + upper: + linked: 1 + left: {x: 0, y: 0, z: 0, w: 0} + right: {x: 0, y: 0, z: 0, w: 0} + lower: + linked: 1 + left: {x: 0, y: 0, z: 0, w: 0} + right: {x: 0, y: 0, z: 0, w: 0} + eyelidsLookingDown: + upper: + linked: 1 + left: {x: 0, y: 0, z: 0, w: 0} + right: {x: 0, y: 0, z: 0, w: 0} + lower: + linked: 1 + left: {x: 0, y: 0, z: 0, w: 0} + right: {x: 0, y: 0, z: 0, w: 0} + eyelidsSkinnedMesh: {fileID: 0} + eyelidsBlendshapes: + customizeAnimationLayers: 0 + baseAnimationLayers: + - isEnabled: 0 + type: 0 + animatorController: {fileID: 0} + mask: {fileID: 0} + isDefault: 1 + - isEnabled: 0 + type: 4 + animatorController: {fileID: 0} + mask: {fileID: 0} + isDefault: 1 + - isEnabled: 0 + type: 5 + animatorController: {fileID: 0} + mask: {fileID: 0} + isDefault: 1 + specialAnimationLayers: + - isEnabled: 0 + type: 6 + animatorController: {fileID: 0} + mask: {fileID: 0} + isDefault: 1 + - isEnabled: 0 + type: 7 + animatorController: {fileID: 0} + mask: {fileID: 0} + isDefault: 1 + - isEnabled: 0 + type: 8 + animatorController: {fileID: 0} + mask: {fileID: 0} + isDefault: 1 + AnimationPreset: {fileID: 0} + animationHashSet: [] + autoFootsteps: 1 + autoLocomotion: 1 + collider_head: + isMirrored: 1 + state: 0 + transform: {fileID: 0} + radius: 0 + height: 0 + position: {x: 0, y: 0, z: 0} + rotation: {x: 0, y: 0, z: 0, w: 1} + collider_torso: + isMirrored: 1 + state: 0 + transform: {fileID: 0} + radius: 0 + height: 0 + position: {x: 0, y: 0, z: 0} + rotation: {x: 0, y: 0, z: 0, w: 1} + collider_footR: + isMirrored: 1 + state: 0 + transform: {fileID: 0} + radius: 0 + height: 0 + position: {x: 0, y: 0, z: 0} + rotation: {x: 0, y: 0, z: 0, w: 1} + collider_footL: + isMirrored: 1 + state: 0 + transform: {fileID: 0} + radius: 0 + height: 0 + position: {x: 0, y: 0, z: 0} + rotation: {x: 0, y: 0, z: 0, w: 1} + collider_handR: + isMirrored: 1 + state: 0 + transform: {fileID: 0} + radius: 0 + height: 0 + position: {x: 0, y: 0, z: 0} + rotation: {x: 0, y: 0, z: 0, w: 1} + collider_handL: + isMirrored: 1 + state: 0 + transform: {fileID: 0} + radius: 0 + height: 0 + position: {x: 0, y: 0, z: 0} + rotation: {x: 0, y: 0, z: 0, w: 1} + collider_fingerIndexL: + isMirrored: 1 + state: 0 + transform: {fileID: 0} + radius: 0 + height: 0 + position: {x: 0, y: 0, z: 0} + rotation: {x: 0, y: 0, z: 0, w: 1} + collider_fingerMiddleL: + isMirrored: 1 + state: 0 + transform: {fileID: 0} + radius: 0 + height: 0 + position: {x: 0, y: 0, z: 0} + rotation: {x: 0, y: 0, z: 0, w: 1} + collider_fingerRingL: + isMirrored: 1 + state: 0 + transform: {fileID: 0} + radius: 0 + height: 0 + position: {x: 0, y: 0, z: 0} + rotation: {x: 0, y: 0, z: 0, w: 1} + collider_fingerLittleL: + isMirrored: 1 + state: 0 + transform: {fileID: 0} + radius: 0 + height: 0 + position: {x: 0, y: 0, z: 0} + rotation: {x: 0, y: 0, z: 0, w: 1} + collider_fingerIndexR: + isMirrored: 1 + state: 0 + transform: {fileID: 0} + radius: 0 + height: 0 + position: {x: 0, y: 0, z: 0} + rotation: {x: 0, y: 0, z: 0, w: 1} + collider_fingerMiddleR: + isMirrored: 1 + state: 0 + transform: {fileID: 0} + radius: 0 + height: 0 + position: {x: 0, y: 0, z: 0} + rotation: {x: 0, y: 0, z: 0, w: 1} + collider_fingerRingR: + isMirrored: 1 + state: 0 + transform: {fileID: 0} + radius: 0 + height: 0 + position: {x: 0, y: 0, z: 0} + rotation: {x: 0, y: 0, z: 0, w: 1} + collider_fingerLittleR: + isMirrored: 1 + state: 0 + transform: {fileID: 0} + radius: 0 + height: 0 + position: {x: 0, y: 0, z: 0} + rotation: {x: 0, y: 0, z: 0, w: 1} +--- !u!114 &5146811121193962360 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6855505756433160176} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: -1427037861, guid: 4ecd63eff847044b68db9453ce219299, type: 3} + m_Name: + m_EditorClassIdentifier: + launchedFromSDKPipeline: 0 + completedSDKPipeline: 0 + blueprintId: + contentType: 0 + assetBundleUnityVersion: + fallbackStatus: 0 +--- !u!1001 &1577363430154308999 +PrefabInstance: + m_ObjectHideFlags: 0 + serializedVersion: 2 + m_Modification: + serializedVersion: 3 + m_TransformParent: {fileID: 8936933457054072598} + m_Modifications: + - target: {fileID: -8679921383154817045, guid: cd28f61dacdc2424d951194ff69ba154, type: 3} + propertyPath: m_LocalPosition.x + value: -0 + objectReference: {fileID: 0} + - target: {fileID: -8679921383154817045, guid: cd28f61dacdc2424d951194ff69ba154, type: 3} + propertyPath: m_LocalPosition.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: -8679921383154817045, guid: cd28f61dacdc2424d951194ff69ba154, type: 3} + propertyPath: m_LocalPosition.z + value: 0 + objectReference: {fileID: 0} + - target: {fileID: -8679921383154817045, guid: cd28f61dacdc2424d951194ff69ba154, type: 3} + propertyPath: m_LocalRotation.w + value: 0.7071067 + objectReference: {fileID: 0} + - target: {fileID: -8679921383154817045, guid: cd28f61dacdc2424d951194ff69ba154, type: 3} + propertyPath: m_LocalRotation.x + value: -0.7071068 + objectReference: {fileID: 0} + - target: {fileID: -8679921383154817045, guid: cd28f61dacdc2424d951194ff69ba154, type: 3} + propertyPath: m_LocalRotation.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: -8679921383154817045, guid: cd28f61dacdc2424d951194ff69ba154, type: 3} + propertyPath: m_LocalRotation.z + value: -0 + objectReference: {fileID: 0} + - target: {fileID: -8679921383154817045, guid: cd28f61dacdc2424d951194ff69ba154, type: 3} + propertyPath: m_LocalEulerAnglesHint.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: -8679921383154817045, guid: cd28f61dacdc2424d951194ff69ba154, type: 3} + propertyPath: m_LocalEulerAnglesHint.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: -8679921383154817045, guid: cd28f61dacdc2424d951194ff69ba154, type: 3} + propertyPath: m_LocalEulerAnglesHint.z + value: 0 + objectReference: {fileID: 0} + - target: {fileID: -3887185075125053422, guid: cd28f61dacdc2424d951194ff69ba154, type: 3} + propertyPath: m_DirtyAABB + value: 0 + objectReference: {fileID: 0} + - target: {fileID: -3887185075125053422, guid: cd28f61dacdc2424d951194ff69ba154, type: 3} + propertyPath: m_AABB.m_Extent.x + value: 1 + objectReference: {fileID: 0} + - target: {fileID: -3887185075125053422, guid: cd28f61dacdc2424d951194ff69ba154, type: 3} + propertyPath: m_AABB.m_Extent.y + value: 1 + objectReference: {fileID: 0} + - target: {fileID: -3887185075125053422, guid: cd28f61dacdc2424d951194ff69ba154, type: 3} + propertyPath: m_BlendShapeWeights.Array.data[0] + value: 5 + objectReference: {fileID: 0} + - target: {fileID: -3887185075125053422, guid: cd28f61dacdc2424d951194ff69ba154, type: 3} + propertyPath: m_BlendShapeWeights.Array.data[1] + value: 6 + objectReference: {fileID: 0} + - target: {fileID: -3887185075125053422, guid: cd28f61dacdc2424d951194ff69ba154, type: 3} + propertyPath: m_BlendShapeWeights.Array.data[2] + value: 7 + objectReference: {fileID: 0} + - target: {fileID: 919132149155446097, guid: cd28f61dacdc2424d951194ff69ba154, type: 3} + propertyPath: m_Name + value: test mesh + objectReference: {fileID: 0} + m_RemovedComponents: [] + m_RemovedGameObjects: [] + m_AddedGameObjects: [] + m_AddedComponents: [] + m_SourcePrefab: {fileID: 100100000, guid: cd28f61dacdc2424d951194ff69ba154, type: 3} +--- !u!4 &1326682634762807916 stripped +Transform: + m_CorrespondingSourceObject: {fileID: -8679921383154817045, guid: cd28f61dacdc2424d951194ff69ba154, type: 3} + m_PrefabInstance: {fileID: 1577363430154308999} + m_PrefabAsset: {fileID: 0} diff --git a/UnitTests~/ShapeChanger/InitialStates/SCDefaultAnimationInverted.prefab.meta b/UnitTests~/ShapeChanger/InitialStates/SCDefaultAnimationInverted.prefab.meta new file mode 100644 index 00000000..487346d8 --- /dev/null +++ b/UnitTests~/ShapeChanger/InitialStates/SCDefaultAnimationInverted.prefab.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: c86e54d4b828d364aa677a5b3ce7be12 +PrefabImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: From 02204c272f4d326e81baea3ba5e65538d5611b0c Mon Sep 17 00:00:00 2001 From: bd_ Date: Wed, 2 Oct 2024 19:03:44 -0700 Subject: [PATCH 62/85] Revert "fix: remove unnecessory exit transitions for reactive components (#1161)" (#1248) This reverts commit 9dfa0dae23d9d4aa6e80e9c9d691e363dc297fdc. Those transitions are needed when controlling the same object from multiple parameters. Closes: #1233 --- .../AnimationGeneration/ReactiveObjectPass.cs | 40 ++++++++++--------- 1 file changed, 21 insertions(+), 19 deletions(-) diff --git a/Editor/ReactiveObjects/AnimationGeneration/ReactiveObjectPass.cs b/Editor/ReactiveObjects/AnimationGeneration/ReactiveObjectPass.cs index 793fba66..69a0ede7 100644 --- a/Editor/ReactiveObjects/AnimationGeneration/ReactiveObjectPass.cs +++ b/Editor/ReactiveObjects/AnimationGeneration/ReactiveObjectPass.cs @@ -300,8 +300,7 @@ namespace nadena.dev.modular_avatar.core.editor var transitionBuffer = new List<(AnimatorState, List)>(); var entryTransitions = new List(); - var initialStateTransitionList = new List(); - transitionBuffer.Add((initialState, initialStateTransitionList)); + transitionBuffer.Add((initialState, new List())); foreach (var group in info.actionGroups.Skip(lastConstant)) { @@ -321,30 +320,33 @@ namespace nadena.dev.modular_avatar.core.editor var conditions = GetTransitionConditions(asc, group); - if (!group.Inverted) + foreach (var (st, transitions) in transitionBuffer) { - var transition = new AnimatorStateTransition + if (!group.Inverted) { - isExit = true, - hasExitTime = false, - duration = 0, - hasFixedDuration = true, - conditions = (AnimatorCondition[])conditions.Clone() - }; - initialStateTransitionList.Add(transition); - } - else - { - foreach (var cond in conditions) - { - initialStateTransitionList.Add(new AnimatorStateTransition + var transition = new AnimatorStateTransition { isExit = true, hasExitTime = false, duration = 0, hasFixedDuration = true, - conditions = new[] { InvertCondition(cond) } - }); + conditions = (AnimatorCondition[])conditions.Clone() + }; + transitions.Add(transition); + } + else + { + foreach (var cond in conditions) + { + transitions.Add(new AnimatorStateTransition + { + isExit = true, + hasExitTime = false, + duration = 0, + hasFixedDuration = true, + conditions = new[] { InvertCondition(cond) } + }); + } } } From 409592f952b3e93a61b99b800623b6cef4bd6cbd Mon Sep 17 00:00:00 2001 From: bd_ Date: Wed, 2 Oct 2024 19:42:19 -0700 Subject: [PATCH 63/85] fix(rc): constant-off objects are not handled correctly (#1249) Closes: #1233 --- Editor/ReactiveObjects/AnimationGeneration/ReactionRule.cs | 4 +++- .../AnimationGeneration/ReactiveObjectAnalyzer.cs | 2 +- .../ShapeChanger/InitialStates/SCDefaultAnimation.prefab | 3 ++- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/Editor/ReactiveObjects/AnimationGeneration/ReactionRule.cs b/Editor/ReactiveObjects/AnimationGeneration/ReactionRule.cs index 68ae3154..dcf040ea 100644 --- a/Editor/ReactiveObjects/AnimationGeneration/ReactionRule.cs +++ b/Editor/ReactiveObjects/AnimationGeneration/ReactionRule.cs @@ -35,7 +35,9 @@ namespace nadena.dev.modular_avatar.core.editor public bool Inverted; - public bool IsConstant => ControllingConditions.Count == 0 || ControllingConditions.All(c => c.IsConstant); + public bool IsConstant => ControllingConditions.Count == 0 + || ControllingConditions.All(c => c.IsConstant) + || ControllingConditions.Any(c => c.IsConstant && !c.InitiallyActive); public bool IsConstantOn => IsConstant && InitiallyActive; public override string ToString() diff --git a/Editor/ReactiveObjects/AnimationGeneration/ReactiveObjectAnalyzer.cs b/Editor/ReactiveObjects/AnimationGeneration/ReactiveObjectAnalyzer.cs index defcc3c1..745c5184 100644 --- a/Editor/ReactiveObjects/AnimationGeneration/ReactiveObjectAnalyzer.cs +++ b/Editor/ReactiveObjects/AnimationGeneration/ReactiveObjectAnalyzer.cs @@ -144,7 +144,7 @@ namespace nadena.dev.modular_avatar.core.editor HashSet toggledObjects = new(); if (asc == null) return; - + foreach (var targetProp in shapes.Keys) if (targetProp is { TargetObject: GameObject go, PropertyName: "m_IsActive" }) toggledObjects.Add(go); diff --git a/UnitTests~/ShapeChanger/InitialStates/SCDefaultAnimation.prefab b/UnitTests~/ShapeChanger/InitialStates/SCDefaultAnimation.prefab index 71de2608..6dbfb2b7 100644 --- a/UnitTests~/ShapeChanger/InitialStates/SCDefaultAnimation.prefab +++ b/UnitTests~/ShapeChanger/InitialStates/SCDefaultAnimation.prefab @@ -183,7 +183,7 @@ GameObject: m_Icon: {fileID: 0} m_NavMeshLayer: 0 m_StaticEditorFlags: 0 - m_IsActive: 0 + m_IsActive: 1 --- !u!4 &569625391371299408 Transform: m_ObjectHideFlags: 0 @@ -250,6 +250,7 @@ MonoBehaviour: isSynced: 1 isSaved: 1 isDefault: 0 + automaticValue: 0 --- !u!114 &664065153831629983 MonoBehaviour: m_ObjectHideFlags: 0 From 4ec36ca489c2b14f5adf05d06f62342a75bd36e7 Mon Sep 17 00:00:00 2001 From: bd_ Date: Wed, 2 Oct 2024 19:48:38 -0700 Subject: [PATCH 64/85] fix: shape changer preview overrides default blendshape values inappropriately (#1250) Closes: #1227 --- Editor/ReactiveObjects/ShapeChangerPreview.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/Editor/ReactiveObjects/ShapeChangerPreview.cs b/Editor/ReactiveObjects/ShapeChangerPreview.cs index d17c7a37..2ca011c7 100644 --- a/Editor/ReactiveObjects/ShapeChangerPreview.cs +++ b/Editor/ReactiveObjects/ShapeChangerPreview.cs @@ -101,6 +101,7 @@ namespace nadena.dev.modular_avatar.core.editor var activeRule = prop.actionGroups.LastOrDefault(rule => rule.InitiallyActive); if (activeRule == null || activeRule.Value is not float value) continue; + if (activeRule.ControllingObject == null) continue; // default value is being inherited value = Math.Clamp(value, 0, 100); From 816d2b28cb3733503d5c0da82adba1246a4740a1 Mon Sep 17 00:00:00 2001 From: bd_ Date: Wed, 2 Oct 2024 19:51:17 -0700 Subject: [PATCH 65/85] fix: NRE from scale adjuster preview (#1251) --- Editor/ScaleAdjuster/ScaleAdjusterPreview.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Editor/ScaleAdjuster/ScaleAdjusterPreview.cs b/Editor/ScaleAdjuster/ScaleAdjusterPreview.cs index 542cd5ff..3b34cec1 100644 --- a/Editor/ScaleAdjuster/ScaleAdjusterPreview.cs +++ b/Editor/ScaleAdjuster/ScaleAdjusterPreview.cs @@ -344,7 +344,7 @@ namespace nadena.dev.modular_avatar.core.editor if (proxy == null) return; var curParent = proxy.transform.parent ?? original.transform.parent; - if (_finalBonesMap.TryGetValue(curParent, out var newRoot)) + if (curParent != null && _finalBonesMap.TryGetValue(curParent, out var newRoot)) { // We need to remember this proxy so we can avoid destroying it when we destroy VirtualAvatarRoot // in Dispose From d9c0a21f0dcdcc8dec86249511dd403aa675d906 Mon Sep 17 00:00:00 2001 From: bd_ Date: Wed, 2 Oct 2024 19:52:21 -0700 Subject: [PATCH 66/85] 1.10.1 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index c84e0cd9..1b12db66 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "nadena.dev.modular-avatar", "displayName": "Modular Avatar", - "version": "1.10.0", + "version": "1.10.1", "unity": "2022.3", "description": "A suite of tools for assembling your avatar out of reusable components", "author": { From c379d730ca5d1a02df26605497984fc594df2832 Mon Sep 17 00:00:00 2001 From: bd_ Date: Wed, 2 Oct 2024 20:09:14 -0700 Subject: [PATCH 67/85] chore: fix unit test broken by merge --- .../InitialStates/SCDefaultAnimation.cs | 45 ++++++++++++++++++- 1 file changed, 44 insertions(+), 1 deletion(-) diff --git a/UnitTests~/ShapeChanger/InitialStates/SCDefaultAnimation.cs b/UnitTests~/ShapeChanger/InitialStates/SCDefaultAnimation.cs index 8a3f9ad6..c1061b3e 100644 --- a/UnitTests~/ShapeChanger/InitialStates/SCDefaultAnimation.cs +++ b/UnitTests~/ShapeChanger/InitialStates/SCDefaultAnimation.cs @@ -20,7 +20,50 @@ namespace ShapeChangerTests [Test] public void SetsCorrectInitialStatesAndAnimationsForInactiveSC() { - SetsCorrectInitialStatesAndAnimations("SCDefaultAnimationInactive.prefab"); + var root = CreatePrefab("SCDefaultAnimationInactive.prefab"); + AvatarProcessor.ProcessAvatar(root); + + var fx = (AnimatorController) FindFxController(root).animatorController; + var baseLayer = fx.layers[0]; + + var bt = baseLayer.stateMachine.states[0].state.motion as BlendTree; + Assert.NotNull(bt); + var subBt = bt.children[0].motion as BlendTree; + Assert.NotNull(subBt); + var clip = subBt.children[0].motion as AnimationClip; + Assert.NotNull(clip); + + var smr = root.transform.Find("test mesh").GetComponent(); + var sharedMesh = smr.sharedMesh; + + var bindings = AnimationUtility.GetCurveBindings(clip); + var curve = AnimationUtility.GetEditorCurve(clip, EditorCurveBinding.FloatCurve( + "test mesh", + typeof(SkinnedMeshRenderer), + "blendShape.key1" + )); + Assert.IsNull(curve); // always off MenuItem (due to object disable), no curve should be generated + + curve = AnimationUtility.GetEditorCurve(clip, EditorCurveBinding.FloatCurve( + "test mesh", + typeof(SkinnedMeshRenderer), + "blendShape.key2" + )); + // Always-on delete, no curve should be generated + Assert.IsNull(curve); + + curve = AnimationUtility.GetEditorCurve(clip, EditorCurveBinding.FloatCurve( + "test mesh", + typeof(SkinnedMeshRenderer), + "blendShape.key3" + )); + // Always-on set, no curve should be generated + Assert.IsNull(curve); + + // Check actual blendshape states + Assert.AreEqual(10.0f, smr.GetBlendShapeWeight(sharedMesh.GetBlendShapeIndex("key1")), 0.1f); + Assert.AreEqual(5.0f, smr.GetBlendShapeWeight(sharedMesh.GetBlendShapeIndex("key2")), 0.1f); + Assert.AreEqual(100.0f, smr.GetBlendShapeWeight(sharedMesh.GetBlendShapeIndex("key3")), 0.1f); } [Test] From 30cafb21e40e08431636e3dfaec6fb542f07c094 Mon Sep 17 00:00:00 2001 From: bd_ Date: Thu, 3 Oct 2024 20:16:53 -0700 Subject: [PATCH 68/85] fix: incorrect handling of shape key deletion (#1258) This change reworks delete handling to be more consistent with other properties, by treating it as a virtual property (`deletedShape.{blendshapeName}`) instead of a weird additional field of blendshape keys. This then fixes a number of issues (e.g. broken preview for delete keys). Fixes: #1253 --- .../AnimationGeneration/AnimatedProperty.cs | 1 - .../AnimationGeneration/ReactionRule.cs | 10 +- .../ReactiveObjectAnalyzer.LocateReactions.cs | 75 +- .../ReactiveObjectAnalyzer.cs | 29 +- .../AnimationGeneration/ReactiveObjectPass.cs | 77 +- Editor/ReactiveObjects/ShapeChangerPreview.cs | 54 +- .../ReactiveObjects/Simulator/ROSimulator.cs | 5 +- .../ReactiveComponent/DeletionTest.prefab | 666 ++++++++++++++++++ .../DeletionTest.prefab.meta | 7 + .../ShapeDeletionAnalysis.cs | 98 +++ .../ShapeDeletionAnalysis.cs.meta | 11 + .../shape deletion test mesh.fbx | Bin 0 -> 17116 bytes .../shape deletion test mesh.fbx.meta | 109 +++ 13 files changed, 1040 insertions(+), 102 deletions(-) create mode 100644 UnitTests~/ReactiveComponent/DeletionTest.prefab create mode 100644 UnitTests~/ReactiveComponent/DeletionTest.prefab.meta create mode 100644 UnitTests~/ReactiveComponent/ShapeDeletionAnalysis.cs create mode 100644 UnitTests~/ReactiveComponent/ShapeDeletionAnalysis.cs.meta create mode 100644 UnitTests~/ReactiveComponent/shape deletion test mesh.fbx create mode 100644 UnitTests~/ReactiveComponent/shape deletion test mesh.fbx.meta diff --git a/Editor/ReactiveObjects/AnimationGeneration/AnimatedProperty.cs b/Editor/ReactiveObjects/AnimationGeneration/AnimatedProperty.cs index c3bded7d..f56a59af 100644 --- a/Editor/ReactiveObjects/AnimationGeneration/AnimatedProperty.cs +++ b/Editor/ReactiveObjects/AnimationGeneration/AnimatedProperty.cs @@ -8,7 +8,6 @@ namespace nadena.dev.modular_avatar.core.editor public TargetProp TargetProp { get; } public string ControlParam { get; set; } - public bool alwaysDeleted; public object currentState; // Objects which trigger deletion of this shape key. diff --git a/Editor/ReactiveObjects/AnimationGeneration/ReactionRule.cs b/Editor/ReactiveObjects/AnimationGeneration/ReactionRule.cs index dcf040ea..12bea0cb 100644 --- a/Editor/ReactiveObjects/AnimationGeneration/ReactionRule.cs +++ b/Editor/ReactiveObjects/AnimationGeneration/ReactionRule.cs @@ -1,6 +1,5 @@ using System.Collections.Generic; using System.Linq; -using nadena.dev.modular_avatar.animation; using UnityEngine; namespace nadena.dev.modular_avatar.core.editor @@ -9,8 +8,8 @@ namespace nadena.dev.modular_avatar.core.editor { public ReactionRule(TargetProp key, float value) : this(key, (object)value) { } - - public ReactionRule(TargetProp key, UnityEngine.Object value) + + public ReactionRule(TargetProp key, Object value) : this(key, (object)value) { } private ReactionRule(TargetProp key, object value) @@ -31,15 +30,15 @@ namespace nadena.dev.modular_avatar.core.editor public bool InitiallyActive => ((ControllingConditions.Count == 0) || ControllingConditions.All(c => c.InitiallyActive)) ^ Inverted; - public bool IsDelete; public bool Inverted; public bool IsConstant => ControllingConditions.Count == 0 || ControllingConditions.All(c => c.IsConstant) || ControllingConditions.Any(c => c.IsConstant && !c.InitiallyActive); - public bool IsConstantOn => IsConstant && InitiallyActive; + public bool IsConstantActive => IsConstant && InitiallyActive ^ Inverted; + public override string ToString() { return $"AGK: {TargetProp}={Value}"; @@ -57,7 +56,6 @@ namespace nadena.dev.modular_avatar.core.editor } else return false; if (!ControllingConditions.SequenceEqual(other.ControllingConditions)) return false; - if (IsDelete || other.IsDelete) return false; return true; } diff --git a/Editor/ReactiveObjects/AnimationGeneration/ReactiveObjectAnalyzer.LocateReactions.cs b/Editor/ReactiveObjects/AnimationGeneration/ReactiveObjectAnalyzer.LocateReactions.cs index f84d0b30..f2e500e7 100644 --- a/Editor/ReactiveObjects/AnimationGeneration/ReactiveObjectAnalyzer.LocateReactions.cs +++ b/Editor/ReactiveObjects/AnimationGeneration/ReactiveObjectAnalyzer.LocateReactions.cs @@ -124,50 +124,55 @@ namespace nadena.dev.modular_avatar.core.editor var key = new TargetProp { TargetObject = renderer, - PropertyName = "blendShape." + shape.ShapeName, + PropertyName = BlendshapePrefix + shape.ShapeName }; + var currentValue = renderer.GetBlendShapeWeight(shapeId); var value = shape.ChangeType == ShapeChangeType.Delete ? 100 : shape.Value; - if (!shapeKeys.TryGetValue(key, out var info)) + + RegisterAction(key, renderer, currentValue, value, changer, shape); + + key = new TargetProp { - info = new AnimatedProperty(key, renderer.GetBlendShapeWeight(shapeId)); - shapeKeys[key] = info; + TargetObject = renderer, + PropertyName = DeletedShapePrefix + shape.ShapeName + }; - // Add initial state - var agk = new ReactionRule(key, value); - agk.Value = renderer.GetBlendShapeWeight(shapeId); - info.actionGroups.Add(agk); - } - - var action = ObjectRule(key, changer, value); - action.Inverted = _computeContext.Observe(changer, c => c.Inverted); - var isCurrentlyActive = changer.gameObject.activeInHierarchy; - - if (shape.ChangeType == ShapeChangeType.Delete) - { - action.IsDelete = true; - - if (isCurrentlyActive) info.currentState = 100; - - info.actionGroups.Add(action); // Never merge - - continue; - } - - if (changer.gameObject.activeInHierarchy) info.currentState = action.Value; - - if (info.actionGroups.Count == 0) - { - info.actionGroups.Add(action); - } - else if (!info.actionGroups[^1].TryMerge(action)) - { - info.actionGroups.Add(action); - } + value = shape.ChangeType == ShapeChangeType.Delete ? 1 : 0; + RegisterAction(key, renderer, 0, value, changer, shape); } } return shapeKeys; + + void RegisterAction(TargetProp key, SkinnedMeshRenderer renderer, float currentValue, float value, + ModularAvatarShapeChanger changer, ChangedShape shape) + { + if (!shapeKeys.TryGetValue(key, out var info)) + { + info = new AnimatedProperty(key, currentValue); + shapeKeys[key] = info; + + // Add initial state + var agk = new ReactionRule(key, value); + agk.Value = currentValue; + info.actionGroups.Add(agk); + } + + var action = ObjectRule(key, changer, value); + action.Inverted = _computeContext.Observe(changer, c => c.Inverted); + + if (changer.gameObject.activeInHierarchy) info.currentState = action.Value; + + if (info.actionGroups.Count == 0) + { + info.actionGroups.Add(action); + } + else if (!info.actionGroups[^1].TryMerge(action)) + { + info.actionGroups.Add(action); + } + } } private void FindMaterialSetters(Dictionary objectGroups, GameObject root) diff --git a/Editor/ReactiveObjects/AnimationGeneration/ReactiveObjectAnalyzer.cs b/Editor/ReactiveObjects/AnimationGeneration/ReactiveObjectAnalyzer.cs index 745c5184..1c5b97b2 100644 --- a/Editor/ReactiveObjects/AnimationGeneration/ReactiveObjectAnalyzer.cs +++ b/Editor/ReactiveObjects/AnimationGeneration/ReactiveObjectAnalyzer.cs @@ -18,6 +18,9 @@ namespace nadena.dev.modular_avatar.core.editor private readonly ndmf.BuildContext _context; private readonly AnimationServicesContext _asc; private Dictionary _simulationInitialStates; + + public const string BlendshapePrefix = "blendShape."; + public const string DeletedShapePrefix = "deletedShape."; public ImmutableDictionary ForcePropertyOverrides { get; set; } = ImmutableDictionary.Empty; @@ -58,7 +61,6 @@ namespace nadena.dev.modular_avatar.core.editor { public Dictionary Shapes; public Dictionary InitialStates; - public HashSet DeletedShapes; } private static PropCache _analysisCache; @@ -86,7 +88,6 @@ namespace nadena.dev.modular_avatar.core.editor /// /// The avatar root /// A dictionary of target property to initial state (float or UnityEngine.Object) - /// A hashset of blendshape properties which are always deleted /// public AnalysisResult Analyze( GameObject root @@ -98,7 +99,6 @@ namespace nadena.dev.modular_avatar.core.editor { result.Shapes = new(); result.InitialStates = new(); - result.DeletedShapes = new(); return result; } @@ -109,7 +109,7 @@ namespace nadena.dev.modular_avatar.core.editor ApplyInitialStateOverrides(shapes); AnalyzeConstants(shapes); ResolveToggleInitialStates(shapes); - PreprocessShapes(shapes, out result.InitialStates, out result.DeletedShapes); + PreprocessShapes(shapes, out result.InitialStates); result.Shapes = shapes; return result; @@ -165,7 +165,7 @@ namespace nadena.dev.modular_avatar.core.editor group.actionGroups.RemoveAll(agk => agk.IsConstant && !agk.InitiallyActive); // Remove all action groups up until the last one where we're always on - var lastAlwaysOnGroup = group.actionGroups.FindLastIndex(ag => ag.IsConstantOn); + var lastAlwaysOnGroup = group.actionGroups.FindLastIndex(ag => ag.IsConstantActive); if (lastAlwaysOnGroup > 0) group.actionGroups.RemoveRange(0, lastAlwaysOnGroup - 1); } @@ -264,18 +264,17 @@ namespace nadena.dev.modular_avatar.core.editor } ///

- /// Determine initial state and deleted shapes for all properties + /// Determine initial state for all properties /// /// /// - /// - private void PreprocessShapes(Dictionary shapes, out Dictionary initialStates, out HashSet deletedShapes) + private void PreprocessShapes(Dictionary shapes, + out Dictionary initialStates) { // For each shapekey, determine 1) if we can just set an initial state and skip and 2) if we can delete the // corresponding mesh. If we can't, delete ops are merged into the main list of operations. initialStates = new Dictionary(); - deletedShapes = new HashSet(); foreach (var (key, info) in shapes.ToList()) { @@ -285,18 +284,6 @@ namespace nadena.dev.modular_avatar.core.editor shapes.Remove(key); continue; } - - var deletions = info.actionGroups.Where(agk => agk.IsDelete).ToList(); - if (deletions.Any(d => d.InitiallyActive)) - { - // always deleted - shapes.Remove(key); - deletedShapes.Add(key); - continue; - } - - // Move deleted shapes to the end of the list, so they override all Set actions - info.actionGroups = info.actionGroups.Where(agk => !agk.IsDelete).Concat(deletions).ToList(); var initialState = info.actionGroups.Where(agk => agk.InitiallyActive) .Select(agk => agk.Value) diff --git a/Editor/ReactiveObjects/AnimationGeneration/ReactiveObjectPass.cs b/Editor/ReactiveObjects/AnimationGeneration/ReactiveObjectPass.cs index 69a0ede7..3ff0fe4a 100644 --- a/Editor/ReactiveObjects/AnimationGeneration/ReactiveObjectPass.cs +++ b/Editor/ReactiveObjects/AnimationGeneration/ReactiveObjectPass.cs @@ -2,7 +2,6 @@ using System; using System.Collections.Generic; -using System.Collections.Immutable; using System.Linq; using nadena.dev.modular_avatar.animation; using UnityEditor; @@ -42,10 +41,11 @@ namespace nadena.dev.modular_avatar.core.editor var shapes = analysis.Shapes; var initialStates = analysis.InitialStates; - var deletedShapes = analysis.DeletedShapes; GenerateActiveSelfProxies(shapes); + ProcessMeshDeletion(initialStates, shapes); + ProcessInitialStates(initialStates, shapes); ProcessInitialAnimatorVariables(shapes); @@ -53,8 +53,6 @@ namespace nadena.dev.modular_avatar.core.editor { ProcessShapeKey(groups); } - - ProcessMeshDeletion(deletedShapes); } private void GenerateActiveSelfProxies(Dictionary shapes) @@ -225,30 +223,65 @@ namespace nadena.dev.modular_avatar.core.editor #region Mesh processing - private void ProcessMeshDeletion(HashSet deletedKeys) + private void ProcessMeshDeletion(Dictionary initialStates, + Dictionary shapes) { - ImmutableDictionary> renderers = deletedKeys - .GroupBy( - v => (SkinnedMeshRenderer) v.TargetObject - ).ToImmutableDictionary( - g => (SkinnedMeshRenderer) g.Key, - g => g.ToList() - ); + var renderers = initialStates + .Where(kvp => kvp.Key.PropertyName.StartsWith(ReactiveObjectAnalyzer.DeletedShapePrefix)) + .Where(kvp => kvp.Key.TargetObject is SkinnedMeshRenderer) + .Where(kvp => kvp.Value is float f && f > 0.5f) + // Filter any non-constant keys + .Where(kvp => + { + if (!shapes.ContainsKey(kvp.Key)) + { + // Constant value + return true; + } - foreach (var (renderer, infos) in renderers) + var lastGroup = shapes[kvp.Key].actionGroups.LastOrDefault(); + return lastGroup?.IsConstantActive == true && lastGroup.Value is float f && f > 0.5f; + }) + .GroupBy(kvp => kvp.Key.TargetObject as SkinnedMeshRenderer) + .Select(grouping => (grouping.Key, grouping.Select( + kvp => kvp.Key.PropertyName.Substring(ReactiveObjectAnalyzer.DeletedShapePrefix.Length) + ).ToList())) + .ToList(); + foreach (var (renderer, shapeNamesToDelete) in renderers) { if (renderer == null) continue; var mesh = renderer.sharedMesh; if (mesh == null) continue; - renderer.sharedMesh = RemoveBlendShapeFromMesh.RemoveBlendshapes( - mesh, - infos - .Select(i => mesh.GetBlendShapeIndex(i.PropertyName.Substring("blendShape.".Length))) - .Where(k => k >= 0) - .ToList() - ); + var shapesToDelete = shapeNamesToDelete + .Select(shape => mesh.GetBlendShapeIndex(shape)) + .Where(k => k >= 0) + .ToList(); + + renderer.sharedMesh = RemoveBlendShapeFromMesh.RemoveBlendshapes(mesh, shapesToDelete); + + foreach (var name in shapeNamesToDelete) + { + // Don't need to animate this anymore...! + shapes.Remove(new TargetProp + { + TargetObject = renderer, + PropertyName = ReactiveObjectAnalyzer.BlendshapePrefix + name + }); + + shapes.Remove(new TargetProp + { + TargetObject = renderer, + PropertyName = ReactiveObjectAnalyzer.DeletedShapePrefix + name + }); + + initialStates.Remove(new TargetProp + { + TargetObject = renderer, + PropertyName = ReactiveObjectAnalyzer.BlendshapePrefix + name + }); + } } } @@ -257,10 +290,6 @@ namespace nadena.dev.modular_avatar.core.editor private void ProcessShapeKey(AnimatedProperty info) { // TODO: prune non-animated keys - - // Check if this is non-animated and skip most processing if so - if (info.alwaysDeleted || info.actionGroups[^1].IsConstant) return; - var asm = GenerateStateMachine(info); ApplyController(asm, "MA Responsive: " + info.TargetProp.TargetObject.name); } diff --git a/Editor/ReactiveObjects/ShapeChangerPreview.cs b/Editor/ReactiveObjects/ShapeChangerPreview.cs index 2ca011c7..58c09131 100644 --- a/Editor/ReactiveObjects/ShapeChangerPreview.cs +++ b/Editor/ReactiveObjects/ShapeChangerPreview.cs @@ -72,8 +72,8 @@ namespace nadena.dev.modular_avatar.core.editor var analysis = ReactiveObjectAnalyzer.CachedAnalyze(context, avatarRoot); var shapes = analysis.Shapes; - ImmutableDictionary>.Builder rendererStates = - ImmutableDictionary.CreateBuilder>( + var rendererStates = + ImmutableDictionary.CreateBuilder>( ); var avatarRootTransform = avatarRoot.transform; @@ -83,16 +83,29 @@ namespace nadena.dev.modular_avatar.core.editor var target = prop.TargetProp; if (target.TargetObject == null || target.TargetObject is not SkinnedMeshRenderer r) continue; if (!r.transform.IsChildOf(avatarRootTransform)) continue; - if (!target.PropertyName.StartsWith("blendShape.")) continue; + var isDelete = false; + string shapeName = null; + if (target.PropertyName.StartsWith(ReactiveObjectAnalyzer.DeletedShapePrefix)) + { + isDelete = true; + shapeName = target.PropertyName.Substring(ReactiveObjectAnalyzer.DeletedShapePrefix.Length); + } + else if (target.PropertyName.StartsWith(ReactiveObjectAnalyzer.BlendshapePrefix)) + { + shapeName = target.PropertyName.Substring(ReactiveObjectAnalyzer.BlendshapePrefix.Length); + } + else + { + continue; + } + var mesh = r.sharedMesh; if (mesh == null) continue; - var shapeName = target.PropertyName.Substring("blendShape.".Length); - if (!rendererStates.TryGetValue(r, out var states)) { - states = ImmutableList<(int, float)>.Empty; + states = ImmutableDictionary.Empty; rendererStates[r] = states; } @@ -103,15 +116,30 @@ namespace nadena.dev.modular_avatar.core.editor if (activeRule == null || activeRule.Value is not float value) continue; if (activeRule.ControllingObject == null) continue; // default value is being inherited - value = Math.Clamp(value, 0, 100); - - if (activeRule.IsDelete) value = -1; - - states = states.Add((index, value)); + if (isDelete) + { + if (value < 0.5f) continue; + value = -1; + } + else + { + if (states.ContainsKey(index)) + { + // Delete takes precedence over set in preview + continue; + } + + value = Math.Clamp(value, 0, 100); + } + + states = states.SetItem(index, value); rendererStates[r] = states; } - - return rendererStates.ToImmutableDictionary(); + + return rendererStates.ToImmutableDictionary( + kvp => kvp.Key, + kvp => kvp.Value.Select(shapePair => (shapePair.Key, shapePair.Value) + ).ToImmutableList()); } private IEnumerable ShapesToGroups(GameObject avatarRoot, ImmutableDictionary> shapes) diff --git a/Editor/ReactiveObjects/Simulator/ROSimulator.cs b/Editor/ReactiveObjects/Simulator/ROSimulator.cs index 3aaf3237..84896612 100644 --- a/Editor/ReactiveObjects/Simulator/ROSimulator.cs +++ b/Editor/ReactiveObjects/Simulator/ROSimulator.cs @@ -471,7 +471,7 @@ namespace nadena.dev.modular_avatar.core.editor.Simulator var f_set_inactive = effectGroup.Q("effect__set-inactive"); var f_value = effectGroup.Q("effect__value"); var f_material = effectGroup.Q("effect__material"); - var f_delete = effectGroup.Q("effect__deleted"); + var f_delete = effectGroup.Q("effect__deleted"); f_target_component.style.display = DisplayStyle.None; f_target_component.SetEnabled(false); @@ -504,9 +504,10 @@ namespace nadena.dev.modular_avatar.core.editor.Simulator f_property.value = targetProp.PropertyName; f_property.style.display = DisplayStyle.Flex; - if (reactionRule.IsDelete) + if (reactionRule.TargetProp.PropertyName.StartsWith(ReactiveObjectAnalyzer.DeletedShapePrefix)) { f_delete.style.display = DisplayStyle.Flex; + f_delete.value = reactionRule.Value is > 0.5f ? "DELETE" : "RETAIN"; } else if (reactionRule.Value is float f) { f_value.SetValueWithoutNotify(f); diff --git a/UnitTests~/ReactiveComponent/DeletionTest.prefab b/UnitTests~/ReactiveComponent/DeletionTest.prefab new file mode 100644 index 00000000..6cefc636 --- /dev/null +++ b/UnitTests~/ReactiveComponent/DeletionTest.prefab @@ -0,0 +1,666 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!1 &2464504760772767737 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 3251791125987375227} + - component: {fileID: 6611954401356246169} + - component: {fileID: 4257580493320060063} + - component: {fileID: 7095484051158404692} + m_Layer: 0 + m_Name: DeletionTest + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &3251791125987375227 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2464504760772767737} + serializedVersion: 2 + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0.06867766, y: 0.7869835, z: -0.57959247} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 1 + m_Children: + - {fileID: 8671858138418525756} + - {fileID: 3787319563290092876} + - {fileID: 2780879708549973278} + - {fileID: 6867583134219554799} + - {fileID: 3617623734196600728} + m_Father: {fileID: 0} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!95 &6611954401356246169 +Animator: + serializedVersion: 5 + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2464504760772767737} + m_Enabled: 1 + m_Avatar: {fileID: 0} + m_Controller: {fileID: 0} + m_CullingMode: 0 + m_UpdateMode: 0 + m_ApplyRootMotion: 0 + m_LinearVelocityBlending: 0 + m_StabilizeFeet: 0 + m_WarningMessage: + m_HasTransformHierarchy: 1 + m_AllowConstantClipSamplingOptimization: 1 + m_KeepAnimatorStateOnDisable: 0 + m_WriteDefaultValuesOnDisable: 0 +--- !u!114 &4257580493320060063 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2464504760772767737} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 542108242, guid: 67cc4cb7839cd3741b63733d5adf0442, type: 3} + m_Name: + m_EditorClassIdentifier: + Name: + ViewPosition: {x: 0, y: 1.6, z: 0.2} + Animations: 0 + ScaleIPD: 1 + lipSync: 0 + lipSyncJawBone: {fileID: 0} + lipSyncJawClosed: {x: 0, y: 0, z: 0, w: 1} + lipSyncJawOpen: {x: 0, y: 0, z: 0, w: 1} + VisemeSkinnedMesh: {fileID: 0} + MouthOpenBlendShapeName: Facial_Blends.Jaw_Down + VisemeBlendShapes: [] + unityVersion: + portraitCameraPositionOffset: {x: 0, y: 0, z: 0} + portraitCameraRotationOffset: {x: 0, y: 1, z: 0, w: -0.00000004371139} + networkIDs: [] + customExpressions: 0 + expressionsMenu: {fileID: 0} + expressionParameters: {fileID: 0} + enableEyeLook: 0 + customEyeLookSettings: + eyeMovement: + confidence: 0.5 + excitement: 0.5 + leftEye: {fileID: 0} + rightEye: {fileID: 0} + eyesLookingStraight: + linked: 1 + left: {x: 0, y: 0, z: 0, w: 0} + right: {x: 0, y: 0, z: 0, w: 0} + eyesLookingUp: + linked: 1 + left: {x: 0, y: 0, z: 0, w: 0} + right: {x: 0, y: 0, z: 0, w: 0} + eyesLookingDown: + linked: 1 + left: {x: 0, y: 0, z: 0, w: 0} + right: {x: 0, y: 0, z: 0, w: 0} + eyesLookingLeft: + linked: 1 + left: {x: 0, y: 0, z: 0, w: 0} + right: {x: 0, y: 0, z: 0, w: 0} + eyesLookingRight: + linked: 1 + left: {x: 0, y: 0, z: 0, w: 0} + right: {x: 0, y: 0, z: 0, w: 0} + eyelidType: 0 + upperLeftEyelid: {fileID: 0} + upperRightEyelid: {fileID: 0} + lowerLeftEyelid: {fileID: 0} + lowerRightEyelid: {fileID: 0} + eyelidsDefault: + upper: + linked: 1 + left: {x: 0, y: 0, z: 0, w: 0} + right: {x: 0, y: 0, z: 0, w: 0} + lower: + linked: 1 + left: {x: 0, y: 0, z: 0, w: 0} + right: {x: 0, y: 0, z: 0, w: 0} + eyelidsClosed: + upper: + linked: 1 + left: {x: 0, y: 0, z: 0, w: 0} + right: {x: 0, y: 0, z: 0, w: 0} + lower: + linked: 1 + left: {x: 0, y: 0, z: 0, w: 0} + right: {x: 0, y: 0, z: 0, w: 0} + eyelidsLookingUp: + upper: + linked: 1 + left: {x: 0, y: 0, z: 0, w: 0} + right: {x: 0, y: 0, z: 0, w: 0} + lower: + linked: 1 + left: {x: 0, y: 0, z: 0, w: 0} + right: {x: 0, y: 0, z: 0, w: 0} + eyelidsLookingDown: + upper: + linked: 1 + left: {x: 0, y: 0, z: 0, w: 0} + right: {x: 0, y: 0, z: 0, w: 0} + lower: + linked: 1 + left: {x: 0, y: 0, z: 0, w: 0} + right: {x: 0, y: 0, z: 0, w: 0} + eyelidsSkinnedMesh: {fileID: 0} + eyelidsBlendshapes: + customizeAnimationLayers: 0 + baseAnimationLayers: + - isEnabled: 0 + type: 0 + animatorController: {fileID: 0} + mask: {fileID: 0} + isDefault: 1 + - isEnabled: 0 + type: 4 + animatorController: {fileID: 0} + mask: {fileID: 0} + isDefault: 1 + - isEnabled: 0 + type: 5 + animatorController: {fileID: 0} + mask: {fileID: 0} + isDefault: 1 + specialAnimationLayers: + - isEnabled: 0 + type: 6 + animatorController: {fileID: 0} + mask: {fileID: 0} + isDefault: 1 + - isEnabled: 0 + type: 7 + animatorController: {fileID: 0} + mask: {fileID: 0} + isDefault: 1 + - isEnabled: 0 + type: 8 + animatorController: {fileID: 0} + mask: {fileID: 0} + isDefault: 1 + AnimationPreset: {fileID: 0} + animationHashSet: [] + autoFootsteps: 1 + autoLocomotion: 1 + collider_head: + isMirrored: 1 + state: 0 + transform: {fileID: 0} + radius: 0 + height: 0 + position: {x: 0, y: 0, z: 0} + rotation: {x: 0, y: 0, z: 0, w: 1} + collider_torso: + isMirrored: 1 + state: 0 + transform: {fileID: 0} + radius: 0 + height: 0 + position: {x: 0, y: 0, z: 0} + rotation: {x: 0, y: 0, z: 0, w: 1} + collider_footR: + isMirrored: 1 + state: 0 + transform: {fileID: 0} + radius: 0 + height: 0 + position: {x: 0, y: 0, z: 0} + rotation: {x: 0, y: 0, z: 0, w: 1} + collider_footL: + isMirrored: 1 + state: 0 + transform: {fileID: 0} + radius: 0 + height: 0 + position: {x: 0, y: 0, z: 0} + rotation: {x: 0, y: 0, z: 0, w: 1} + collider_handR: + isMirrored: 1 + state: 0 + transform: {fileID: 0} + radius: 0 + height: 0 + position: {x: 0, y: 0, z: 0} + rotation: {x: 0, y: 0, z: 0, w: 1} + collider_handL: + isMirrored: 1 + state: 0 + transform: {fileID: 0} + radius: 0 + height: 0 + position: {x: 0, y: 0, z: 0} + rotation: {x: 0, y: 0, z: 0, w: 1} + collider_fingerIndexL: + isMirrored: 1 + state: 0 + transform: {fileID: 0} + radius: 0 + height: 0 + position: {x: 0, y: 0, z: 0} + rotation: {x: 0, y: 0, z: 0, w: 1} + collider_fingerMiddleL: + isMirrored: 1 + state: 0 + transform: {fileID: 0} + radius: 0 + height: 0 + position: {x: 0, y: 0, z: 0} + rotation: {x: 0, y: 0, z: 0, w: 1} + collider_fingerRingL: + isMirrored: 1 + state: 0 + transform: {fileID: 0} + radius: 0 + height: 0 + position: {x: 0, y: 0, z: 0} + rotation: {x: 0, y: 0, z: 0, w: 1} + collider_fingerLittleL: + isMirrored: 1 + state: 0 + transform: {fileID: 0} + radius: 0 + height: 0 + position: {x: 0, y: 0, z: 0} + rotation: {x: 0, y: 0, z: 0, w: 1} + collider_fingerIndexR: + isMirrored: 1 + state: 0 + transform: {fileID: 0} + radius: 0 + height: 0 + position: {x: 0, y: 0, z: 0} + rotation: {x: 0, y: 0, z: 0, w: 1} + collider_fingerMiddleR: + isMirrored: 1 + state: 0 + transform: {fileID: 0} + radius: 0 + height: 0 + position: {x: 0, y: 0, z: 0} + rotation: {x: 0, y: 0, z: 0, w: 1} + collider_fingerRingR: + isMirrored: 1 + state: 0 + transform: {fileID: 0} + radius: 0 + height: 0 + position: {x: 0, y: 0, z: 0} + rotation: {x: 0, y: 0, z: 0, w: 1} + collider_fingerLittleR: + isMirrored: 1 + state: 0 + transform: {fileID: 0} + radius: 0 + height: 0 + position: {x: 0, y: 0, z: 0} + rotation: {x: 0, y: 0, z: 0, w: 1} +--- !u!114 &7095484051158404692 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2464504760772767737} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: -1427037861, guid: 4ecd63eff847044b68db9453ce219299, type: 3} + m_Name: + m_EditorClassIdentifier: + launchedFromSDKPipeline: 0 + completedSDKPipeline: 0 + blueprintId: + contentType: 0 + assetBundleUnityVersion: + fallbackStatus: 0 +--- !u!1 &3134446681435896768 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 2780879708549973278} + - component: {fileID: 2470606632396626262} + m_Layer: 0 + m_Name: Delete + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &2780879708549973278 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 3134446681435896768} + serializedVersion: 2 + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 1 + m_Children: [] + m_Father: {fileID: 3251791125987375227} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!114 &2470606632396626262 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 3134446681435896768} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 2db441f589c3407bb6fb5f02ff8ab541, type: 3} + m_Name: + m_EditorClassIdentifier: + m_inverted: 0 + m_shapes: + - Object: + referencePath: shape deletion test mesh + targetObject: {fileID: 0} + ShapeName: bottom + ChangeType: 0 + Value: 50 +--- !u!1 &7874409458034691206 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 3787319563290092876} + - component: {fileID: 8462455628590652122} + m_Layer: 0 + m_Name: PriorSet + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &3787319563290092876 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 7874409458034691206} + serializedVersion: 2 + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 1 + m_Children: [] + m_Father: {fileID: 3251791125987375227} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!114 &8462455628590652122 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 7874409458034691206} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 2db441f589c3407bb6fb5f02ff8ab541, type: 3} + m_Name: + m_EditorClassIdentifier: + m_inverted: 0 + m_shapes: + - Object: + referencePath: shape deletion test mesh + targetObject: {fileID: 0} + ShapeName: bottom + ChangeType: 1 + Value: 50 +--- !u!1 &7956182162252432618 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 3617623734196600728} + - component: {fileID: 4167915178638071617} + - component: {fileID: 3280847981733507148} + m_Layer: 0 + m_Name: MenuSet + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 0 +--- !u!4 &3617623734196600728 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 7956182162252432618} + serializedVersion: 2 + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 1 + m_Children: [] + m_Father: {fileID: 3251791125987375227} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!114 &4167915178638071617 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 7956182162252432618} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 2db441f589c3407bb6fb5f02ff8ab541, type: 3} + m_Name: + m_EditorClassIdentifier: + m_inverted: 0 + m_shapes: + - Object: + referencePath: shape deletion test mesh + targetObject: {fileID: 0} + ShapeName: bottom + ChangeType: 1 + Value: 0 +--- !u!114 &3280847981733507148 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 7956182162252432618} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 3b29d45007c5493d926d2cd45a489529, type: 3} + m_Name: + m_EditorClassIdentifier: + Control: + name: + icon: {fileID: 0} + type: 102 + parameter: + name: + value: 1 + style: 0 + subMenu: {fileID: 0} + subParameters: [] + labels: [] + MenuSource: 1 + menuSource_otherObjectChildren: {fileID: 0} + isSynced: 1 + isSaved: 1 + isDefault: 0 + automaticValue: 1 +--- !u!1 &8389945206789797712 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 6867583134219554799} + - component: {fileID: 8099891503683627458} + m_Layer: 0 + m_Name: NullSet + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 0 +--- !u!4 &6867583134219554799 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 8389945206789797712} + serializedVersion: 2 + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 1 + m_Children: [] + m_Father: {fileID: 3251791125987375227} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!114 &8099891503683627458 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 8389945206789797712} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 2db441f589c3407bb6fb5f02ff8ab541, type: 3} + m_Name: + m_EditorClassIdentifier: + m_inverted: 0 + m_shapes: + - Object: + referencePath: shape deletion test mesh + targetObject: {fileID: 0} + ShapeName: bottom + ChangeType: 1 + Value: 0 +--- !u!1001 &9210451080691405271 +PrefabInstance: + m_ObjectHideFlags: 0 + serializedVersion: 2 + m_Modification: + serializedVersion: 3 + m_TransformParent: {fileID: 3251791125987375227} + m_Modifications: + - target: {fileID: -8679921383154817045, guid: fe5b76dae94c07345b74d51e9a9a8440, + type: 3} + propertyPath: m_LocalPosition.x + value: -0 + objectReference: {fileID: 0} + - target: {fileID: -8679921383154817045, guid: fe5b76dae94c07345b74d51e9a9a8440, + type: 3} + propertyPath: m_LocalPosition.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: -8679921383154817045, guid: fe5b76dae94c07345b74d51e9a9a8440, + type: 3} + propertyPath: m_LocalPosition.z + value: 0 + objectReference: {fileID: 0} + - target: {fileID: -8679921383154817045, guid: fe5b76dae94c07345b74d51e9a9a8440, + type: 3} + propertyPath: m_LocalRotation.w + value: 0.7071067 + objectReference: {fileID: 0} + - target: {fileID: -8679921383154817045, guid: fe5b76dae94c07345b74d51e9a9a8440, + type: 3} + propertyPath: m_LocalRotation.x + value: -0.7071068 + objectReference: {fileID: 0} + - target: {fileID: -8679921383154817045, guid: fe5b76dae94c07345b74d51e9a9a8440, + type: 3} + propertyPath: m_LocalRotation.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: -8679921383154817045, guid: fe5b76dae94c07345b74d51e9a9a8440, + type: 3} + propertyPath: m_LocalRotation.z + value: -0 + objectReference: {fileID: 0} + - target: {fileID: -8679921383154817045, guid: fe5b76dae94c07345b74d51e9a9a8440, + type: 3} + propertyPath: m_LocalEulerAnglesHint.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: -8679921383154817045, guid: fe5b76dae94c07345b74d51e9a9a8440, + type: 3} + propertyPath: m_LocalEulerAnglesHint.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: -8679921383154817045, guid: fe5b76dae94c07345b74d51e9a9a8440, + type: 3} + propertyPath: m_LocalEulerAnglesHint.z + value: 0 + objectReference: {fileID: 0} + - target: {fileID: -3887185075125053422, guid: fe5b76dae94c07345b74d51e9a9a8440, + type: 3} + propertyPath: m_DirtyAABB + value: 0 + objectReference: {fileID: 0} + - target: {fileID: -3887185075125053422, guid: fe5b76dae94c07345b74d51e9a9a8440, + type: 3} + propertyPath: m_AABB.m_Extent.x + value: 1 + objectReference: {fileID: 0} + - target: {fileID: -3887185075125053422, guid: fe5b76dae94c07345b74d51e9a9a8440, + type: 3} + propertyPath: m_AABB.m_Extent.y + value: 1 + objectReference: {fileID: 0} + - target: {fileID: -3887185075125053422, guid: fe5b76dae94c07345b74d51e9a9a8440, + type: 3} + propertyPath: m_AABB.m_Extent.z + value: 2 + objectReference: {fileID: 0} + - target: {fileID: -3887185075125053422, guid: fe5b76dae94c07345b74d51e9a9a8440, + type: 3} + propertyPath: m_BlendShapeWeights.Array.data[0] + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 919132149155446097, guid: fe5b76dae94c07345b74d51e9a9a8440, + type: 3} + propertyPath: m_Name + value: shape deletion test mesh + objectReference: {fileID: 0} + m_RemovedComponents: [] + m_RemovedGameObjects: [] + m_AddedGameObjects: [] + m_AddedComponents: [] + m_SourcePrefab: {fileID: 100100000, guid: fe5b76dae94c07345b74d51e9a9a8440, type: 3} +--- !u!4 &8671858138418525756 stripped +Transform: + m_CorrespondingSourceObject: {fileID: -8679921383154817045, guid: fe5b76dae94c07345b74d51e9a9a8440, + type: 3} + m_PrefabInstance: {fileID: 9210451080691405271} + m_PrefabAsset: {fileID: 0} diff --git a/UnitTests~/ReactiveComponent/DeletionTest.prefab.meta b/UnitTests~/ReactiveComponent/DeletionTest.prefab.meta new file mode 100644 index 00000000..0197de59 --- /dev/null +++ b/UnitTests~/ReactiveComponent/DeletionTest.prefab.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: a82669288fc87d94db320a2494fd76c5 +PrefabImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnitTests~/ReactiveComponent/ShapeDeletionAnalysis.cs b/UnitTests~/ReactiveComponent/ShapeDeletionAnalysis.cs new file mode 100644 index 00000000..7cb78e50 --- /dev/null +++ b/UnitTests~/ReactiveComponent/ShapeDeletionAnalysis.cs @@ -0,0 +1,98 @@ +using System.Collections; +using System.Collections.Generic; +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; + +public class ShapeDeletionAnalysis : TestBase +{ + [Test] + public void BasicShapeDeletionAnalysis() + { + var root = CreatePrefab("DeletionTest.prefab"); + + var mesh = AssertPreviewDeletion(root); + + AssertBuildDeletion(mesh, root); + } + + [Test] + public void WhenShapeDeletionIsConditionedOnSubsequentChanger_DoesNotDelete() + { + var root = CreatePrefab("DeletionTest.prefab"); + root.transform.Find("MenuSet").gameObject.SetActive(true); + + AssertPreviewDeletion(root); + AssertNoMeshDeletion(root); + + var mesh = root.GetComponentInChildren(); + Assert.AreEqual(100, mesh.GetBlendShapeWeight(mesh.sharedMesh.GetBlendShapeIndex("bottom"))); + } + + + [Test] + public void WhenShapeDeletionIsConditionedOnItself_DoesNotDelete() + { + var root = CreatePrefab("DeletionTest.prefab"); + root.transform.Find("Delete").gameObject.AddComponent().InitSettings(); + + AssertNoPreviewDeletion(root); + AssertNoMeshDeletion(root); + + var mesh = root.GetComponentInChildren(); + // deletion action is initially off, so we use the shape changer above it, which is set to 50. + Assert.AreEqual(50f, mesh.GetBlendShapeWeight(mesh.sharedMesh.GetBlendShapeIndex("bottom"))); + } + + private static void AssertBuildDeletion(SkinnedMeshRenderer mesh, GameObject root) + { + var originalSharedMesh = mesh.sharedMesh; + AvatarProcessor.ProcessAvatar(root); + Assert.AreNotEqual(originalSharedMesh, mesh.sharedMesh); + + Assert.IsTrue(mesh.sharedMesh.vertices.All(v => v.z >= 0)); + } + + private static SkinnedMeshRenderer AssertPreviewDeletion(GameObject root) + { + var mesh = root.GetComponentInChildren(); + var analysis = new ReactiveObjectAnalyzer().Analyze(root); + var deletedShape = analysis.Shapes.GetValueOrDefault(new TargetProp() + { + TargetObject = mesh, + PropertyName = "deletedShape.bottom" + }); + Assert.IsNotNull(deletedShape); + var activeGroup = deletedShape.actionGroups.LastOrDefault(ag => ag.InitiallyActive); + Assert.AreEqual(1.0f, activeGroup?.Value); + return mesh; + } + + private static void AssertNoPreviewDeletion(GameObject root) + { + var mesh = root.GetComponentInChildren(); + var analysis = new ReactiveObjectAnalyzer().Analyze(root); + var deletedShape = analysis.Shapes.GetValueOrDefault(new TargetProp() + { + TargetObject = mesh, + PropertyName = "deletedShape.bottom" + }); + if (deletedShape != null) + { + var activeGroup = deletedShape.actionGroups.LastOrDefault(ag => ag.InitiallyActive); + Assert.IsFalse(activeGroup?.Value is float f && f > 0); + } + + } + + private static void AssertNoMeshDeletion(GameObject root) + { + var mesh = root.GetComponentInChildren(); + var originalSharedMesh = mesh.sharedMesh; + AvatarProcessor.ProcessAvatar(root); + Assert.AreEqual(originalSharedMesh, mesh.sharedMesh); + } +} diff --git a/UnitTests~/ReactiveComponent/ShapeDeletionAnalysis.cs.meta b/UnitTests~/ReactiveComponent/ShapeDeletionAnalysis.cs.meta new file mode 100644 index 00000000..024b7f11 --- /dev/null +++ b/UnitTests~/ReactiveComponent/ShapeDeletionAnalysis.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 18eb55e1b66a00243a91142456dfd5f5 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnitTests~/ReactiveComponent/shape deletion test mesh.fbx b/UnitTests~/ReactiveComponent/shape deletion test mesh.fbx new file mode 100644 index 0000000000000000000000000000000000000000..52fa8bb9d39297d235bc9146d397de02a8c87a50 GIT binary patch literal 17116 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 literal 0 HcmV?d00001 diff --git a/UnitTests~/ReactiveComponent/shape deletion test mesh.fbx.meta b/UnitTests~/ReactiveComponent/shape deletion test mesh.fbx.meta new file mode 100644 index 00000000..0f60ec10 --- /dev/null +++ b/UnitTests~/ReactiveComponent/shape deletion test mesh.fbx.meta @@ -0,0 +1,109 @@ +fileFormatVersion: 2 +guid: fe5b76dae94c07345b74d51e9a9a8440 +ModelImporter: + serializedVersion: 22200 + internalIDToNameTable: [] + externalObjects: {} + materials: + materialImportMode: 2 + materialName: 0 + materialSearch: 1 + materialLocation: 1 + animations: + legacyGenerateAnimations: 4 + bakeSimulation: 0 + resampleCurves: 1 + optimizeGameObjects: 0 + removeConstantScaleCurves: 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 + importPhysicalCameras: 1 + importVisibility: 1 + importBlendShapes: 1 + importCameras: 1 + importLights: 1 + nodeNameCollisionStrategy: 1 + fileIdsGeneration: 2 + swapUVChannels: 0 + generateSecondaryUV: 0 + useFileUnits: 1 + keepQuads: 0 + weldVertices: 1 + bakeAxisConversion: 0 + preserveHierarchy: 0 + skinWeightsMode: 0 + maxBonesPerVertex: 4 + minBoneWeight: 0.001 + optimizeBones: 1 + meshOptimizationFlags: -1 + indexFormat: 0 + secondaryUVAngleDistortion: 8 + secondaryUVAreaDistortion: 15.000001 + secondaryUVHardAngle: 88 + secondaryUVMarginMethod: 1 + secondaryUVMinLightmapResolution: 40 + secondaryUVMinObjectScale: 1 + secondaryUVPackMargin: 4 + useFileScale: 1 + strictVertexDataChecks: 0 + 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 + addHumanoidExtraRootOnlyWhenUsingAvatar: 1 + importBlendShapeDeformPercent: 1 + remapMaterialsIfMaterialImportModeIsNone: 0 + additionalBone: 0 + userData: + assetBundleName: + assetBundleVariant: From 4da4ebc9849aba51c16feb6d8069fe23088a7041 Mon Sep 17 00:00:00 2001 From: bd_ Date: Thu, 3 Oct 2024 20:17:33 -0700 Subject: [PATCH 69/85] 1.10.2 --- .github/ProjectRoot/vpm-manifest-2022.json | 2 +- package.json | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/ProjectRoot/vpm-manifest-2022.json b/.github/ProjectRoot/vpm-manifest-2022.json index eaba4f86..60d7c06f 100644 --- a/.github/ProjectRoot/vpm-manifest-2022.json +++ b/.github/ProjectRoot/vpm-manifest-2022.json @@ -19,7 +19,7 @@ "dependencies": {} }, "nadena.dev.ndmf": { - "version": "1.5.0" + "version": "1.5.3" } } } \ No newline at end of file diff --git a/package.json b/package.json index 1b12db66..b6141b32 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "nadena.dev.modular-avatar", "displayName": "Modular Avatar", - "version": "1.10.1", + "version": "1.10.2", "unity": "2022.3", "description": "A suite of tools for assembling your avatar out of reusable components", "author": { @@ -16,6 +16,6 @@ }, "vpmDependencies": { "com.vrchat.avatars": ">=3.7.0", - "nadena.dev.ndmf": ">=1.5.0 <2.0.0-a" + "nadena.dev.ndmf": ">=1.5.3 <2.0.0-a" } } From 394601d4a782d0fb1973decaebe8131f6894d0b7 Mon Sep 17 00:00:00 2001 From: Kisaragi <48310258+KisaragiEffective@users.noreply.github.com> Date: Sun, 6 Oct 2024 07:19:32 +0900 Subject: [PATCH 70/85] =?UTF-8?q?docs:=20=E3=83=89=E3=82=AD=E3=83=A5?= =?UTF-8?q?=E3=83=A1=E3=83=B3=E3=83=88=E3=81=B8=E3=81=AE=E8=AA=98=E5=B0=8E?= =?UTF-8?q?=E3=82=92=E5=BE=AE=E8=AA=BF=E6=95=B4=20(#1265)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 033d49d3..c4b74d03 100644 --- a/README.md +++ b/README.md @@ -33,4 +33,4 @@ For more information, check out the [documentation](https://m-a.nadena.dev). * 部分的なアニメーターを親に統合することで、様々のギミックの実装を簡単にします。 * 他にもいろいろ! -詳しくは[ドキュメンテーションページにご参照ください](https://modular-avatar.nadena.dev/ja/). +詳しくは[ドキュメンテーションページをご覧ください](https://modular-avatar.nadena.dev/ja/). From 656a4016842c3216c2bf807fddd0016b076dc0d5 Mon Sep 17 00:00:00 2001 From: bd_ Date: Sat, 5 Oct 2024 15:19:42 -0700 Subject: [PATCH 71/85] fix: proxy animations are cloned in Merge Animator (#1266) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This fixes issues with しゃがみ置き換え+α among other things. --- Editor/Animation/AnimationDatabase.cs | 16 +- UnitTests~/MergeAnimatorTests/ProxyAnim.meta | 8 + .../New Animator Controller.controller | 72 ++++ .../New Animator Controller.controller.meta | 8 + .../ProxyAnim/ProxyAnimTest.cs | 28 ++ .../ProxyAnim/ProxyAnimTest.cs.meta | 3 + .../ProxyAnim/ProxyAnimTest.prefab | 378 ++++++++++++++++++ .../ProxyAnim/ProxyAnimTest.prefab.meta | 7 + 8 files changed, 519 insertions(+), 1 deletion(-) create mode 100644 UnitTests~/MergeAnimatorTests/ProxyAnim.meta create mode 100644 UnitTests~/MergeAnimatorTests/ProxyAnim/New Animator Controller.controller create mode 100644 UnitTests~/MergeAnimatorTests/ProxyAnim/New Animator Controller.controller.meta create mode 100644 UnitTests~/MergeAnimatorTests/ProxyAnim/ProxyAnimTest.cs create mode 100644 UnitTests~/MergeAnimatorTests/ProxyAnim/ProxyAnimTest.cs.meta create mode 100644 UnitTests~/MergeAnimatorTests/ProxyAnim/ProxyAnimTest.prefab create mode 100644 UnitTests~/MergeAnimatorTests/ProxyAnim/ProxyAnimTest.prefab.meta diff --git a/Editor/Animation/AnimationDatabase.cs b/Editor/Animation/AnimationDatabase.cs index bf788923..dd594092 100644 --- a/Editor/Animation/AnimationDatabase.cs +++ b/Editor/Animation/AnimationDatabase.cs @@ -53,7 +53,21 @@ namespace nadena.dev.modular_avatar.animation set { _originalClip = value; - IsProxyAnimation = value != null && Util.IsProxyAnimation(value); + + var baseClip = ObjectRegistry.GetReference(value)?.Object as AnimationClip; + + IsProxyAnimation = false; + if (value != null && Util.IsProxyAnimation(value)) + { + IsProxyAnimation = true; + } + else if (baseClip != null && Util.IsProxyAnimation(baseClip)) + { + // RenameParametersPass replaces proxy clips outside of the purview of the animation database, + // so trace this using ObjectRegistry and correct the reference. + IsProxyAnimation = true; + _originalClip = baseClip; + } } } diff --git a/UnitTests~/MergeAnimatorTests/ProxyAnim.meta b/UnitTests~/MergeAnimatorTests/ProxyAnim.meta new file mode 100644 index 00000000..659236e2 --- /dev/null +++ b/UnitTests~/MergeAnimatorTests/ProxyAnim.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 130af01284a51c24f99eeb52361a81fb +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnitTests~/MergeAnimatorTests/ProxyAnim/New Animator Controller.controller b/UnitTests~/MergeAnimatorTests/ProxyAnim/New Animator Controller.controller new file mode 100644 index 00000000..9a6333ca --- /dev/null +++ b/UnitTests~/MergeAnimatorTests/ProxyAnim/New Animator Controller.controller @@ -0,0 +1,72 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!1102 &-9046052599989551153 +AnimatorState: + serializedVersion: 6 + m_ObjectHideFlags: 1 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: proxy_tpose + m_Speed: 1 + m_CycleOffset: 0 + m_Transitions: [] + m_StateMachineBehaviours: [] + m_Position: {x: 50, y: 50, z: 0} + m_IKOnFeet: 0 + m_WriteDefaultValues: 1 + m_Mirror: 0 + m_SpeedParameterActive: 0 + m_MirrorParameterActive: 0 + m_CycleOffsetParameterActive: 0 + m_TimeParameterActive: 0 + m_Motion: {fileID: 7400000, guid: 645a7092829eff9478fb3a29f959a6fa, type: 2} + m_Tag: + m_SpeedParameter: + m_MirrorParameter: + m_CycleOffsetParameter: + m_TimeParameter: +--- !u!91 &9100000 +AnimatorController: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: New Animator Controller + serializedVersion: 5 + m_AnimatorParameters: [] + m_AnimatorLayers: + - serializedVersion: 5 + m_Name: proxy + m_StateMachine: {fileID: 1953483892909110087} + m_Mask: {fileID: 0} + m_Motions: [] + m_Behaviours: [] + m_BlendingMode: 0 + m_SyncedLayerIndex: -1 + m_DefaultWeight: 0 + m_IKPass: 0 + m_SyncedLayerAffectsTiming: 0 + m_Controller: {fileID: 9100000} +--- !u!1107 &1953483892909110087 +AnimatorStateMachine: + serializedVersion: 6 + m_ObjectHideFlags: 1 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: proxy + m_ChildStates: + - serializedVersion: 1 + m_State: {fileID: -9046052599989551153} + m_Position: {x: 360, y: 110, z: 0} + m_ChildStateMachines: [] + m_AnyStateTransitions: [] + m_EntryTransitions: [] + m_StateMachineTransitions: {} + m_StateMachineBehaviours: [] + m_AnyStatePosition: {x: 50, y: 20, z: 0} + m_EntryPosition: {x: 50, y: 120, z: 0} + m_ExitPosition: {x: 800, y: 120, z: 0} + m_ParentStateMachinePosition: {x: 800, y: 20, z: 0} + m_DefaultState: {fileID: -9046052599989551153} diff --git a/UnitTests~/MergeAnimatorTests/ProxyAnim/New Animator Controller.controller.meta b/UnitTests~/MergeAnimatorTests/ProxyAnim/New Animator Controller.controller.meta new file mode 100644 index 00000000..b2d87165 --- /dev/null +++ b/UnitTests~/MergeAnimatorTests/ProxyAnim/New Animator Controller.controller.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 60603c8e68ac87447b02be4e3af6a7bd +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 9100000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnitTests~/MergeAnimatorTests/ProxyAnim/ProxyAnimTest.cs b/UnitTests~/MergeAnimatorTests/ProxyAnim/ProxyAnimTest.cs new file mode 100644 index 00000000..b67e30d1 --- /dev/null +++ b/UnitTests~/MergeAnimatorTests/ProxyAnim/ProxyAnimTest.cs @@ -0,0 +1,28 @@ +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.MergeAnimatorTests.ProxyAnim +{ + public class ProxyAnimTest : TestBase + { + [Test] + public void whenProxyAnimIsMerged_itIsNotReplaced() + { + var root = CreatePrefab("ProxyAnimTest.prefab"); + + var originalAnimator = (AnimatorController) root.GetComponentInChildren().animator; + var originalClip = originalAnimator.layers[0].stateMachine.states[0].state.motion as AnimationClip; + + AvatarProcessor.ProcessAvatar(root); + + var resultLayer = findFxLayer(root, "proxy"); + var resultClip = resultLayer.stateMachine.states[0].state.motion as AnimationClip; + + Assert.AreEqual(originalClip, resultClip); + } + } +} \ No newline at end of file diff --git a/UnitTests~/MergeAnimatorTests/ProxyAnim/ProxyAnimTest.cs.meta b/UnitTests~/MergeAnimatorTests/ProxyAnim/ProxyAnimTest.cs.meta new file mode 100644 index 00000000..bc3638bd --- /dev/null +++ b/UnitTests~/MergeAnimatorTests/ProxyAnim/ProxyAnimTest.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 2cfba229fa1e4c718f5cb5dd579d3319 +timeCreated: 1728166108 \ No newline at end of file diff --git a/UnitTests~/MergeAnimatorTests/ProxyAnim/ProxyAnimTest.prefab b/UnitTests~/MergeAnimatorTests/ProxyAnim/ProxyAnimTest.prefab new file mode 100644 index 00000000..dff56d51 --- /dev/null +++ b/UnitTests~/MergeAnimatorTests/ProxyAnim/ProxyAnimTest.prefab @@ -0,0 +1,378 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!1 &603567390109878184 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 2557688482630581002} + - component: {fileID: 2868037606074871127} + - component: {fileID: 1028276594299388724} + - component: {fileID: 223023489903813839} + m_Layer: 0 + m_Name: ProxyAnimTest + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &2557688482630581002 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 603567390109878184} + serializedVersion: 2 + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 1.1618705, y: 1.0265146, z: 1.8807894} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 1 + m_Children: + - {fileID: 2189711873526373063} + m_Father: {fileID: 0} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!95 &2868037606074871127 +Animator: + serializedVersion: 5 + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 603567390109878184} + m_Enabled: 1 + m_Avatar: {fileID: 0} + m_Controller: {fileID: 0} + m_CullingMode: 0 + m_UpdateMode: 0 + m_ApplyRootMotion: 0 + m_LinearVelocityBlending: 0 + m_StabilizeFeet: 0 + m_WarningMessage: + m_HasTransformHierarchy: 1 + m_AllowConstantClipSamplingOptimization: 1 + m_KeepAnimatorStateOnDisable: 0 + m_WriteDefaultValuesOnDisable: 0 +--- !u!114 &1028276594299388724 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 603567390109878184} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 542108242, guid: 67cc4cb7839cd3741b63733d5adf0442, type: 3} + m_Name: + m_EditorClassIdentifier: + Name: + ViewPosition: {x: 0, y: 1.6, z: 0.2} + Animations: 0 + ScaleIPD: 1 + lipSync: 0 + lipSyncJawBone: {fileID: 0} + lipSyncJawClosed: {x: 0, y: 0, z: 0, w: 1} + lipSyncJawOpen: {x: 0, y: 0, z: 0, w: 1} + VisemeSkinnedMesh: {fileID: 0} + MouthOpenBlendShapeName: Facial_Blends.Jaw_Down + VisemeBlendShapes: [] + unityVersion: + portraitCameraPositionOffset: {x: 0, y: 0, z: 0} + portraitCameraRotationOffset: {x: 0, y: 1, z: 0, w: -0.00000004371139} + networkIDs: [] + customExpressions: 0 + expressionsMenu: {fileID: 0} + expressionParameters: {fileID: 0} + enableEyeLook: 0 + customEyeLookSettings: + eyeMovement: + confidence: 0.5 + excitement: 0.5 + leftEye: {fileID: 0} + rightEye: {fileID: 0} + eyesLookingStraight: + linked: 1 + left: {x: 0, y: 0, z: 0, w: 0} + right: {x: 0, y: 0, z: 0, w: 0} + eyesLookingUp: + linked: 1 + left: {x: 0, y: 0, z: 0, w: 0} + right: {x: 0, y: 0, z: 0, w: 0} + eyesLookingDown: + linked: 1 + left: {x: 0, y: 0, z: 0, w: 0} + right: {x: 0, y: 0, z: 0, w: 0} + eyesLookingLeft: + linked: 1 + left: {x: 0, y: 0, z: 0, w: 0} + right: {x: 0, y: 0, z: 0, w: 0} + eyesLookingRight: + linked: 1 + left: {x: 0, y: 0, z: 0, w: 0} + right: {x: 0, y: 0, z: 0, w: 0} + eyelidType: 0 + upperLeftEyelid: {fileID: 0} + upperRightEyelid: {fileID: 0} + lowerLeftEyelid: {fileID: 0} + lowerRightEyelid: {fileID: 0} + eyelidsDefault: + upper: + linked: 1 + left: {x: 0, y: 0, z: 0, w: 0} + right: {x: 0, y: 0, z: 0, w: 0} + lower: + linked: 1 + left: {x: 0, y: 0, z: 0, w: 0} + right: {x: 0, y: 0, z: 0, w: 0} + eyelidsClosed: + upper: + linked: 1 + left: {x: 0, y: 0, z: 0, w: 0} + right: {x: 0, y: 0, z: 0, w: 0} + lower: + linked: 1 + left: {x: 0, y: 0, z: 0, w: 0} + right: {x: 0, y: 0, z: 0, w: 0} + eyelidsLookingUp: + upper: + linked: 1 + left: {x: 0, y: 0, z: 0, w: 0} + right: {x: 0, y: 0, z: 0, w: 0} + lower: + linked: 1 + left: {x: 0, y: 0, z: 0, w: 0} + right: {x: 0, y: 0, z: 0, w: 0} + eyelidsLookingDown: + upper: + linked: 1 + left: {x: 0, y: 0, z: 0, w: 0} + right: {x: 0, y: 0, z: 0, w: 0} + lower: + linked: 1 + left: {x: 0, y: 0, z: 0, w: 0} + right: {x: 0, y: 0, z: 0, w: 0} + eyelidsSkinnedMesh: {fileID: 0} + eyelidsBlendshapes: + customizeAnimationLayers: 0 + baseAnimationLayers: + - isEnabled: 0 + type: 0 + animatorController: {fileID: 0} + mask: {fileID: 0} + isDefault: 1 + - isEnabled: 0 + type: 4 + animatorController: {fileID: 0} + mask: {fileID: 0} + isDefault: 1 + - isEnabled: 0 + type: 5 + animatorController: {fileID: 0} + mask: {fileID: 0} + isDefault: 1 + specialAnimationLayers: + - isEnabled: 0 + type: 6 + animatorController: {fileID: 0} + mask: {fileID: 0} + isDefault: 1 + - isEnabled: 0 + type: 7 + animatorController: {fileID: 0} + mask: {fileID: 0} + isDefault: 1 + - isEnabled: 0 + type: 8 + animatorController: {fileID: 0} + mask: {fileID: 0} + isDefault: 1 + AnimationPreset: {fileID: 0} + animationHashSet: [] + autoFootsteps: 1 + autoLocomotion: 1 + collider_head: + isMirrored: 1 + state: 0 + transform: {fileID: 0} + radius: 0 + height: 0 + position: {x: 0, y: 0, z: 0} + rotation: {x: 0, y: 0, z: 0, w: 1} + collider_torso: + isMirrored: 1 + state: 0 + transform: {fileID: 0} + radius: 0 + height: 0 + position: {x: 0, y: 0, z: 0} + rotation: {x: 0, y: 0, z: 0, w: 1} + collider_footR: + isMirrored: 1 + state: 0 + transform: {fileID: 0} + radius: 0 + height: 0 + position: {x: 0, y: 0, z: 0} + rotation: {x: 0, y: 0, z: 0, w: 1} + collider_footL: + isMirrored: 1 + state: 0 + transform: {fileID: 0} + radius: 0 + height: 0 + position: {x: 0, y: 0, z: 0} + rotation: {x: 0, y: 0, z: 0, w: 1} + collider_handR: + isMirrored: 1 + state: 0 + transform: {fileID: 0} + radius: 0 + height: 0 + position: {x: 0, y: 0, z: 0} + rotation: {x: 0, y: 0, z: 0, w: 1} + collider_handL: + isMirrored: 1 + state: 0 + transform: {fileID: 0} + radius: 0 + height: 0 + position: {x: 0, y: 0, z: 0} + rotation: {x: 0, y: 0, z: 0, w: 1} + collider_fingerIndexL: + isMirrored: 1 + state: 0 + transform: {fileID: 0} + radius: 0 + height: 0 + position: {x: 0, y: 0, z: 0} + rotation: {x: 0, y: 0, z: 0, w: 1} + collider_fingerMiddleL: + isMirrored: 1 + state: 0 + transform: {fileID: 0} + radius: 0 + height: 0 + position: {x: 0, y: 0, z: 0} + rotation: {x: 0, y: 0, z: 0, w: 1} + collider_fingerRingL: + isMirrored: 1 + state: 0 + transform: {fileID: 0} + radius: 0 + height: 0 + position: {x: 0, y: 0, z: 0} + rotation: {x: 0, y: 0, z: 0, w: 1} + collider_fingerLittleL: + isMirrored: 1 + state: 0 + transform: {fileID: 0} + radius: 0 + height: 0 + position: {x: 0, y: 0, z: 0} + rotation: {x: 0, y: 0, z: 0, w: 1} + collider_fingerIndexR: + isMirrored: 1 + state: 0 + transform: {fileID: 0} + radius: 0 + height: 0 + position: {x: 0, y: 0, z: 0} + rotation: {x: 0, y: 0, z: 0, w: 1} + collider_fingerMiddleR: + isMirrored: 1 + state: 0 + transform: {fileID: 0} + radius: 0 + height: 0 + position: {x: 0, y: 0, z: 0} + rotation: {x: 0, y: 0, z: 0, w: 1} + collider_fingerRingR: + isMirrored: 1 + state: 0 + transform: {fileID: 0} + radius: 0 + height: 0 + position: {x: 0, y: 0, z: 0} + rotation: {x: 0, y: 0, z: 0, w: 1} + collider_fingerLittleR: + isMirrored: 1 + state: 0 + transform: {fileID: 0} + radius: 0 + height: 0 + position: {x: 0, y: 0, z: 0} + rotation: {x: 0, y: 0, z: 0, w: 1} +--- !u!114 &223023489903813839 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 603567390109878184} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: -1427037861, guid: 4ecd63eff847044b68db9453ce219299, type: 3} + m_Name: + m_EditorClassIdentifier: + launchedFromSDKPipeline: 0 + completedSDKPipeline: 0 + blueprintId: + contentType: 0 + assetBundleUnityVersion: + fallbackStatus: 0 +--- !u!1 &1425973809379277617 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 2189711873526373063} + - component: {fileID: 3380859768730913427} + m_Layer: 0 + m_Name: GameObject + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &2189711873526373063 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1425973809379277617} + serializedVersion: 2 + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 1 + m_Children: [] + m_Father: {fileID: 2557688482630581002} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!114 &3380859768730913427 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1425973809379277617} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 1bb122659f724ebf85fe095ac02dc339, type: 3} + m_Name: + m_EditorClassIdentifier: + animator: {fileID: 9100000, guid: 60603c8e68ac87447b02be4e3af6a7bd, type: 2} + layerType: 5 + deleteAttachedAnimator: 1 + pathMode: 0 + matchAvatarWriteDefaults: 0 + relativePathRoot: + referencePath: + targetObject: {fileID: 0} + layerPriority: 0 diff --git a/UnitTests~/MergeAnimatorTests/ProxyAnim/ProxyAnimTest.prefab.meta b/UnitTests~/MergeAnimatorTests/ProxyAnim/ProxyAnimTest.prefab.meta new file mode 100644 index 00000000..6ceea0ce --- /dev/null +++ b/UnitTests~/MergeAnimatorTests/ProxyAnim/ProxyAnimTest.prefab.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: a77dd3314cc88714bb6e9f1ad014cfc8 +PrefabImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: From 828e6b4548c4fb0817cc48f36b3ce520a9328901 Mon Sep 17 00:00:00 2001 From: bd_ Date: Sat, 5 Oct 2024 17:46:45 -0700 Subject: [PATCH 72/85] fix: propagate shape changer effects through BlendshapeSync (#1267) Closes: #1259 --- .../AnimationGeneration/AnimatedProperty.cs | 32 +++++- .../AnimationGeneration/ControlCondition.cs | 32 +++++- .../AnimationGeneration/ReactionRule.cs | 32 +++++- .../ReactiveObjectAnalyzer.LocateReactions.cs | 105 +++++++++++++++++- .../ReactiveObjectAnalyzer.cs | 2 + 5 files changed, 193 insertions(+), 10 deletions(-) diff --git a/Editor/ReactiveObjects/AnimationGeneration/AnimatedProperty.cs b/Editor/ReactiveObjects/AnimationGeneration/AnimatedProperty.cs index f56a59af..6a488a5a 100644 --- a/Editor/ReactiveObjects/AnimationGeneration/AnimatedProperty.cs +++ b/Editor/ReactiveObjects/AnimationGeneration/AnimatedProperty.cs @@ -1,12 +1,13 @@ -using System.Collections.Generic; -using UnityEngine; +using System; +using System.Collections.Generic; +using System.Linq; +using Object = UnityEngine.Object; namespace nadena.dev.modular_avatar.core.editor { internal class AnimatedProperty { public TargetProp TargetProp { get; } - public string ControlParam { get; set; } public object currentState; @@ -24,5 +25,30 @@ namespace nadena.dev.modular_avatar.core.editor TargetProp = key; this.currentState = currentState; } + + protected bool Equals(AnimatedProperty other) + { + return Equals(currentState, other.currentState) && actionGroups.SequenceEqual(other.actionGroups) && + TargetProp.Equals(other.TargetProp); + } + + public override bool Equals(object obj) + { + if (obj is null) return false; + if (ReferenceEquals(this, obj)) return true; + if (obj.GetType() != GetType()) return false; + return Equals((AnimatedProperty)obj); + } + + public override int GetHashCode() + { + var actionGroupHash = 0; + foreach (var ag in actionGroups) + { + actionGroupHash = HashCode.Combine(actionGroupHash, ag); + } + + return HashCode.Combine(currentState, actionGroupHash, TargetProp); + } } } \ No newline at end of file diff --git a/Editor/ReactiveObjects/AnimationGeneration/ControlCondition.cs b/Editor/ReactiveObjects/AnimationGeneration/ControlCondition.cs index 33368ea5..f61b33e0 100644 --- a/Editor/ReactiveObjects/AnimationGeneration/ControlCondition.cs +++ b/Editor/ReactiveObjects/AnimationGeneration/ControlCondition.cs @@ -1,11 +1,13 @@ -using UnityEngine; +using System; +using UnityEngine; +using Object = UnityEngine.Object; namespace nadena.dev.modular_avatar.core.editor { internal class ControlCondition { public string Parameter; - public UnityEngine.Object DebugReference; + public Object DebugReference; public string DebugName; public bool IsConstant; @@ -14,5 +16,31 @@ namespace nadena.dev.modular_avatar.core.editor public bool IsConstantActive => InitiallyActive && IsConstant; public GameObject ReferenceObject; + + protected bool Equals(ControlCondition other) + { + return Parameter == other.Parameter + && Equals(DebugReference, other.DebugReference) + && DebugName == other.DebugName + && IsConstant == other.IsConstant + && ParameterValueLo.Equals(other.ParameterValueLo) + && ParameterValueHi.Equals(other.ParameterValueHi) + && InitialValue.Equals(other.InitialValue) + && Equals(ReferenceObject, other.ReferenceObject); + } + + public override bool Equals(object obj) + { + if (obj is null) return false; + if (ReferenceEquals(this, obj)) return true; + if (obj.GetType() != GetType()) return false; + return Equals((ControlCondition)obj); + } + + public override int GetHashCode() + { + return HashCode.Combine(Parameter, DebugReference, DebugName, IsConstant, ParameterValueLo, + ParameterValueHi, InitialValue, ReferenceObject); + } } } \ No newline at end of file diff --git a/Editor/ReactiveObjects/AnimationGeneration/ReactionRule.cs b/Editor/ReactiveObjects/AnimationGeneration/ReactionRule.cs index 12bea0cb..497046ab 100644 --- a/Editor/ReactiveObjects/AnimationGeneration/ReactionRule.cs +++ b/Editor/ReactiveObjects/AnimationGeneration/ReactionRule.cs @@ -1,6 +1,8 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; using System.Linq; using UnityEngine; +using Object = UnityEngine.Object; namespace nadena.dev.modular_avatar.core.editor { @@ -59,5 +61,33 @@ namespace nadena.dev.modular_avatar.core.editor return true; } + + protected bool Equals(ReactionRule other) + { + return TargetProp.Equals(other.TargetProp) + && Equals(Value, other.Value) + && Equals(ControllingObject, other.ControllingObject) + && ControllingConditions.SequenceEqual(other.ControllingConditions) + && Inverted == other.Inverted; + } + + public override bool Equals(object obj) + { + if (obj is null) return false; + if (ReferenceEquals(this, obj)) return true; + if (obj.GetType() != GetType()) return false; + return Equals((ReactionRule)obj); + } + + public override int GetHashCode() + { + var ccHash = 0; + foreach (var cc in ControllingConditions) + { + ccHash = HashCode.Combine(ccHash, cc); + } + + return HashCode.Combine(TargetProp, Value, ControllingObject, ccHash, Inverted); + } } } \ No newline at end of file diff --git a/Editor/ReactiveObjects/AnimationGeneration/ReactiveObjectAnalyzer.LocateReactions.cs b/Editor/ReactiveObjects/AnimationGeneration/ReactiveObjectAnalyzer.LocateReactions.cs index f2e500e7..179e4ce4 100644 --- a/Editor/ReactiveObjects/AnimationGeneration/ReactiveObjectAnalyzer.LocateReactions.cs +++ b/Editor/ReactiveObjects/AnimationGeneration/ReactiveObjectAnalyzer.LocateReactions.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using System.Collections.Immutable; using System.Linq; using nadena.dev.ndmf.preview; using UnityEngine; @@ -38,6 +39,77 @@ namespace nadena.dev.modular_avatar.core.editor return param; } } + + private readonly Dictionary<(SkinnedMeshRenderer, string), HashSet<(SkinnedMeshRenderer, string)>> + _blendshapeSyncMappings = new(); + + private void LocateBlendshapeSyncs(GameObject root) + { + var components = _computeContext.GetComponentsInChildren(root, true); + + foreach (var bss in components) + { + var localMesh = _computeContext.GetComponent(bss.gameObject); + if (localMesh == null) continue; + + foreach (var entry in _computeContext.Observe(bss, bss_ => bss_.Bindings.ToImmutableList(), + Enumerable.SequenceEqual)) + { + var src = entry.ReferenceMesh.Get(bss); + if (src == null) continue; + + var srcMesh = _computeContext.GetComponent(src); + + var localBlendshape = entry.LocalBlendshape; + if (string.IsNullOrWhiteSpace(localBlendshape)) + { + localBlendshape = entry.Blendshape; + } + + var srcBinding = (srcMesh, entry.Blendshape); + var dstBinding = (localMesh, localBlendshape); + + if (!_blendshapeSyncMappings.TryGetValue(srcBinding, out var dstSet)) + { + dstSet = new HashSet<(SkinnedMeshRenderer, string)>(); + _blendshapeSyncMappings[srcBinding] = dstSet; + } + + dstSet.Add(dstBinding); + } + } + + // For recursive blendshape syncs, we need to precompute the full set of affected blendshapes. + foreach (var (src, dsts) in _blendshapeSyncMappings) + { + var visited = new HashSet<(SkinnedMeshRenderer, string)>(); + foreach (var item in Visit(src, visited).ToList()) + { + dsts.Add(item); + } + } + + IEnumerable<(SkinnedMeshRenderer, string)> Visit( + (SkinnedMeshRenderer, string) key, + HashSet<(SkinnedMeshRenderer, string)> visited + ) + { + if (!visited.Add(key)) yield break; + + if (_blendshapeSyncMappings.TryGetValue(key, out var children)) + { + foreach (var child in children) + { + foreach (var item in Visit(child, visited)) + { + yield return item; + } + } + } + + yield return key; + } + } private void BuildConditions(Component controllingComponent, ReactionRule rule) { @@ -130,8 +202,34 @@ namespace nadena.dev.modular_avatar.core.editor var currentValue = renderer.GetBlendShapeWeight(shapeId); var value = shape.ChangeType == ShapeChangeType.Delete ? 100 : shape.Value; - RegisterAction(key, renderer, currentValue, value, changer, shape); + RegisterAction(key, currentValue, value, changer); + if (_blendshapeSyncMappings.TryGetValue((renderer, shape.ShapeName), out var bindings)) + { + // Propagate the new value through any Blendshape Syncs we might have. + // Note that we don't propagate deletes; it's common to e.g. want to delete breasts from the + // base model while retaining outerwear that matches the breast size. + foreach (var binding in bindings) + { + var bindingKey = new TargetProp + { + TargetObject = binding.Item1, + PropertyName = BlendshapePrefix + binding.Item2 + }; + var bindingRenderer = binding.Item1; + + var bindingMesh = bindingRenderer.sharedMesh; + if (bindingMesh == null) continue; + + var bindingShapeIndex = bindingMesh.GetBlendShapeIndex(binding.Item2); + if (bindingShapeIndex < 0) continue; + + var bindingInitialState = bindingRenderer.GetBlendShapeWeight(bindingShapeIndex); + + RegisterAction(bindingKey, bindingInitialState, value, changer); + } + } + key = new TargetProp { TargetObject = renderer, @@ -139,14 +237,13 @@ namespace nadena.dev.modular_avatar.core.editor }; value = shape.ChangeType == ShapeChangeType.Delete ? 1 : 0; - RegisterAction(key, renderer, 0, value, changer, shape); + RegisterAction(key, 0, value, changer); } } return shapeKeys; - void RegisterAction(TargetProp key, SkinnedMeshRenderer renderer, float currentValue, float value, - ModularAvatarShapeChanger changer, ChangedShape shape) + void RegisterAction(TargetProp key, float currentValue, float value, ModularAvatarShapeChanger changer) { if (!shapeKeys.TryGetValue(key, out var info)) { diff --git a/Editor/ReactiveObjects/AnimationGeneration/ReactiveObjectAnalyzer.cs b/Editor/ReactiveObjects/AnimationGeneration/ReactiveObjectAnalyzer.cs index 1c5b97b2..643c4a4e 100644 --- a/Editor/ReactiveObjects/AnimationGeneration/ReactiveObjectAnalyzer.cs +++ b/Editor/ReactiveObjects/AnimationGeneration/ReactiveObjectAnalyzer.cs @@ -101,6 +101,8 @@ namespace nadena.dev.modular_avatar.core.editor result.InitialStates = new(); return result; } + + LocateBlendshapeSyncs(root); Dictionary shapes = FindShapes(root); FindObjectToggles(shapes, root); From 1024f626e84b07eeb2a64d663826b541994b4cb1 Mon Sep 17 00:00:00 2001 From: bd_ Date: Sat, 5 Oct 2024 17:55:29 -0700 Subject: [PATCH 73/85] 1.10.3 --- package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index b6141b32..778562f3 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "nadena.dev.modular-avatar", "displayName": "Modular Avatar", - "version": "1.10.2", + "version": "1.10.3", "unity": "2022.3", "description": "A suite of tools for assembling your avatar out of reusable components", "author": { @@ -16,6 +16,6 @@ }, "vpmDependencies": { "com.vrchat.avatars": ">=3.7.0", - "nadena.dev.ndmf": ">=1.5.3 <2.0.0-a" + "nadena.dev.ndmf": ">=1.5.4 <2.0.0-a" } } From 4a376f8723689f514e646bba43aa513e8f76dd57 Mon Sep 17 00:00:00 2001 From: Sayamame-beans <61457993+Sayamame-beans@users.noreply.github.com> Date: Sun, 13 Oct 2024 08:34:30 +0900 Subject: [PATCH 74/85] =?UTF-8?q?Merge=20Armature=E3=81=AE"Reset=20positio?= =?UTF-8?q?n=20to=20base=20avatar"=E3=81=ABA/T=E3=83=9D=E3=83=BC=E3=82=BA?= =?UTF-8?q?=E5=A4=89=E6=8F=9B=E3=82=AA=E3=83=97=E3=82=B7=E3=83=A7=E3=83=B3?= =?UTF-8?q?=E3=82=92=E8=BF=BD=E5=8A=A0=20(#1188)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat: A/T Pose conversion on "Reset position to base avatar" * chore: reorder posReset options * chore: unify FixAPose functions into SetupOutfit.FixAPose --- Editor/Inspector/MergeArmatureEditor.cs | 17 +++++++++++++---- Editor/Localization/en-US.json | 1 + Editor/Localization/ja-JP.json | 1 + Editor/SetupOutfit.cs | 23 ++++++++++++++--------- 4 files changed, 29 insertions(+), 13 deletions(-) diff --git a/Editor/Inspector/MergeArmatureEditor.cs b/Editor/Inspector/MergeArmatureEditor.cs index 3785a608..0fd215b4 100644 --- a/Editor/Inspector/MergeArmatureEditor.cs +++ b/Editor/Inspector/MergeArmatureEditor.cs @@ -84,6 +84,7 @@ namespace nadena.dev.modular_avatar.core.editor } private bool posResetOptionFoldout = false; + private bool posReset_convertATPose = true; private bool posReset_adjustRotation = false; private bool posReset_adjustScale = false; private bool posReset_heuristicRootScale = true; @@ -134,14 +135,17 @@ namespace nadena.dev.modular_avatar.core.editor MessageType.Info ); + posReset_heuristicRootScale = EditorGUILayout.ToggleLeft( + G("merge_armature.reset_pos.heuristic_scale"), + posReset_heuristicRootScale); + posReset_convertATPose = EditorGUILayout.ToggleLeft( + G("merge_armature.reset_pos.convert_atpose"), + posReset_convertATPose); posReset_adjustRotation = EditorGUILayout.ToggleLeft( G("merge_armature.reset_pos.adjust_rotation"), posReset_adjustRotation); posReset_adjustScale = EditorGUILayout.ToggleLeft(G("merge_armature.reset_pos.adjust_scale"), posReset_adjustScale); - posReset_heuristicRootScale = EditorGUILayout.ToggleLeft( - G("merge_armature.reset_pos.heuristic_scale"), - posReset_heuristicRootScale); if (GUILayout.Button(G("merge_armature.reset_pos.execute"))) { @@ -188,6 +192,11 @@ namespace nadena.dev.modular_avatar.core.editor } } + if (posReset_convertATPose) + { + SetupOutfit.FixAPose(RuntimeUtil.FindAvatarTransformInParents(mergeTarget.transform).gameObject, mama.transform, false); + } + if (posReset_heuristicRootScale && !suppressRootScale) { AdjustRootScale(); @@ -279,4 +288,4 @@ namespace nadena.dev.modular_avatar.core.editor } } } -} \ No newline at end of file +} diff --git a/Editor/Localization/en-US.json b/Editor/Localization/en-US.json index bc7e8ec8..8d84f379 100644 --- a/Editor/Localization/en-US.json +++ b/Editor/Localization/en-US.json @@ -86,6 +86,7 @@ "merge_armature.lockmode.bidirectional.body": "The base armature and the merged armature will always have the same position. This is useful when creating animations that are meant to target the base armature. In order to activate this, your armatures must already be in the exact same position.", "merge_armature.reset_pos": "Reset position to base avatar", "merge_armature.reset_pos.info": "This command will force the position of all bones in the outfit to match that of the base avatar. This can be helpful as a starting point for installing outfits not set up for your current avatar.", + "merge_armature.reset_pos.convert_atpose": "Convert A-Pose/T-Pose to match base avatar", "merge_armature.reset_pos.adjust_rotation": "Also set rotation to base avatar", "merge_armature.reset_pos.adjust_scale": "Also set local scale to base avatar", "merge_armature.reset_pos.execute": "Do it!", diff --git a/Editor/Localization/ja-JP.json b/Editor/Localization/ja-JP.json index 94c6022a..95c10a1b 100644 --- a/Editor/Localization/ja-JP.json +++ b/Editor/Localization/ja-JP.json @@ -82,6 +82,7 @@ "merge_armature.lockmode.bidirectional.body": "アバターと統合されるアーマチュアは常に同じ位置になります。元のアバターを操作するアニメーションを作る時に便利かもしれません。有効にするためには、統合されるアーマチュアの位置を統合先と同じにしておく必要があります。", "merge_armature.reset_pos": "位置を元アバターに合わせてリセット", "merge_armature.reset_pos.info": "衣装のボーンの位置をアバターのボーンの位置に合わせます。非対応衣装を導入する際、アバウトに位置を合わせるのに便利です。", + "merge_armature.reset_pos.convert_atpose": "Aポーズ/Tポーズを合わせる", "merge_armature.reset_pos.adjust_rotation": "回転も合わせる", "merge_armature.reset_pos.adjust_scale": "スケールも合わせる", "merge_armature.reset_pos.execute": "実行", diff --git a/Editor/SetupOutfit.cs b/Editor/SetupOutfit.cs index 922fbc74..ba69ed9f 100644 --- a/Editor/SetupOutfit.cs +++ b/Editor/SetupOutfit.cs @@ -229,7 +229,7 @@ namespace nadena.dev.modular_avatar.core.editor } } - private static void FixAPose(GameObject avatarRoot, Transform outfitArmature) + internal static void FixAPose(GameObject avatarRoot, Transform outfitArmature, bool strictMode = true) { var mergeArmature = outfitArmature.GetComponent(); if (mergeArmature == null) return; @@ -249,7 +249,7 @@ namespace nadena.dev.modular_avatar.core.editor { var lowerArm = (HumanBodyBones)((int)arm + 2); - // check if the rotation of the arm differs, but distances and origin point are the same + // check if the rotation of the arm differs(, but distances and origin point are the same when strictMode) var avatarArm = rootAnimator.GetBoneTransform(arm); var outfitArm = avatarToOutfit(avatarArm); @@ -259,22 +259,27 @@ namespace nadena.dev.modular_avatar.core.editor if (outfitArm == null) return; if (outfitLowerArm == null) return; - if ((avatarArm.position - outfitArm.position).magnitude > 0.001f) return; + if (strictMode) + { + if ((avatarArm.position - outfitArm.position).magnitude > 0.001f) return; - // check relative distance to lower arm as well - var avatarArmLength = (avatarLowerArm.position - avatarArm.position).magnitude; - var outfitArmLength = (outfitLowerArm.position - outfitArm.position).magnitude; + // check relative distance to lower arm as well + var avatarArmLength = (avatarLowerArm.position - avatarArm.position).magnitude; + var outfitArmLength = (outfitLowerArm.position - outfitArm.position).magnitude; - if (Mathf.Abs(avatarArmLength - outfitArmLength) > 0.001f) return; + if (Mathf.Abs(avatarArmLength - outfitArmLength) > 0.001f) return; + } else { + if (Vector3.Dot((outfitLowerArm.position - outfitArm.position).normalized, (avatarLowerArm.position - avatarArm.position).normalized) > 0.999f) return; + } - // Rotate the outfit arm to ensure these two points match. + // Rotate the outfit arm to ensure these two bone orientations match. + Undo.RecordObject(outfitArm, "Convert A/T Pose"); var relRot = Quaternion.FromToRotation( outfitLowerArm.position - outfitArm.position, avatarLowerArm.position - avatarArm.position ); outfitArm.rotation = relRot * outfitArm.rotation; PrefabUtility.RecordPrefabInstancePropertyModifications(outfitArm); - EditorUtility.SetDirty(outfitArm); } Transform avatarToOutfit(Transform avBone) From 7f9e65bcbcbb7833d337580dab7f362b9315c429 Mon Sep 17 00:00:00 2001 From: Mooncake Sugar <60507815+Tsukina-7mochi@users.noreply.github.com> Date: Sun, 13 Oct 2024 08:35:54 +0900 Subject: [PATCH 75/85] docs: delete button group on top page (#1270) --- docs~/src/pages/index.module.css | 3 ++- docs~/src/pages/index.tsx | 4 ++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/docs~/src/pages/index.module.css b/docs~/src/pages/index.module.css index a8166690..9ef0a6aa 100644 --- a/docs~/src/pages/index.module.css +++ b/docs~/src/pages/index.module.css @@ -23,6 +23,7 @@ justify-content: center; column-gap: 2rem; row-gap: 1rem; + margin-bottom: 1em; } @media screen and (max-width: 996px) { @@ -36,4 +37,4 @@ div.logo { text-align: center; display: flex; justify-content: center; -} \ No newline at end of file +} diff --git a/docs~/src/pages/index.tsx b/docs~/src/pages/index.tsx index 88796298..889f8ced 100644 --- a/docs~/src/pages/index.tsx +++ b/docs~/src/pages/index.tsx @@ -29,7 +29,7 @@ function HomepageHeader() {

Drag-and-Drop Avatar Assembly

-
+
Tutorials
-
+
Discord Date: Sun, 13 Oct 2024 08:52:37 +0900 Subject: [PATCH 76/85] feat: add support for drag-and-drop on MaterialSetter and ShapeChanger (#1271) * feat: add support for drag-and-drop on MaterialSetter and ShapeChanger * fix: allow adding known objects to MaterialSetter and ShapeChanger --- Editor/Inspector/DragAndDropManipulator.cs | 106 ++++++++++++++++++ .../Inspector/DragAndDropManipulator.cs.meta | 11 ++ .../MaterialSetter/MaterialSetterEditor.cs | 38 +++++++ .../MaterialSetter/MaterialSetterStyles.uss | 10 ++ .../ObjectToggle/ObjectSwitcherEditor.cs | 94 +++------------- .../ObjectToggle/ObjectSwitcherStyles.uss | 10 +- .../ShapeChanger/ShapeChangerEditor.cs | 38 +++++++ .../ShapeChanger/ShapeChangerStyles.uss | 10 ++ 8 files changed, 234 insertions(+), 83 deletions(-) create mode 100644 Editor/Inspector/DragAndDropManipulator.cs create mode 100644 Editor/Inspector/DragAndDropManipulator.cs.meta diff --git a/Editor/Inspector/DragAndDropManipulator.cs b/Editor/Inspector/DragAndDropManipulator.cs new file mode 100644 index 00000000..0d3de862 --- /dev/null +++ b/Editor/Inspector/DragAndDropManipulator.cs @@ -0,0 +1,106 @@ +using System; +using System.Linq; +using UnityEditor; +using UnityEngine; +using UnityEngine.UIElements; + +namespace nadena.dev.modular_avatar.core.editor +{ + internal abstract class DragAndDropManipulator : PointerManipulator where T : Component, IHaveObjReferences + { + private const string DragActiveClassName = "drop-area--drag-active"; + + public T TargetComponent { get; set; } + + protected virtual bool AllowKnownObjects => true; + + private Transform _avatarRoot; + private GameObject[] _draggingObjects = Array.Empty(); + + public DragAndDropManipulator(VisualElement targetElement, T targetComponent) + { + target = targetElement; + TargetComponent = targetComponent; + } + + protected sealed override void RegisterCallbacksOnTarget() + { + target.RegisterCallback(OnDragEnter); + target.RegisterCallback(OnDragLeave); + target.RegisterCallback(OnDragExited); + target.RegisterCallback(OnDragUpdated); + target.RegisterCallback(OnDragPerform); + } + + protected sealed override void UnregisterCallbacksFromTarget() + { + target.UnregisterCallback(OnDragEnter); + target.UnregisterCallback(OnDragLeave); + target.UnregisterCallback(OnDragExited); + target.UnregisterCallback(OnDragUpdated); + target.UnregisterCallback(OnDragPerform); + } + + private void OnDragEnter(DragEnterEvent _) + { + if (TargetComponent == null) return; + + _avatarRoot = RuntimeUtil.FindAvatarTransformInParents(TargetComponent.transform); + if (_avatarRoot == null) return; + + var knownObjects = TargetComponent.GetObjectReferences().Select(x => x.Get(TargetComponent)).ToHashSet(); + _draggingObjects = DragAndDrop.objectReferences.OfType() + .Where(x => AllowKnownObjects || !knownObjects.Contains(x)) + .Where(x => RuntimeUtil.FindAvatarTransformInParents(x.transform) == _avatarRoot) + .Where(FilterGameObject) + .ToArray(); + if (_draggingObjects.Length == 0) return; + + target.AddToClassList(DragActiveClassName); + } + + private void OnDragLeave(DragLeaveEvent _) + { + _draggingObjects = Array.Empty(); + target.RemoveFromClassList(DragActiveClassName); + } + + private void OnDragExited(DragExitedEvent _) + { + _draggingObjects = Array.Empty(); + target.RemoveFromClassList(DragActiveClassName); + } + + private void OnDragUpdated(DragUpdatedEvent _) + { + if (TargetComponent == null) return; + if (_avatarRoot == null) return; + if (_draggingObjects.Length == 0) return; + + DragAndDrop.visualMode = DragAndDropVisualMode.Generic; + } + + private void OnDragPerform(DragPerformEvent _) + { + if (TargetComponent == null) return; + if (_avatarRoot == null) return; + if (_draggingObjects.Length == 0) return; + + AddObjectReferences(_draggingObjects + .Select(x => + { + var reference = new AvatarObjectReference(); + reference.Set(x); + return reference; + }) + .ToArray()); + } + + protected virtual bool FilterGameObject(GameObject obj) + { + return true; + } + + protected abstract void AddObjectReferences(AvatarObjectReference[] references); + } +} diff --git a/Editor/Inspector/DragAndDropManipulator.cs.meta b/Editor/Inspector/DragAndDropManipulator.cs.meta new file mode 100644 index 00000000..b78bdf93 --- /dev/null +++ b/Editor/Inspector/DragAndDropManipulator.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 528c660b56905844ea2f88bc73837e9f +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Inspector/MaterialSetter/MaterialSetterEditor.cs b/Editor/Inspector/MaterialSetter/MaterialSetterEditor.cs index c7410eb8..a2b055b3 100644 --- a/Editor/Inspector/MaterialSetter/MaterialSetterEditor.cs +++ b/Editor/Inspector/MaterialSetter/MaterialSetterEditor.cs @@ -16,6 +16,7 @@ namespace nadena.dev.modular_avatar.core.editor.ShapeChanger [SerializeField] private StyleSheet uss; [SerializeField] private VisualTreeAsset uxml; + private DragAndDropManipulator _dragAndDropManipulator; protected override void OnInnerInspectorGUI() { @@ -37,7 +38,44 @@ namespace nadena.dev.modular_avatar.core.editor.ShapeChanger listView.showBoundCollectionSize = false; listView.virtualizationMethod = CollectionVirtualizationMethod.DynamicHeight; + _dragAndDropManipulator = new DragAndDropManipulator(root.Q("group-box"), target as ModularAvatarMaterialSetter); + return root; } + + private void OnEnable() + { + if (_dragAndDropManipulator != null) + _dragAndDropManipulator.TargetComponent = target as ModularAvatarMaterialSetter; + } + + private class DragAndDropManipulator : DragAndDropManipulator + { + public DragAndDropManipulator(VisualElement targetElement, ModularAvatarMaterialSetter targetComponent) + : base(targetElement, targetComponent) { } + + protected override bool FilterGameObject(GameObject obj) + { + if (obj.TryGetComponent(out var renderer)) + { + return renderer.sharedMaterials.Length > 0; + } + return false; + } + + protected override void AddObjectReferences(AvatarObjectReference[] references) + { + Undo.RecordObject(TargetComponent, "Add Material Switch Objects"); + + foreach (var reference in references) + { + var materialSwitchObject = new MaterialSwitchObject { Object = reference, MaterialIndex = 0 }; + TargetComponent.Objects.Add(materialSwitchObject); + } + + EditorUtility.SetDirty(TargetComponent); + PrefabUtility.RecordPrefabInstancePropertyModifications(TargetComponent); + } + } } } \ No newline at end of file diff --git a/Editor/Inspector/MaterialSetter/MaterialSetterStyles.uss b/Editor/Inspector/MaterialSetter/MaterialSetterStyles.uss index 84204231..8e422d2d 100644 --- a/Editor/Inspector/MaterialSetter/MaterialSetterStyles.uss +++ b/Editor/Inspector/MaterialSetter/MaterialSetterStyles.uss @@ -62,3 +62,13 @@ #f-material { flex-grow: 1; } + +.drop-area--drag-active { + background-color: rgba(0, 127, 255, 0.2); +} + +.drop-area--drag-active .unity-scroll-view, +.drop-area--drag-active .unity-list-view__footer, +.drop-area--drag-active .unity-list-view__reorderable-item { + background-color: rgba(0, 0, 0, 0.0); +} diff --git a/Editor/Inspector/ObjectToggle/ObjectSwitcherEditor.cs b/Editor/Inspector/ObjectToggle/ObjectSwitcherEditor.cs index 627121b7..999f596c 100644 --- a/Editor/Inspector/ObjectToggle/ObjectSwitcherEditor.cs +++ b/Editor/Inspector/ObjectToggle/ObjectSwitcherEditor.cs @@ -35,14 +35,12 @@ namespace nadena.dev.modular_avatar.core.editor.ShapeChanger ROSimulatorButton.BindRefObject(root, target); var listView = root.Q("Shapes"); - _dragAndDropManipulator = new DragAndDropManipulator(listView) - { - TargetComponent = target as ModularAvatarObjectToggle - }; listView.showBoundCollectionSize = false; listView.virtualizationMethod = CollectionVirtualizationMethod.DynamicHeight; + _dragAndDropManipulator = new DragAndDropManipulator(root.Q("group-box"), target as ModularAvatarObjectToggle); + return root; } @@ -52,91 +50,25 @@ namespace nadena.dev.modular_avatar.core.editor.ShapeChanger _dragAndDropManipulator.TargetComponent = target as ModularAvatarObjectToggle; } - private class DragAndDropManipulator : PointerManipulator + private class DragAndDropManipulator : DragAndDropManipulator { - public ModularAvatarObjectToggle TargetComponent; - private GameObject[] _nowDragging = Array.Empty(); - private Transform _avatarRoot; + public DragAndDropManipulator(VisualElement targetElement, ModularAvatarObjectToggle targetComponent) + : base(targetElement, targetComponent) { } - private readonly VisualElement _parentElem; + protected override bool AllowKnownObjects => false; - public DragAndDropManipulator(VisualElement target) + protected override void AddObjectReferences(AvatarObjectReference[] references) { - this.target = target; - _parentElem = target.parent; - } + Undo.RecordObject(TargetComponent, "Add Toggled Objects"); - protected override void RegisterCallbacksOnTarget() - { - target.RegisterCallback(OnDragEnter); - target.RegisterCallback(OnDragLeave); - target.RegisterCallback(OnDragPerform); - target.RegisterCallback(OnDragUpdate); - } - - protected override void UnregisterCallbacksFromTarget() - { - target.UnregisterCallback(OnDragEnter); - target.UnregisterCallback(OnDragLeave); - target.UnregisterCallback(OnDragPerform); - target.RegisterCallback(OnDragUpdate); - } - - - private void OnDragEnter(DragEnterEvent evt) - { - if (TargetComponent == null) return; - - _avatarRoot = RuntimeUtil.FindAvatarTransformInParents(TargetComponent.transform); - if (_avatarRoot == null) return; - - _nowDragging = DragAndDrop.objectReferences.OfType() - .Where(o => RuntimeUtil.FindAvatarTransformInParents(o.transform) == _avatarRoot) - .ToArray(); - - if (_nowDragging.Length > 0) + foreach (var reference in references) { - DragAndDrop.visualMode = DragAndDropVisualMode.Link; - - _parentElem.AddToClassList("drop-area--drag-active"); - } - } - - private void OnDragUpdate(DragUpdatedEvent _) - { - if (_nowDragging.Length > 0) DragAndDrop.visualMode = DragAndDropVisualMode.Link; - } - - private void OnDragLeave(DragLeaveEvent evt) - { - _nowDragging = Array.Empty(); - _parentElem.RemoveFromClassList("drop-area--drag-active"); - } - - private void OnDragPerform(DragPerformEvent evt) - { - if (_nowDragging.Length > 0 && TargetComponent != null && _avatarRoot != null) - { - var knownObjs = TargetComponent.Objects.Select(o => o.Object.Get(TargetComponent)).ToHashSet(); - - Undo.RecordObject(TargetComponent, "Add Toggled Objects"); - foreach (var obj in _nowDragging) - { - if (knownObjs.Contains(obj)) continue; - - var aor = new AvatarObjectReference(); - aor.Set(obj); - - var toggledObject = new ToggledObject { Object = aor, Active = !obj.activeSelf }; - TargetComponent.Objects.Add(toggledObject); - } - - EditorUtility.SetDirty(TargetComponent); - PrefabUtility.RecordPrefabInstancePropertyModifications(TargetComponent); + var toggledObject = new ToggledObject { Object = reference, Active = !reference.Get(TargetComponent).activeSelf }; + TargetComponent.Objects.Add(toggledObject); } - _nowDragging = Array.Empty(); - _parentElem.RemoveFromClassList("drop-area--drag-active"); + EditorUtility.SetDirty(TargetComponent); + PrefabUtility.RecordPrefabInstancePropertyModifications(TargetComponent); } } } diff --git a/Editor/Inspector/ObjectToggle/ObjectSwitcherStyles.uss b/Editor/Inspector/ObjectToggle/ObjectSwitcherStyles.uss index d4bdedc5..12402b5d 100644 --- a/Editor/Inspector/ObjectToggle/ObjectSwitcherStyles.uss +++ b/Editor/Inspector/ObjectToggle/ObjectSwitcherStyles.uss @@ -51,6 +51,12 @@ width: 60px; } -.drop-area--drag-active > ListView ScrollView { - background-color: rgba(0, 255, 255, 0.1); +.drop-area--drag-active { + background-color: rgba(0, 127, 255, 0.2); +} + +.drop-area--drag-active .unity-scroll-view, +.drop-area--drag-active .unity-list-view__footer, +.drop-area--drag-active .unity-list-view__reorderable-item { + background-color: rgba(0, 0, 0, 0.0); } diff --git a/Editor/Inspector/ShapeChanger/ShapeChangerEditor.cs b/Editor/Inspector/ShapeChanger/ShapeChangerEditor.cs index 9a278278..9bec32a3 100644 --- a/Editor/Inspector/ShapeChanger/ShapeChangerEditor.cs +++ b/Editor/Inspector/ShapeChanger/ShapeChangerEditor.cs @@ -19,6 +19,7 @@ namespace nadena.dev.modular_avatar.core.editor.ShapeChanger [SerializeField] private StyleSheet uss; [SerializeField] private VisualTreeAsset uxml; + private DragAndDropManipulator _dragAndDropManipulator; private BlendshapeSelectWindow _window; protected override void OnInnerInspectorGUI() @@ -41,6 +42,8 @@ namespace nadena.dev.modular_avatar.core.editor.ShapeChanger listView.showBoundCollectionSize = false; listView.virtualizationMethod = CollectionVirtualizationMethod.DynamicHeight; + _dragAndDropManipulator = new DragAndDropManipulator(root.Q("group-box"), target as ModularAvatarShapeChanger); + // The Add button callback isn't exposed publicly for some reason... var field_addButton = typeof(BaseListView).GetField("m_AddButton", NonPublic | Instance); var addButton = (Button)field_addButton.GetValue(listView); @@ -50,6 +53,41 @@ namespace nadena.dev.modular_avatar.core.editor.ShapeChanger return root; } + private void OnEnable() + { + if (_dragAndDropManipulator != null) + _dragAndDropManipulator.TargetComponent = target as ModularAvatarShapeChanger; + } + + private class DragAndDropManipulator : DragAndDropManipulator + { + public DragAndDropManipulator(VisualElement targetElement, ModularAvatarShapeChanger targetComponent) + : base(targetElement, targetComponent) { } + + protected override bool FilterGameObject(GameObject obj) + { + if (obj.TryGetComponent(out var smr)) + { + return smr.sharedMesh != null && smr.sharedMesh.blendShapeCount > 0; + } + return false; + } + + protected override void AddObjectReferences(AvatarObjectReference[] references) + { + Undo.RecordObject(TargetComponent, "Add Changed Shapes"); + + foreach (var reference in references) + { + var changedShape = new ChangedShape { Object = reference, ShapeName = string.Empty }; + TargetComponent.Shapes.Add(changedShape); + } + + EditorUtility.SetDirty(TargetComponent); + PrefabUtility.RecordPrefabInstancePropertyModifications(TargetComponent); + } + } + private void OnDisable() { if (_window != null) DestroyImmediate(_window); diff --git a/Editor/Inspector/ShapeChanger/ShapeChangerStyles.uss b/Editor/Inspector/ShapeChanger/ShapeChangerStyles.uss index adff445e..e74734ff 100644 --- a/Editor/Inspector/ShapeChanger/ShapeChangerStyles.uss +++ b/Editor/Inspector/ShapeChanger/ShapeChangerStyles.uss @@ -68,3 +68,13 @@ .change-type-delete #f-value-delete { display: flex; } + +.drop-area--drag-active { + background-color: rgba(0, 127, 255, 0.2); +} + +.drop-area--drag-active .unity-scroll-view, +.drop-area--drag-active .unity-list-view__footer, +.drop-area--drag-active .unity-list-view__reorderable-item { + background-color: rgba(0, 0, 0, 0.0); +} From 7ae98d63b096bf8bc89742e9dc8e9750e017c3b6 Mon Sep 17 00:00:00 2001 From: bd_ Date: Sat, 12 Oct 2024 17:29:19 -0700 Subject: [PATCH 77/85] fix: missing localization strings for Replace Object errors (#1282) Closes: #1281 --- Editor/Localization/en-US.json | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Editor/Localization/en-US.json b/Editor/Localization/en-US.json index 8d84f379..07a5a565 100644 --- a/Editor/Localization/en-US.json +++ b/Editor/Localization/en-US.json @@ -150,6 +150,8 @@ "error.rename_params.default_value_conflict:hint": "To avoid unpredictable behavior, leave the default value field blank in all but on MA Parameters component. If multiple values are present, Modular Avatar will select the first default value specified in the hierarchy order.", "error.replace_object.null_target": "[MA-0008] No target specified", "error.replace_object.null_target:hint": "Replace object needs a target object to replace. Try setting one.", + "error.replace_object.replacing_replacement": "[MA-0009] The same target object cannot be specified in multiple Replace Object components", + "error.replace_object.parent_of_target": "[MA-0010] The target object cannot be a parent of this object", "validation.blendshape_sync.no_local_renderer": "[MA-1000] No renderer found on this object", "validation.blendshape_sync.no_local_renderer:hint": "Blendshape Sync acts on a Skinned Mesh Renderer on the same GameObject. Did you attach it to the right object?", "validation.blendshape_sync.no_local_mesh": "[MA-1001] No mesh found on the renderer on this object", From f40d02ceb95a4583adb7d33fd3b7d8785dbded29 Mon Sep 17 00:00:00 2001 From: bd_ Date: Sat, 12 Oct 2024 17:29:27 -0700 Subject: [PATCH 78/85] fix: NRE when `AnimatorControllerLayer.stateMachine` is null (#1283) Closes: #1056 --- Editor/Animation/AnimatorCombiner.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Editor/Animation/AnimatorCombiner.cs b/Editor/Animation/AnimatorCombiner.cs index 674140dc..6a64fe28 100644 --- a/Editor/Animation/AnimatorCombiner.cs +++ b/Editor/Animation/AnimatorCombiner.cs @@ -573,6 +573,8 @@ namespace nadena.dev.modular_avatar.animation private AnimatorStateMachine mapStateMachine(string basePath, AnimatorStateMachine layerStateMachine) { + if (layerStateMachine == null) return null; + var cacheKey = new KeyValuePair(basePath, layerStateMachine); if (_stateMachines.TryGetValue(cacheKey, out var asm)) From 766f728a8aa65c502bfff3276731127fe39a6d8a Mon Sep 17 00:00:00 2001 From: nadena-dev-ci Date: Mon, 14 Oct 2024 10:28:53 +0900 Subject: [PATCH 79/85] New Crowdin updates (#1284) * Update source file en-US.json * Update source file en-US.json * New translations en-us.json (Japanese) --- Editor/Localization/ja-JP.json | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Editor/Localization/ja-JP.json b/Editor/Localization/ja-JP.json index 95c10a1b..ad1378f4 100644 --- a/Editor/Localization/ja-JP.json +++ b/Editor/Localization/ja-JP.json @@ -146,6 +146,8 @@ "error.rename_params.default_value_conflict:hint": "予測不可能な動作を避けるため、MA Parametersコンポーネントの初期値フィールドはパラメーター名毎に1つだけしか指定しないようにし、他のコンポーネントでは空白のままにしてください。複数の値が存在する場合、Modular Avatarは階層順で最初に指定された初期値を採用します。", "error.replace_object.null_target": "[MA-0008] 置き換え先が指定されていません", "error.replace_object.null_target:hint": "Replace Objectは置き換え先のオブジェクトを指定する必要があります。", + "error.replace_object.replacing_replacement": "[MA-0009] 複数のReplace Objectコンポーネントで、同じ置き換え先を指定できません", + "error.replace_object.parent_of_target": "[MA-0010] このオブジェクトの親を置き換え先に指定できません", "validation.blendshape_sync.no_local_renderer": "[MA-1000] このオブジェクトにはSkinned Mesh Rendererがありません。", "validation.blendshape_sync.no_local_renderer:hint": "Blendshape Syncは同じGameObject上のSkinned Mesh Rendererに作用します。コンポーネントが正しいオブジェクトに追加されているか確認してください。", "validation.blendshape_sync.no_local_mesh": "[MA-1001] このオブジェクトにはSkinned Mesh Rendererがありますが、メッシュがありません。", From 5d399dce4a6f036972f300c2f668d16ef5a6eb51 Mon Sep 17 00:00:00 2001 From: bd_ Date: Mon, 14 Oct 2024 21:17:31 -0700 Subject: [PATCH 80/85] ci: workaround VPM issues --- .github/workflows/gameci.yml | 1 + .../ReactiveObjects/AnimationGeneration/ReactiveObjectPass.cs | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/gameci.yml b/.github/workflows/gameci.yml index 2d30547d..adf05e8e 100644 --- a/.github/workflows/gameci.yml +++ b/.github/workflows/gameci.yml @@ -116,6 +116,7 @@ jobs: with: repos: | https://vpm.nadena.dev/vpm-prerelease.json + https://vrchat.github.io/packages/index.json?download - if: ${{ steps.setup.outputs.should_test == 'true' }} name: "Debug: List project contents" diff --git a/Editor/ReactiveObjects/AnimationGeneration/ReactiveObjectPass.cs b/Editor/ReactiveObjects/AnimationGeneration/ReactiveObjectPass.cs index 3ff0fe4a..882f96bf 100644 --- a/Editor/ReactiveObjects/AnimationGeneration/ReactiveObjectPass.cs +++ b/Editor/ReactiveObjects/AnimationGeneration/ReactiveObjectPass.cs @@ -83,7 +83,7 @@ namespace nadena.dev.modular_avatar.core.editor initialValues[condition.Parameter] = condition.InitialValue; } } - } + } private void ProcessInitialStates(Dictionary initialStates, Dictionary shapes) From 662172c2e5a32563a6d95809c26053e18f25c0b1 Mon Sep 17 00:00:00 2001 From: bd_ Date: Tue, 15 Oct 2024 19:13:01 -0700 Subject: [PATCH 81/85] fix: NRE in RO simulator (#1292) --- Editor/ReactiveObjects/Simulator/ROSimulator.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Editor/ReactiveObjects/Simulator/ROSimulator.cs b/Editor/ReactiveObjects/Simulator/ROSimulator.cs index 84896612..66e1578d 100644 --- a/Editor/ReactiveObjects/Simulator/ROSimulator.cs +++ b/Editor/ReactiveObjects/Simulator/ROSimulator.cs @@ -256,7 +256,7 @@ namespace nadena.dev.modular_avatar.core.editor.Simulator return; } - _btn_clear.SetEnabled(!PropertyOverrides.Value.IsEmpty || !MenuItemOverrides.Value.IsEmpty); + _btn_clear.SetEnabled(PropertyOverrides.Value?.IsEmpty == false || MenuItemOverrides.Value?.IsEmpty == false); e_debugInfo.style.display = DisplayStyle.Flex; From b73feb6b71a2f2108417c8a7fc099c9fe4002aa2 Mon Sep 17 00:00:00 2001 From: bd_ Date: Tue, 15 Oct 2024 19:13:08 -0700 Subject: [PATCH 82/85] fix: inactive menu items don't appear in RO debugger (#1291) --- .../AnimationGeneration/ReactiveObjectAnalyzer.cs | 8 +++++--- Editor/ReactiveObjects/Simulator/ROSimulator.cs | 1 + 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/Editor/ReactiveObjects/AnimationGeneration/ReactiveObjectAnalyzer.cs b/Editor/ReactiveObjects/AnimationGeneration/ReactiveObjectAnalyzer.cs index 643c4a4e..923ac135 100644 --- a/Editor/ReactiveObjects/AnimationGeneration/ReactiveObjectAnalyzer.cs +++ b/Editor/ReactiveObjects/AnimationGeneration/ReactiveObjectAnalyzer.cs @@ -21,6 +21,8 @@ namespace nadena.dev.modular_avatar.core.editor public const string BlendshapePrefix = "blendShape."; public const string DeletedShapePrefix = "deletedShape."; + + public bool OptimizeShapes = true; public ImmutableDictionary ForcePropertyOverrides { get; set; } = ImmutableDictionary.Empty; @@ -277,13 +279,13 @@ namespace nadena.dev.modular_avatar.core.editor // corresponding mesh. If we can't, delete ops are merged into the main list of operations. initialStates = new Dictionary(); - + foreach (var (key, info) in shapes.ToList()) { if (info.actionGroups.Count == 0) { // never active control; ignore it entirely - shapes.Remove(key); + if (OptimizeShapes) shapes.Remove(key); continue; } @@ -297,7 +299,7 @@ namespace nadena.dev.modular_avatar.core.editor // If we're now constant-on, we can skip animation generation if (info.actionGroups[^1].IsConstant) { - shapes.Remove(key); + if (OptimizeShapes) shapes.Remove(key); } } } diff --git a/Editor/ReactiveObjects/Simulator/ROSimulator.cs b/Editor/ReactiveObjects/Simulator/ROSimulator.cs index 66e1578d..40b9be8c 100644 --- a/Editor/ReactiveObjects/Simulator/ROSimulator.cs +++ b/Editor/ReactiveObjects/Simulator/ROSimulator.cs @@ -264,6 +264,7 @@ namespace nadena.dev.modular_avatar.core.editor.Simulator _lastComputeContext.InvokeOnInvalidate(this, MaybeRefreshUI); var analysis = new ReactiveObjectAnalyzer(_lastComputeContext); + analysis.OptimizeShapes = false; analysis.ForcePropertyOverrides = PropertyOverrides.Value; analysis.ForceMenuItems = MenuItemOverrides.Value; var result = analysis.Analyze(avatar.gameObject); From 55ab65e22d121341ca443417362bd2044698bca0 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 15 Oct 2024 19:13:24 -0700 Subject: [PATCH 83/85] chore(deps): bump nathanvaughn/actions-cloudflare-purge (#1287) Bumps [nathanvaughn/actions-cloudflare-purge](https://github.com/nathanvaughn/actions-cloudflare-purge) from cd4afdf666c2e6a6720048f27ac9cbdd664a673a to 992cc4e96422fb8ddf077281678373fe41e7736c. - [Release notes](https://github.com/nathanvaughn/actions-cloudflare-purge/releases) - [Commits](https://github.com/nathanvaughn/actions-cloudflare-purge/compare/cd4afdf666c2e6a6720048f27ac9cbdd664a673a...992cc4e96422fb8ddf077281678373fe41e7736c) --- updated-dependencies: - dependency-name: nathanvaughn/actions-cloudflare-purge dependency-type: direct:production ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/deploy-pages.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/deploy-pages.yml b/.github/workflows/deploy-pages.yml index 2ee06ea0..ec465e5c 100644 --- a/.github/workflows/deploy-pages.yml +++ b/.github/workflows/deploy-pages.yml @@ -122,7 +122,7 @@ jobs: workingDirectory: docs-site~ - name: Purge cache - uses: nathanvaughn/actions-cloudflare-purge@cd4afdf666c2e6a6720048f27ac9cbdd664a673a + uses: nathanvaughn/actions-cloudflare-purge@992cc4e96422fb8ddf077281678373fe41e7736c continue-on-error: true with: cf_zone: ${{ secrets.CF_ZONE_ID }} From 8bf1d29bf3630db5fe738b28368482b90143c45c Mon Sep 17 00:00:00 2001 From: bd_ Date: Tue, 15 Oct 2024 19:16:43 -0700 Subject: [PATCH 84/85] test: add missing blendshape/RC tests (#1293) --- .../ReactiveComponent/BlendshapeSyncTest.cs | 61 ++ .../BlendshapeSyncTest.cs.meta | 3 + .../BlendshapeSyncTest.prefab | 799 ++++++++++++++++++ .../BlendshapeSyncTest.prefab.meta | 7 + 4 files changed, 870 insertions(+) create mode 100644 UnitTests~/ReactiveComponent/BlendshapeSyncTest.cs create mode 100644 UnitTests~/ReactiveComponent/BlendshapeSyncTest.cs.meta create mode 100644 UnitTests~/ReactiveComponent/BlendshapeSyncTest.prefab create mode 100644 UnitTests~/ReactiveComponent/BlendshapeSyncTest.prefab.meta diff --git a/UnitTests~/ReactiveComponent/BlendshapeSyncTest.cs b/UnitTests~/ReactiveComponent/BlendshapeSyncTest.cs new file mode 100644 index 00000000..19d61e6c --- /dev/null +++ b/UnitTests~/ReactiveComponent/BlendshapeSyncTest.cs @@ -0,0 +1,61 @@ +using System.Linq; +using modular_avatar_tests; +using nadena.dev.modular_avatar.core.editor; +using NUnit.Framework; +using UnityEngine; + +namespace UnitTests.ReactiveComponent +{ + public class BlendshapeSyncTest : TestBase + { + [Test] + public void blendshapeSync_propagatesThroughMeshes() + { + var root = CreatePrefab("BlendshapeSyncTest.prefab"); + + var analysis = new ReactiveObjectAnalyzer().Analyze(root); + + var m1 = analysis.Shapes[new TargetProp() + { + TargetObject = root.transform.Find("m1").GetComponent(), + PropertyName = "blendShape.bottom" + }]; + var m2 = analysis.Shapes[new TargetProp() + { + TargetObject = root.transform.Find("m2").GetComponent(), + PropertyName = "blendShape.bottom" + }]; + var m3 = analysis.Shapes[new TargetProp() + { + TargetObject = root.transform.Find("m3").GetComponent(), + PropertyName = "blendShape.top" + }]; + + Assert.IsTrue(analysis.Shapes.ContainsKey(new TargetProp() + { + TargetObject = root.transform.Find("m1").GetComponent(), + PropertyName = "deletedShape.bottom" + })); + + Assert.AreEqual(4, analysis.Shapes.Count); + + foreach (var ag in m1.actionGroups) + { + ag.TargetProp = new TargetProp(); + } + + foreach (var ag in m2.actionGroups) + { + ag.TargetProp = new TargetProp(); + } + + foreach (var ag in m3.actionGroups) + { + ag.TargetProp = new TargetProp(); + } + + Assert.AreEqual(m2.actionGroups, m1.actionGroups); + Assert.AreEqual(m3.actionGroups, m1.actionGroups); + } + } +} \ No newline at end of file diff --git a/UnitTests~/ReactiveComponent/BlendshapeSyncTest.cs.meta b/UnitTests~/ReactiveComponent/BlendshapeSyncTest.cs.meta new file mode 100644 index 00000000..c614946b --- /dev/null +++ b/UnitTests~/ReactiveComponent/BlendshapeSyncTest.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: f74d4e816d0247159d977e21ebc57458 +timeCreated: 1728168066 \ No newline at end of file diff --git a/UnitTests~/ReactiveComponent/BlendshapeSyncTest.prefab b/UnitTests~/ReactiveComponent/BlendshapeSyncTest.prefab new file mode 100644 index 00000000..c0b98180 --- /dev/null +++ b/UnitTests~/ReactiveComponent/BlendshapeSyncTest.prefab @@ -0,0 +1,799 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!1 &4750389987621451750 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 3724328547737935111} + - component: {fileID: 6141552197888553193} + - component: {fileID: 866105862211182099} + - component: {fileID: 5955186656294850035} + m_Layer: 0 + m_Name: New Toggle + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &3724328547737935111 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 4750389987621451750} + serializedVersion: 2 + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 1 + m_Children: [] + m_Father: {fileID: 295226914695240947} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!114 &6141552197888553193 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 4750389987621451750} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 3b29d45007c5493d926d2cd45a489529, type: 3} + m_Name: + m_EditorClassIdentifier: + Control: + name: New Toggle + icon: {fileID: 0} + type: 102 + parameter: + name: + value: 1 + style: 0 + subMenu: {fileID: 0} + subParameters: [] + labels: [] + MenuSource: 1 + menuSource_otherObjectChildren: {fileID: 0} + isSynced: 1 + isSaved: 1 + isDefault: 1 + automaticValue: 1 +--- !u!114 &866105862211182099 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 4750389987621451750} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 7ef83cb0c23d4d7c9d41021e544a1978, type: 3} + m_Name: + m_EditorClassIdentifier: + menuToAppend: {fileID: 0} + installTargetMenu: {fileID: 0} +--- !u!114 &5955186656294850035 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 4750389987621451750} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 2db441f589c3407bb6fb5f02ff8ab541, type: 3} + m_Name: + m_EditorClassIdentifier: + m_inverted: 0 + m_shapes: + - Object: + referencePath: m1 + targetObject: {fileID: 7767603723203631002} + ShapeName: bottom + ChangeType: 1 + Value: 100 +--- !u!1 &7303978391080220300 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 295226914695240947} + - component: {fileID: 1177795503533185300} + - component: {fileID: 7792711537747161192} + - component: {fileID: 8538029171187693289} + m_Layer: 0 + m_Name: BlendshapeSyncTest + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &295226914695240947 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 7303978391080220300} + serializedVersion: 2 + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 1.1618705, y: 1.0265146, z: 1.8807894} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 1 + m_Children: + - {fileID: 6955742288500591904} + - {fileID: 2035853062413530075} + - {fileID: 2118711245520540949} + - {fileID: 3724328547737935111} + m_Father: {fileID: 0} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!95 &1177795503533185300 +Animator: + serializedVersion: 5 + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 7303978391080220300} + m_Enabled: 1 + m_Avatar: {fileID: 0} + m_Controller: {fileID: 0} + m_CullingMode: 0 + m_UpdateMode: 0 + m_ApplyRootMotion: 0 + m_LinearVelocityBlending: 0 + m_StabilizeFeet: 0 + m_WarningMessage: + m_HasTransformHierarchy: 1 + m_AllowConstantClipSamplingOptimization: 1 + m_KeepAnimatorStateOnDisable: 0 + m_WriteDefaultValuesOnDisable: 0 +--- !u!114 &7792711537747161192 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 7303978391080220300} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 542108242, guid: 67cc4cb7839cd3741b63733d5adf0442, type: 3} + m_Name: + m_EditorClassIdentifier: + Name: + ViewPosition: {x: 0, y: 1.6, z: 0.2} + Animations: 0 + ScaleIPD: 1 + lipSync: 0 + lipSyncJawBone: {fileID: 0} + lipSyncJawClosed: {x: 0, y: 0, z: 0, w: 1} + lipSyncJawOpen: {x: 0, y: 0, z: 0, w: 1} + VisemeSkinnedMesh: {fileID: 0} + MouthOpenBlendShapeName: Facial_Blends.Jaw_Down + VisemeBlendShapes: [] + unityVersion: + portraitCameraPositionOffset: {x: 0, y: 0, z: 0} + portraitCameraRotationOffset: {x: 0, y: 1, z: 0, w: -0.00000004371139} + networkIDs: [] + customExpressions: 0 + expressionsMenu: {fileID: 0} + expressionParameters: {fileID: 0} + enableEyeLook: 0 + customEyeLookSettings: + eyeMovement: + confidence: 0.5 + excitement: 0.5 + leftEye: {fileID: 0} + rightEye: {fileID: 0} + eyesLookingStraight: + linked: 1 + left: {x: 0, y: 0, z: 0, w: 0} + right: {x: 0, y: 0, z: 0, w: 0} + eyesLookingUp: + linked: 1 + left: {x: 0, y: 0, z: 0, w: 0} + right: {x: 0, y: 0, z: 0, w: 0} + eyesLookingDown: + linked: 1 + left: {x: 0, y: 0, z: 0, w: 0} + right: {x: 0, y: 0, z: 0, w: 0} + eyesLookingLeft: + linked: 1 + left: {x: 0, y: 0, z: 0, w: 0} + right: {x: 0, y: 0, z: 0, w: 0} + eyesLookingRight: + linked: 1 + left: {x: 0, y: 0, z: 0, w: 0} + right: {x: 0, y: 0, z: 0, w: 0} + eyelidType: 0 + upperLeftEyelid: {fileID: 0} + upperRightEyelid: {fileID: 0} + lowerLeftEyelid: {fileID: 0} + lowerRightEyelid: {fileID: 0} + eyelidsDefault: + upper: + linked: 1 + left: {x: 0, y: 0, z: 0, w: 0} + right: {x: 0, y: 0, z: 0, w: 0} + lower: + linked: 1 + left: {x: 0, y: 0, z: 0, w: 0} + right: {x: 0, y: 0, z: 0, w: 0} + eyelidsClosed: + upper: + linked: 1 + left: {x: 0, y: 0, z: 0, w: 0} + right: {x: 0, y: 0, z: 0, w: 0} + lower: + linked: 1 + left: {x: 0, y: 0, z: 0, w: 0} + right: {x: 0, y: 0, z: 0, w: 0} + eyelidsLookingUp: + upper: + linked: 1 + left: {x: 0, y: 0, z: 0, w: 0} + right: {x: 0, y: 0, z: 0, w: 0} + lower: + linked: 1 + left: {x: 0, y: 0, z: 0, w: 0} + right: {x: 0, y: 0, z: 0, w: 0} + eyelidsLookingDown: + upper: + linked: 1 + left: {x: 0, y: 0, z: 0, w: 0} + right: {x: 0, y: 0, z: 0, w: 0} + lower: + linked: 1 + left: {x: 0, y: 0, z: 0, w: 0} + right: {x: 0, y: 0, z: 0, w: 0} + eyelidsSkinnedMesh: {fileID: 0} + eyelidsBlendshapes: + customizeAnimationLayers: 0 + baseAnimationLayers: + - isEnabled: 0 + type: 0 + animatorController: {fileID: 0} + mask: {fileID: 0} + isDefault: 1 + - isEnabled: 0 + type: 4 + animatorController: {fileID: 0} + mask: {fileID: 0} + isDefault: 1 + - isEnabled: 0 + type: 5 + animatorController: {fileID: 0} + mask: {fileID: 0} + isDefault: 1 + specialAnimationLayers: + - isEnabled: 0 + type: 6 + animatorController: {fileID: 0} + mask: {fileID: 0} + isDefault: 1 + - isEnabled: 0 + type: 7 + animatorController: {fileID: 0} + mask: {fileID: 0} + isDefault: 1 + - isEnabled: 0 + type: 8 + animatorController: {fileID: 0} + mask: {fileID: 0} + isDefault: 1 + AnimationPreset: {fileID: 0} + animationHashSet: [] + autoFootsteps: 1 + autoLocomotion: 1 + collider_head: + isMirrored: 1 + state: 0 + transform: {fileID: 0} + radius: 0 + height: 0 + position: {x: 0, y: 0, z: 0} + rotation: {x: 0, y: 0, z: 0, w: 1} + collider_torso: + isMirrored: 1 + state: 0 + transform: {fileID: 0} + radius: 0 + height: 0 + position: {x: 0, y: 0, z: 0} + rotation: {x: 0, y: 0, z: 0, w: 1} + collider_footR: + isMirrored: 1 + state: 0 + transform: {fileID: 0} + radius: 0 + height: 0 + position: {x: 0, y: 0, z: 0} + rotation: {x: 0, y: 0, z: 0, w: 1} + collider_footL: + isMirrored: 1 + state: 0 + transform: {fileID: 0} + radius: 0 + height: 0 + position: {x: 0, y: 0, z: 0} + rotation: {x: 0, y: 0, z: 0, w: 1} + collider_handR: + isMirrored: 1 + state: 0 + transform: {fileID: 0} + radius: 0 + height: 0 + position: {x: 0, y: 0, z: 0} + rotation: {x: 0, y: 0, z: 0, w: 1} + collider_handL: + isMirrored: 1 + state: 0 + transform: {fileID: 0} + radius: 0 + height: 0 + position: {x: 0, y: 0, z: 0} + rotation: {x: 0, y: 0, z: 0, w: 1} + collider_fingerIndexL: + isMirrored: 1 + state: 0 + transform: {fileID: 0} + radius: 0 + height: 0 + position: {x: 0, y: 0, z: 0} + rotation: {x: 0, y: 0, z: 0, w: 1} + collider_fingerMiddleL: + isMirrored: 1 + state: 0 + transform: {fileID: 0} + radius: 0 + height: 0 + position: {x: 0, y: 0, z: 0} + rotation: {x: 0, y: 0, z: 0, w: 1} + collider_fingerRingL: + isMirrored: 1 + state: 0 + transform: {fileID: 0} + radius: 0 + height: 0 + position: {x: 0, y: 0, z: 0} + rotation: {x: 0, y: 0, z: 0, w: 1} + collider_fingerLittleL: + isMirrored: 1 + state: 0 + transform: {fileID: 0} + radius: 0 + height: 0 + position: {x: 0, y: 0, z: 0} + rotation: {x: 0, y: 0, z: 0, w: 1} + collider_fingerIndexR: + isMirrored: 1 + state: 0 + transform: {fileID: 0} + radius: 0 + height: 0 + position: {x: 0, y: 0, z: 0} + rotation: {x: 0, y: 0, z: 0, w: 1} + collider_fingerMiddleR: + isMirrored: 1 + state: 0 + transform: {fileID: 0} + radius: 0 + height: 0 + position: {x: 0, y: 0, z: 0} + rotation: {x: 0, y: 0, z: 0, w: 1} + collider_fingerRingR: + isMirrored: 1 + state: 0 + transform: {fileID: 0} + radius: 0 + height: 0 + position: {x: 0, y: 0, z: 0} + rotation: {x: 0, y: 0, z: 0, w: 1} + collider_fingerLittleR: + isMirrored: 1 + state: 0 + transform: {fileID: 0} + radius: 0 + height: 0 + position: {x: 0, y: 0, z: 0} + rotation: {x: 0, y: 0, z: 0, w: 1} +--- !u!114 &8538029171187693289 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 7303978391080220300} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: -1427037861, guid: 4ecd63eff847044b68db9453ce219299, type: 3} + m_Name: + m_EditorClassIdentifier: + launchedFromSDKPipeline: 0 + completedSDKPipeline: 0 + blueprintId: + contentType: 0 + assetBundleUnityVersion: + fallbackStatus: 0 +--- !u!1001 &1940371780088492798 +PrefabInstance: + m_ObjectHideFlags: 0 + serializedVersion: 2 + m_Modification: + serializedVersion: 3 + m_TransformParent: {fileID: 295226914695240947} + m_Modifications: + - target: {fileID: -8679921383154817045, guid: fe5b76dae94c07345b74d51e9a9a8440, + type: 3} + propertyPath: m_LocalPosition.x + value: 5.33 + objectReference: {fileID: 0} + - target: {fileID: -8679921383154817045, guid: fe5b76dae94c07345b74d51e9a9a8440, + type: 3} + propertyPath: m_LocalPosition.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: -8679921383154817045, guid: fe5b76dae94c07345b74d51e9a9a8440, + type: 3} + propertyPath: m_LocalPosition.z + value: 0 + objectReference: {fileID: 0} + - target: {fileID: -8679921383154817045, guid: fe5b76dae94c07345b74d51e9a9a8440, + type: 3} + propertyPath: m_LocalRotation.w + value: 0.7071067 + objectReference: {fileID: 0} + - target: {fileID: -8679921383154817045, guid: fe5b76dae94c07345b74d51e9a9a8440, + type: 3} + propertyPath: m_LocalRotation.x + value: -0.7071068 + objectReference: {fileID: 0} + - target: {fileID: -8679921383154817045, guid: fe5b76dae94c07345b74d51e9a9a8440, + type: 3} + propertyPath: m_LocalRotation.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: -8679921383154817045, guid: fe5b76dae94c07345b74d51e9a9a8440, + type: 3} + propertyPath: m_LocalRotation.z + value: -0 + objectReference: {fileID: 0} + - target: {fileID: -8679921383154817045, guid: fe5b76dae94c07345b74d51e9a9a8440, + type: 3} + propertyPath: m_LocalEulerAnglesHint.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: -8679921383154817045, guid: fe5b76dae94c07345b74d51e9a9a8440, + type: 3} + propertyPath: m_LocalEulerAnglesHint.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: -8679921383154817045, guid: fe5b76dae94c07345b74d51e9a9a8440, + type: 3} + propertyPath: m_LocalEulerAnglesHint.z + value: 0 + objectReference: {fileID: 0} + - target: {fileID: -8679921383154817045, guid: fe5b76dae94c07345b74d51e9a9a8440, + type: 3} + propertyPath: m_ConstrainProportionsScale + value: 1 + objectReference: {fileID: 0} + - target: {fileID: -3887185075125053422, guid: fe5b76dae94c07345b74d51e9a9a8440, + type: 3} + propertyPath: m_DirtyAABB + value: 0 + objectReference: {fileID: 0} + - target: {fileID: -3887185075125053422, guid: fe5b76dae94c07345b74d51e9a9a8440, + type: 3} + propertyPath: m_AABB.m_Extent.x + value: 1 + objectReference: {fileID: 0} + - target: {fileID: -3887185075125053422, guid: fe5b76dae94c07345b74d51e9a9a8440, + type: 3} + propertyPath: m_AABB.m_Extent.y + value: 1 + objectReference: {fileID: 0} + - target: {fileID: -3887185075125053422, guid: fe5b76dae94c07345b74d51e9a9a8440, + type: 3} + propertyPath: m_AABB.m_Extent.z + value: 2 + objectReference: {fileID: 0} + - target: {fileID: -3887185075125053422, guid: fe5b76dae94c07345b74d51e9a9a8440, + type: 3} + propertyPath: m_BlendShapeWeights.Array.data[0] + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 919132149155446097, guid: fe5b76dae94c07345b74d51e9a9a8440, + type: 3} + propertyPath: m_Name + value: m3 + objectReference: {fileID: 0} + m_RemovedComponents: [] + m_RemovedGameObjects: [] + m_AddedGameObjects: [] + m_AddedComponents: + - targetCorrespondingSourceObject: {fileID: 919132149155446097, guid: fe5b76dae94c07345b74d51e9a9a8440, + type: 3} + insertIndex: -1 + addedObject: {fileID: 4462016549056391230} + m_SourcePrefab: {fileID: 100100000, guid: fe5b76dae94c07345b74d51e9a9a8440, type: 3} +--- !u!1 &1597929094539956143 stripped +GameObject: + m_CorrespondingSourceObject: {fileID: 919132149155446097, guid: fe5b76dae94c07345b74d51e9a9a8440, + type: 3} + m_PrefabInstance: {fileID: 1940371780088492798} + m_PrefabAsset: {fileID: 0} +--- !u!114 &4462016549056391230 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1597929094539956143} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 6fd7cab7d93b403280f2f9da978d8a4f, type: 3} + m_Name: + m_EditorClassIdentifier: + Bindings: + - ReferenceMesh: + referencePath: m2 + targetObject: {fileID: 1660453041666320737} + Blendshape: bottom + LocalBlendshape: top +--- !u!4 &2118711245520540949 stripped +Transform: + m_CorrespondingSourceObject: {fileID: -8679921383154817045, guid: fe5b76dae94c07345b74d51e9a9a8440, + type: 3} + m_PrefabInstance: {fileID: 1940371780088492798} + m_PrefabAsset: {fileID: 0} +--- !u!1001 &2002541556693849136 +PrefabInstance: + m_ObjectHideFlags: 0 + serializedVersion: 2 + m_Modification: + serializedVersion: 3 + m_TransformParent: {fileID: 295226914695240947} + m_Modifications: + - target: {fileID: -8679921383154817045, guid: fe5b76dae94c07345b74d51e9a9a8440, + type: 3} + propertyPath: m_LocalPosition.x + value: 2.75 + objectReference: {fileID: 0} + - target: {fileID: -8679921383154817045, guid: fe5b76dae94c07345b74d51e9a9a8440, + type: 3} + propertyPath: m_LocalPosition.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: -8679921383154817045, guid: fe5b76dae94c07345b74d51e9a9a8440, + type: 3} + propertyPath: m_LocalPosition.z + value: 0 + objectReference: {fileID: 0} + - target: {fileID: -8679921383154817045, guid: fe5b76dae94c07345b74d51e9a9a8440, + type: 3} + propertyPath: m_LocalRotation.w + value: 0.7071067 + objectReference: {fileID: 0} + - target: {fileID: -8679921383154817045, guid: fe5b76dae94c07345b74d51e9a9a8440, + type: 3} + propertyPath: m_LocalRotation.x + value: -0.7071068 + objectReference: {fileID: 0} + - target: {fileID: -8679921383154817045, guid: fe5b76dae94c07345b74d51e9a9a8440, + type: 3} + propertyPath: m_LocalRotation.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: -8679921383154817045, guid: fe5b76dae94c07345b74d51e9a9a8440, + type: 3} + propertyPath: m_LocalRotation.z + value: -0 + objectReference: {fileID: 0} + - target: {fileID: -8679921383154817045, guid: fe5b76dae94c07345b74d51e9a9a8440, + type: 3} + propertyPath: m_LocalEulerAnglesHint.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: -8679921383154817045, guid: fe5b76dae94c07345b74d51e9a9a8440, + type: 3} + propertyPath: m_LocalEulerAnglesHint.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: -8679921383154817045, guid: fe5b76dae94c07345b74d51e9a9a8440, + type: 3} + propertyPath: m_LocalEulerAnglesHint.z + value: 0 + objectReference: {fileID: 0} + - target: {fileID: -8679921383154817045, guid: fe5b76dae94c07345b74d51e9a9a8440, + type: 3} + propertyPath: m_ConstrainProportionsScale + value: 1 + objectReference: {fileID: 0} + - target: {fileID: -3887185075125053422, guid: fe5b76dae94c07345b74d51e9a9a8440, + type: 3} + propertyPath: m_DirtyAABB + value: 0 + objectReference: {fileID: 0} + - target: {fileID: -3887185075125053422, guid: fe5b76dae94c07345b74d51e9a9a8440, + type: 3} + propertyPath: m_AABB.m_Extent.x + value: 1 + objectReference: {fileID: 0} + - target: {fileID: -3887185075125053422, guid: fe5b76dae94c07345b74d51e9a9a8440, + type: 3} + propertyPath: m_AABB.m_Extent.y + value: 1 + objectReference: {fileID: 0} + - target: {fileID: -3887185075125053422, guid: fe5b76dae94c07345b74d51e9a9a8440, + type: 3} + propertyPath: m_AABB.m_Extent.z + value: 2 + objectReference: {fileID: 0} + - target: {fileID: -3887185075125053422, guid: fe5b76dae94c07345b74d51e9a9a8440, + type: 3} + propertyPath: m_BlendShapeWeights.Array.data[0] + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 919132149155446097, guid: fe5b76dae94c07345b74d51e9a9a8440, + type: 3} + propertyPath: m_Name + value: m2 + objectReference: {fileID: 0} + m_RemovedComponents: [] + m_RemovedGameObjects: [] + m_AddedGameObjects: [] + m_AddedComponents: + - targetCorrespondingSourceObject: {fileID: 919132149155446097, guid: fe5b76dae94c07345b74d51e9a9a8440, + type: 3} + insertIndex: -1 + addedObject: {fileID: 1532028097981150578} + m_SourcePrefab: {fileID: 100100000, guid: fe5b76dae94c07345b74d51e9a9a8440, type: 3} +--- !u!1 &1660453041666320737 stripped +GameObject: + m_CorrespondingSourceObject: {fileID: 919132149155446097, guid: fe5b76dae94c07345b74d51e9a9a8440, + type: 3} + m_PrefabInstance: {fileID: 2002541556693849136} + m_PrefabAsset: {fileID: 0} +--- !u!114 &1532028097981150578 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1660453041666320737} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 6fd7cab7d93b403280f2f9da978d8a4f, type: 3} + m_Name: + m_EditorClassIdentifier: + Bindings: + - ReferenceMesh: + referencePath: m1 + targetObject: {fileID: 7767603723203631002} + Blendshape: bottom + LocalBlendshape: +--- !u!4 &2035853062413530075 stripped +Transform: + m_CorrespondingSourceObject: {fileID: -8679921383154817045, guid: fe5b76dae94c07345b74d51e9a9a8440, + type: 3} + m_PrefabInstance: {fileID: 2002541556693849136} + m_PrefabAsset: {fileID: 0} +--- !u!1001 &7425727422508624587 +PrefabInstance: + m_ObjectHideFlags: 0 + serializedVersion: 2 + m_Modification: + serializedVersion: 3 + m_TransformParent: {fileID: 295226914695240947} + m_Modifications: + - target: {fileID: -8679921383154817045, guid: fe5b76dae94c07345b74d51e9a9a8440, + type: 3} + propertyPath: m_LocalPosition.x + value: -0 + objectReference: {fileID: 0} + - target: {fileID: -8679921383154817045, guid: fe5b76dae94c07345b74d51e9a9a8440, + type: 3} + propertyPath: m_LocalPosition.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: -8679921383154817045, guid: fe5b76dae94c07345b74d51e9a9a8440, + type: 3} + propertyPath: m_LocalPosition.z + value: 0 + objectReference: {fileID: 0} + - target: {fileID: -8679921383154817045, guid: fe5b76dae94c07345b74d51e9a9a8440, + type: 3} + propertyPath: m_LocalRotation.w + value: 0.7071067 + objectReference: {fileID: 0} + - target: {fileID: -8679921383154817045, guid: fe5b76dae94c07345b74d51e9a9a8440, + type: 3} + propertyPath: m_LocalRotation.x + value: -0.7071068 + objectReference: {fileID: 0} + - target: {fileID: -8679921383154817045, guid: fe5b76dae94c07345b74d51e9a9a8440, + type: 3} + propertyPath: m_LocalRotation.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: -8679921383154817045, guid: fe5b76dae94c07345b74d51e9a9a8440, + type: 3} + propertyPath: m_LocalRotation.z + value: -0 + objectReference: {fileID: 0} + - target: {fileID: -8679921383154817045, guid: fe5b76dae94c07345b74d51e9a9a8440, + type: 3} + propertyPath: m_LocalEulerAnglesHint.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: -8679921383154817045, guid: fe5b76dae94c07345b74d51e9a9a8440, + type: 3} + propertyPath: m_LocalEulerAnglesHint.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: -8679921383154817045, guid: fe5b76dae94c07345b74d51e9a9a8440, + type: 3} + propertyPath: m_LocalEulerAnglesHint.z + value: 0 + objectReference: {fileID: 0} + - target: {fileID: -3887185075125053422, guid: fe5b76dae94c07345b74d51e9a9a8440, + type: 3} + propertyPath: m_DirtyAABB + value: 0 + objectReference: {fileID: 0} + - target: {fileID: -3887185075125053422, guid: fe5b76dae94c07345b74d51e9a9a8440, + type: 3} + propertyPath: m_AABB.m_Extent.x + value: 1 + objectReference: {fileID: 0} + - target: {fileID: -3887185075125053422, guid: fe5b76dae94c07345b74d51e9a9a8440, + type: 3} + propertyPath: m_AABB.m_Extent.y + value: 1 + objectReference: {fileID: 0} + - target: {fileID: -3887185075125053422, guid: fe5b76dae94c07345b74d51e9a9a8440, + type: 3} + propertyPath: m_AABB.m_Extent.z + value: 2 + objectReference: {fileID: 0} + - target: {fileID: -3887185075125053422, guid: fe5b76dae94c07345b74d51e9a9a8440, + type: 3} + propertyPath: m_Materials.Array.data[0] + value: + objectReference: {fileID: 0} + - target: {fileID: -3887185075125053422, guid: fe5b76dae94c07345b74d51e9a9a8440, + type: 3} + propertyPath: m_BlendShapeWeights.Array.data[0] + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 919132149155446097, guid: fe5b76dae94c07345b74d51e9a9a8440, + type: 3} + propertyPath: m_Name + value: m1 + objectReference: {fileID: 0} + m_RemovedComponents: [] + m_RemovedGameObjects: [] + m_AddedGameObjects: [] + m_AddedComponents: [] + m_SourcePrefab: {fileID: 100100000, guid: fe5b76dae94c07345b74d51e9a9a8440, type: 3} +--- !u!4 &6955742288500591904 stripped +Transform: + m_CorrespondingSourceObject: {fileID: -8679921383154817045, guid: fe5b76dae94c07345b74d51e9a9a8440, + type: 3} + m_PrefabInstance: {fileID: 7425727422508624587} + m_PrefabAsset: {fileID: 0} +--- !u!1 &7767603723203631002 stripped +GameObject: + m_CorrespondingSourceObject: {fileID: 919132149155446097, guid: fe5b76dae94c07345b74d51e9a9a8440, + type: 3} + m_PrefabInstance: {fileID: 7425727422508624587} + m_PrefabAsset: {fileID: 0} diff --git a/UnitTests~/ReactiveComponent/BlendshapeSyncTest.prefab.meta b/UnitTests~/ReactiveComponent/BlendshapeSyncTest.prefab.meta new file mode 100644 index 00000000..d6863646 --- /dev/null +++ b/UnitTests~/ReactiveComponent/BlendshapeSyncTest.prefab.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 05653f5cab04e764b80709fe866c1b35 +PrefabImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: From 3ba02194300c4432f267e4dec80f2d399a815a0f Mon Sep 17 00:00:00 2001 From: bd_ Date: Tue, 15 Oct 2024 19:19:05 -0700 Subject: [PATCH 85/85] 1.10.4 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 778562f3..ec982b70 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "nadena.dev.modular-avatar", "displayName": "Modular Avatar", - "version": "1.10.3", + "version": "1.10.4", "unity": "2022.3", "description": "A suite of tools for assembling your avatar out of reusable components", "author": {