mirror of
https://github.com/bdunderscore/modular-avatar.git
synced 2024-12-29 18:55:06 +08:00
feat: add UI to show parameter usage (#773)
This commit is contained in:
parent
532e3bc250
commit
654aec1aab
4
.github/ProjectRoot/vpm-manifest-2019.json
vendored
4
.github/ProjectRoot/vpm-manifest-2019.json
vendored
@ -4,7 +4,7 @@
|
|||||||
"version": "3.4.2"
|
"version": "3.4.2"
|
||||||
},
|
},
|
||||||
"nadena.dev.ndmf": {
|
"nadena.dev.ndmf": {
|
||||||
"version": "1.3.6"
|
"version": "1.4.0-rc.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
@ -19,7 +19,7 @@
|
|||||||
"dependencies": {}
|
"dependencies": {}
|
||||||
},
|
},
|
||||||
"nadena.dev.ndmf": {
|
"nadena.dev.ndmf": {
|
||||||
"version": "1.3.6"
|
"version": "1.4.0-rc.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
4
.github/ProjectRoot/vpm-manifest-2022.json
vendored
4
.github/ProjectRoot/vpm-manifest-2022.json
vendored
@ -4,7 +4,7 @@
|
|||||||
"version": "3.5.0"
|
"version": "3.5.0"
|
||||||
},
|
},
|
||||||
"nadena.dev.ndmf": {
|
"nadena.dev.ndmf": {
|
||||||
"version": "1.3.6"
|
"version": "1.4.0-rc.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
@ -19,7 +19,7 @@
|
|||||||
"dependencies": {}
|
"dependencies": {}
|
||||||
},
|
},
|
||||||
"nadena.dev.ndmf": {
|
"nadena.dev.ndmf": {
|
||||||
"version": "1.3.6"
|
"version": "1.4.0-rc.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
102
Editor/HarmonyPatches/InjectParamsUsageUI.cs
Normal file
102
Editor/HarmonyPatches/InjectParamsUsageUI.cs
Normal file
@ -0,0 +1,102 @@
|
|||||||
|
#region
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Reflection;
|
||||||
|
using System.Reflection.Emit;
|
||||||
|
using HarmonyLib;
|
||||||
|
using UnityEditor;
|
||||||
|
using UnityEngine;
|
||||||
|
using UnityEngine.UIElements;
|
||||||
|
using Object = UnityEngine.Object;
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
namespace nadena.dev.modular_avatar.core.editor.HarmonyPatches
|
||||||
|
{
|
||||||
|
internal static class InjectParamsUsageUI
|
||||||
|
{
|
||||||
|
private static readonly Type type = AccessTools.TypeByName("UnityEditor.PropertyEditor");
|
||||||
|
private static readonly PropertyInfo _editorsElement = AccessTools.Property(type, "editorsElement");
|
||||||
|
|
||||||
|
private static readonly Type editorElem = AccessTools.TypeByName("UnityEditor.UIElements.EditorElement");
|
||||||
|
private static readonly PropertyInfo editorElem_editor = AccessTools.Property(editorElem, "editor");
|
||||||
|
|
||||||
|
public static void Patch(Harmony h)
|
||||||
|
{
|
||||||
|
var type = AccessTools.TypeByName("UnityEditor.PropertyEditor");
|
||||||
|
var drawEditors = AccessTools.Method(type, "DrawEditors");
|
||||||
|
|
||||||
|
h.Patch(drawEditors, transpiler: new HarmonyMethod(typeof(InjectParamsUsageUI), nameof(Transpile)));
|
||||||
|
|
||||||
|
var objNames = AccessTools.TypeByName("UnityEditor.ObjectNames");
|
||||||
|
var m_GetObjectTypeName = AccessTools.Method(objNames, "GetObjectTypeName");
|
||||||
|
var postfix_GetObjectTypeName =
|
||||||
|
AccessTools.Method(typeof(InjectParamsUsageUI), nameof(Postfix_GetObjectTypeName));
|
||||||
|
|
||||||
|
h.Patch(m_GetObjectTypeName, postfix: new HarmonyMethod(postfix_GetObjectTypeName));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void Postfix_GetObjectTypeName(ref string __result, Object o)
|
||||||
|
{
|
||||||
|
if (o is ModularAvatarInformation)
|
||||||
|
{
|
||||||
|
__result = "Modular Avatar Information";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static IEnumerable<CodeInstruction> Transpile(IEnumerable<CodeInstruction> ci)
|
||||||
|
{
|
||||||
|
var target = AccessTools.Method(typeof(VisualElement), "Add");
|
||||||
|
|
||||||
|
foreach (var i in ci)
|
||||||
|
{
|
||||||
|
if (i.opcode != OpCodes.Callvirt)
|
||||||
|
{
|
||||||
|
yield return i;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (i.opcode == OpCodes.Callvirt
|
||||||
|
&& i.operand is MethodInfo method
|
||||||
|
&& method == target
|
||||||
|
)
|
||||||
|
{
|
||||||
|
yield return new CodeInstruction(OpCodes.Ldarg_0);
|
||||||
|
yield return new CodeInstruction(OpCodes.Call,
|
||||||
|
AccessTools.Method(typeof(InjectParamsUsageUI), nameof(EditorAdd)));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
yield return i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void EditorAdd(VisualElement container, VisualElement child, object caller)
|
||||||
|
{
|
||||||
|
container.Add(child);
|
||||||
|
|
||||||
|
var editorsElement = _editorsElement.GetValue(caller) as VisualElement;
|
||||||
|
if (editorsElement != container)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!child.ClassListContains("game-object-inspector"))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var editor = editorElem_editor.GetValue(child) as Editor;
|
||||||
|
if (editor == null) return;
|
||||||
|
|
||||||
|
if (editor.targets.Length != 1) return;
|
||||||
|
|
||||||
|
if (editor.target is GameObject obj)
|
||||||
|
{
|
||||||
|
var elem = new ParamsUsageUI();
|
||||||
|
container.Add(elem);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
3
Editor/HarmonyPatches/InjectParamsUsageUI.cs.meta
Normal file
3
Editor/HarmonyPatches/InjectParamsUsageUI.cs.meta
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 5d62a8f41641443ea8bffdc0429e0ad1
|
||||||
|
timeCreated: 1710223876
|
@ -17,6 +17,7 @@ namespace nadena.dev.modular_avatar.core.editor.HarmonyPatches
|
|||||||
#if UNITY_2022_3_OR_NEWER
|
#if UNITY_2022_3_OR_NEWER
|
||||||
HandleUtilityPatches.Patch_FilterInstanceIDs,
|
HandleUtilityPatches.Patch_FilterInstanceIDs,
|
||||||
PickingObjectPatch.Patch,
|
PickingObjectPatch.Patch,
|
||||||
|
InjectParamsUsageUI.Patch,
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -36,6 +37,8 @@ namespace nadena.dev.modular_avatar.core.editor.HarmonyPatches
|
|||||||
Debug.LogException(e);
|
Debug.LogException(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
AssemblyReloadEvents.beforeAssemblyReload += () => { harmony.UnpatchAll(); };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,9 +1,11 @@
|
|||||||
{
|
{
|
||||||
"name": "nadena.dev.modular-avatar.harmony-patches",
|
"name": "nadena.dev.modular-avatar.harmony-patches",
|
||||||
|
"rootNamespace": "",
|
||||||
"references": [
|
"references": [
|
||||||
"nadena.dev.modular-avatar.core",
|
"nadena.dev.modular-avatar.core",
|
||||||
"nadena.dev.modular-avatar.core.editor",
|
"nadena.dev.modular-avatar.core.editor",
|
||||||
"VRC.SDKBase.Editor"
|
"VRC.SDKBase.Editor",
|
||||||
|
"nadena.dev.modular-avatar.param-introspection"
|
||||||
],
|
],
|
||||||
"includePlatforms": [
|
"includePlatforms": [
|
||||||
"Editor"
|
"Editor"
|
||||||
|
@ -22,7 +22,12 @@
|
|||||||
* SOFTWARE.
|
* SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#region
|
||||||
|
|
||||||
using UnityEditor;
|
using UnityEditor;
|
||||||
|
using UnityEngine;
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
namespace nadena.dev.modular_avatar.core.editor
|
namespace nadena.dev.modular_avatar.core.editor
|
||||||
{
|
{
|
||||||
@ -30,6 +35,11 @@ namespace nadena.dev.modular_avatar.core.editor
|
|||||||
[CanEditMultipleObjects]
|
[CanEditMultipleObjects]
|
||||||
internal class PBBlockerEditor : MAEditorBase
|
internal class PBBlockerEditor : MAEditorBase
|
||||||
{
|
{
|
||||||
|
public PBBlockerEditor()
|
||||||
|
{
|
||||||
|
Debug.Log("ctor");
|
||||||
|
}
|
||||||
|
|
||||||
protected override void OnInnerInspectorGUI()
|
protected override void OnInnerInspectorGUI()
|
||||||
{
|
{
|
||||||
EditorGUILayout.HelpBox(Localization.S("pb_blocker.help"), MessageType.Info);
|
EditorGUILayout.HelpBox(Localization.S("pb_blocker.help"), MessageType.Info);
|
||||||
|
@ -1,9 +1,13 @@
|
|||||||
using System;
|
#region
|
||||||
|
|
||||||
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using nadena.dev.ndmf.localization;
|
using nadena.dev.ndmf.localization;
|
||||||
using UnityEngine.UIElements;
|
using UnityEngine.UIElements;
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
namespace nadena.dev.modular_avatar.core.editor
|
namespace nadena.dev.modular_avatar.core.editor
|
||||||
{
|
{
|
||||||
internal class UIElementLocalizer
|
internal class UIElementLocalizer
|
||||||
@ -21,6 +25,7 @@ namespace nadena.dev.modular_avatar.core.editor
|
|||||||
internal void Localize(VisualElement elem)
|
internal void Localize(VisualElement elem)
|
||||||
{
|
{
|
||||||
WalkTree(elem);
|
WalkTree(elem);
|
||||||
|
LanguagePrefs.ApplyFontPreferences(elem);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void WalkTree(VisualElement elem)
|
private void WalkTree(VisualElement elem)
|
||||||
|
@ -240,5 +240,9 @@
|
|||||||
"scale_adjuster.scale": "Scale adjustment",
|
"scale_adjuster.scale": "Scale adjustment",
|
||||||
"scale_adjuster.adjust_children": "Adjust position of child objects",
|
"scale_adjuster.adjust_children": "Adjust position of child objects",
|
||||||
"world_fixed_object.err.unsupported_platform": "World Fixed Object is not supported on this platform",
|
"world_fixed_object.err.unsupported_platform": "World Fixed Object is not supported on this platform",
|
||||||
"world_fixed_object.err.unsupported_platform:description": "World Fixed Object is not supported on Android builds and will be ignored."
|
"world_fixed_object.err.unsupported_platform:description": "World Fixed Object is not supported on Android builds and will be ignored.",
|
||||||
|
"ma_info.param_usage_ui.header": "Expressions Parameter Usage",
|
||||||
|
"ma_info.param_usage_ui.other_objects": "Other objects on this avatar",
|
||||||
|
"ma_info.param_usage_ui.free_space": "Unused parameter space ({0} bits)",
|
||||||
|
"ma_info.param_usage_ui.bits_template": "{0} ({1} bits)"
|
||||||
}
|
}
|
@ -236,5 +236,9 @@
|
|||||||
"scale_adjuster.scale": "Scale調整値",
|
"scale_adjuster.scale": "Scale調整値",
|
||||||
"scale_adjuster.adjust_children": "子オブジェクトの位置を調整",
|
"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向けビルドには対応していないため、動作しません。"
|
"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": "このアバター内の他のオブジェクト",
|
||||||
|
"ma_info.param_usage_ui.free_space": "未使用領域 ({0} 個のビット)",
|
||||||
|
"ma_info.param_usage_ui.bits_template": "{0} ({1} 個のビットを使用中)"
|
||||||
}
|
}
|
3
Editor/ParamsUsage.meta
Normal file
3
Editor/ParamsUsage.meta
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 9914a6ac6399437dbcaa252282d02beb
|
||||||
|
timeCreated: 1710222101
|
100
Editor/ParamsUsage/MAParametersIntrospection.cs
Normal file
100
Editor/ParamsUsage/MAParametersIntrospection.cs
Normal file
@ -0,0 +1,100 @@
|
|||||||
|
#region
|
||||||
|
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Collections.Immutable;
|
||||||
|
using System.Linq;
|
||||||
|
using nadena.dev.modular_avatar.core.editor.plugin;
|
||||||
|
using nadena.dev.ndmf;
|
||||||
|
using UnityEditor;
|
||||||
|
using UnityEngine;
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
namespace nadena.dev.modular_avatar.core.editor
|
||||||
|
{
|
||||||
|
[ParameterProviderFor(typeof(ModularAvatarParameters))]
|
||||||
|
internal class MAParametersIntrospection : IParameterProvider
|
||||||
|
{
|
||||||
|
private readonly ModularAvatarParameters _component;
|
||||||
|
|
||||||
|
public MAParametersIntrospection(ModularAvatarParameters parameters)
|
||||||
|
{
|
||||||
|
_component = parameters;
|
||||||
|
}
|
||||||
|
|
||||||
|
public IEnumerable<ProvidedParameter> GetSuppliedParameters(ndmf.BuildContext context = null)
|
||||||
|
{
|
||||||
|
return _component.parameters.Select(p =>
|
||||||
|
{
|
||||||
|
AnimatorControllerParameterType paramType;
|
||||||
|
bool animatorOnly = false;
|
||||||
|
|
||||||
|
switch (p.syncType)
|
||||||
|
{
|
||||||
|
case ParameterSyncType.Bool:
|
||||||
|
paramType = AnimatorControllerParameterType.Bool;
|
||||||
|
break;
|
||||||
|
case ParameterSyncType.Float:
|
||||||
|
paramType = AnimatorControllerParameterType.Float;
|
||||||
|
break;
|
||||||
|
case ParameterSyncType.Int:
|
||||||
|
paramType = AnimatorControllerParameterType.Int;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
paramType = AnimatorControllerParameterType.Float;
|
||||||
|
animatorOnly = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return new ProvidedParameter(
|
||||||
|
p.nameOrPrefix,
|
||||||
|
p.isPrefix ? ParameterNamespace.PhysBonesPrefix : ParameterNamespace.Animator,
|
||||||
|
_component, PluginDefinition.Instance, paramType)
|
||||||
|
{
|
||||||
|
IsAnimatorOnly = animatorOnly,
|
||||||
|
WantSynced = !p.localOnly,
|
||||||
|
IsHidden = p.internalParameter,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public void RemapParameters(ref ImmutableDictionary<(ParameterNamespace, string), ParameterMapping> nameMap,
|
||||||
|
ndmf.BuildContext context = null)
|
||||||
|
{
|
||||||
|
var remappings = context != null ? ParameterRenameMappings.Get(context) : null;
|
||||||
|
|
||||||
|
// TODO - internal parameter handling
|
||||||
|
foreach (var p in _component.parameters)
|
||||||
|
{
|
||||||
|
ParameterNamespace ns = p.isPrefix ? ParameterNamespace.PhysBonesPrefix : ParameterNamespace.Animator;
|
||||||
|
string remapTo = null;
|
||||||
|
if (p.internalParameter)
|
||||||
|
{
|
||||||
|
if (remappings != null)
|
||||||
|
{
|
||||||
|
remapTo = remappings.Remap(_component, ns, p.nameOrPrefix);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
remapTo = p.nameOrPrefix + "$" + GUID.Generate();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (string.IsNullOrEmpty(p.remapTo))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
remapTo = p.remapTo;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (nameMap.TryGetKey((ns, remapTo), out var existingMapping))
|
||||||
|
{
|
||||||
|
remapTo = existingMapping.Item2;
|
||||||
|
}
|
||||||
|
|
||||||
|
nameMap = nameMap.SetItem((ns, p.nameOrPrefix), new ParameterMapping(remapTo, p.internalParameter));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
3
Editor/ParamsUsage/MAParametersIntrospection.cs.meta
Normal file
3
Editor/ParamsUsage/MAParametersIntrospection.cs.meta
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: eadfd1e62f714d06a8b9f693dec21940
|
||||||
|
timeCreated: 1710229132
|
23
Editor/ParamsUsage/ModularAvatarInformation.cs
Normal file
23
Editor/ParamsUsage/ModularAvatarInformation.cs
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
#region
|
||||||
|
|
||||||
|
using UnityEngine;
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
namespace nadena.dev.modular_avatar.core.editor
|
||||||
|
{
|
||||||
|
[HelpURL("https://m-a.nadena.dev/docs/intro?lang=auto")]
|
||||||
|
internal class ModularAvatarInformation : ScriptableObject
|
||||||
|
{
|
||||||
|
internal static ModularAvatarInformation _instance;
|
||||||
|
|
||||||
|
internal static ModularAvatarInformation instance
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (_instance == null) _instance = CreateInstance<ModularAvatarInformation>();
|
||||||
|
return _instance;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
11
Editor/ParamsUsage/ModularAvatarInformation.cs.meta
Normal file
11
Editor/ParamsUsage/ModularAvatarInformation.cs.meta
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: f902feee12ad4fcbb8a975bbea565ab1
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {fileID: 2800000, guid: a8edd5bd1a0a64a40aa99cc09fb5f198, type: 3}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
75
Editor/ParamsUsage/ParamsUsage.uss
Normal file
75
Editor/ParamsUsage/ParamsUsage.uss
Normal file
@ -0,0 +1,75 @@
|
|||||||
|
Label.header {
|
||||||
|
-unity-font-style: bold;
|
||||||
|
margin-top: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#Outerbox {
|
||||||
|
margin-top: 4px;
|
||||||
|
border-top-width: 1px;
|
||||||
|
border-bottom-width: 1px;
|
||||||
|
border-left-width: 1px;
|
||||||
|
border-right-width: 1px;
|
||||||
|
border-color: black;
|
||||||
|
|
||||||
|
padding: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#root-box {
|
||||||
|
margin-bottom: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#UsageBox {
|
||||||
|
height: 16px;
|
||||||
|
flex-direction: row;
|
||||||
|
margin-bottom: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#UsageBox VisualElement {
|
||||||
|
flex-grow: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#UsageBox VisualElement.Hovering {
|
||||||
|
border-top-width: 4px;
|
||||||
|
border-bottom-width: 4px;
|
||||||
|
/*border-left-width: 4px;
|
||||||
|
border-right-width: 4px;
|
||||||
|
margin: -4px;
|
||||||
|
*/
|
||||||
|
margin-top: -4px;
|
||||||
|
margin-bottom: -4px;
|
||||||
|
|
||||||
|
border-color: black;
|
||||||
|
}
|
||||||
|
|
||||||
|
.Entry {
|
||||||
|
flex-direction: row;
|
||||||
|
}
|
||||||
|
|
||||||
|
.IconOuter {
|
||||||
|
border-top-width: 3px;
|
||||||
|
border-bottom-width: 3px;
|
||||||
|
border-left-width: 3px;
|
||||||
|
border-right-width: 3px;
|
||||||
|
border-color: grey;
|
||||||
|
|
||||||
|
padding: 1px;
|
||||||
|
margin-right: 4px;
|
||||||
|
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
|
||||||
|
height: 16px;
|
||||||
|
width: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.IconInner {
|
||||||
|
height: 100%;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.Entry.Hovering {
|
||||||
|
margin-left: -4px;
|
||||||
|
margin-right: -4px;
|
||||||
|
border-left-width: 4px;
|
||||||
|
border-right-width: 4px;
|
||||||
|
}
|
3
Editor/ParamsUsage/ParamsUsage.uss.meta
Normal file
3
Editor/ParamsUsage/ParamsUsage.uss.meta
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: e6813d571517475dbf36efb2d266003a
|
||||||
|
timeCreated: 1710399136
|
35
Editor/ParamsUsage/ParamsUsage.uxml
Normal file
35
Editor/ParamsUsage/ParamsUsage.uxml
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
<UXML xmlns:ui="UnityEngine.UIElements" xmlns:ma="nadena.dev.modular_avatar.core.editor">
|
||||||
|
<ui:VisualElement name="root-box">
|
||||||
|
<ui:Label text="ma_info.param_usage_ui.header" class="header ndmf-tr"/>
|
||||||
|
|
||||||
|
<ui:VisualElement name="Outerbox">
|
||||||
|
<ui:VisualElement name="UsageBox">
|
||||||
|
<ui:VisualElement name="OtherObjects" style="background-color: #888888; flex-grow: 1;"/>
|
||||||
|
<ui:VisualElement name="UnusedSpace" style="width: auto; background-color: #eeeeee; flex-grow: 1;"/>
|
||||||
|
</ui:VisualElement>
|
||||||
|
|
||||||
|
<ui:VisualElement name="Legend">
|
||||||
|
<ui:VisualElement class="retained">
|
||||||
|
<ui:VisualElement class="Entry" name="OtherObjects" style="display: none">
|
||||||
|
<ui:VisualElement class="IconOuter">
|
||||||
|
<ui:VisualElement class="IconInner" style="background-color: #888888"/>
|
||||||
|
</ui:VisualElement>
|
||||||
|
|
||||||
|
<ui:Label class="description" text="Other objects on this avatar (xx)"/>
|
||||||
|
</ui:VisualElement>
|
||||||
|
|
||||||
|
<ui:VisualElement class="Entry" name="UnusedSpace" style="display: none">
|
||||||
|
<ui:VisualElement class="IconOuter">
|
||||||
|
<ui:VisualElement class="IconInner" style="background-color: #eeeeee"/>
|
||||||
|
</ui:VisualElement>
|
||||||
|
|
||||||
|
<ui:Label class="description" text="Free parameter space (xx)"/>
|
||||||
|
</ui:VisualElement>
|
||||||
|
</ui:VisualElement>
|
||||||
|
|
||||||
|
</ui:VisualElement>
|
||||||
|
</ui:VisualElement>
|
||||||
|
|
||||||
|
<ma:LanguageSwitcherElement/>
|
||||||
|
</ui:VisualElement>
|
||||||
|
</UXML>
|
3
Editor/ParamsUsage/ParamsUsage.uxml.meta
Normal file
3
Editor/ParamsUsage/ParamsUsage.uxml.meta
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 0d51876a8e634298aa6d0271bb820189
|
||||||
|
timeCreated: 1710399118
|
203
Editor/ParamsUsage/ParamsUsageEditor.cs
Normal file
203
Editor/ParamsUsage/ParamsUsageEditor.cs
Normal file
@ -0,0 +1,203 @@
|
|||||||
|
#region
|
||||||
|
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using nadena.dev.ndmf;
|
||||||
|
using UnityEditor;
|
||||||
|
using UnityEngine;
|
||||||
|
using UnityEngine.UIElements;
|
||||||
|
using VRC.SDK3.Avatars.ScriptableObjects;
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
namespace nadena.dev.modular_avatar.core.editor
|
||||||
|
{
|
||||||
|
internal class ParamsUsageEditor : MAEditorBase
|
||||||
|
{
|
||||||
|
[SerializeField] private StyleSheet uss;
|
||||||
|
[SerializeField] private VisualTreeAsset uxml;
|
||||||
|
|
||||||
|
private VisualElement _root;
|
||||||
|
private VisualElement _entryTemplate;
|
||||||
|
private VisualElement _usageBoxContainer;
|
||||||
|
private VisualElement _legendContainer;
|
||||||
|
|
||||||
|
private bool _visible = false;
|
||||||
|
|
||||||
|
public bool Visible
|
||||||
|
{
|
||||||
|
get => _visible;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
if (_visible == value) return;
|
||||||
|
_visible = value;
|
||||||
|
|
||||||
|
if (_visible) Recalculate();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnEnable()
|
||||||
|
{
|
||||||
|
#if UNITY_2022_1_OR_NEWER
|
||||||
|
ObjectChangeEvents.changesPublished += OnChangesPublished;
|
||||||
|
#endif
|
||||||
|
Recalculate();
|
||||||
|
}
|
||||||
|
|
||||||
|
#if UNITY_2022_1_OR_NEWER
|
||||||
|
private void OnChangesPublished(ref ObjectChangeEventStream stream)
|
||||||
|
{
|
||||||
|
Recalculate();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnDisable()
|
||||||
|
{
|
||||||
|
ObjectChangeEvents.changesPublished -= OnChangesPublished;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
protected override VisualElement CreateInnerInspectorGUI()
|
||||||
|
{
|
||||||
|
_root = uxml.CloneTree();
|
||||||
|
_root.styleSheets.Add(uss);
|
||||||
|
Localization.L.LocalizeUIElements(_root);
|
||||||
|
|
||||||
|
_legendContainer = _root.Q<VisualElement>("Legend");
|
||||||
|
_usageBoxContainer = _root.Q<VisualElement>("UsageBox");
|
||||||
|
|
||||||
|
Recalculate();
|
||||||
|
|
||||||
|
return _root;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void OnInnerInspectorGUI()
|
||||||
|
{
|
||||||
|
// no-op
|
||||||
|
}
|
||||||
|
|
||||||
|
private static IEnumerable<Color> Colors()
|
||||||
|
{
|
||||||
|
// Spiral inwards on an HSV scale
|
||||||
|
float h_step = 0.33f;
|
||||||
|
float h_step_mult = 0.8f;
|
||||||
|
float h_step_min = 0.05f;
|
||||||
|
|
||||||
|
float v_mult = 0.98f;
|
||||||
|
|
||||||
|
float h = 0;
|
||||||
|
float s = 1;
|
||||||
|
float v = 0.9f;
|
||||||
|
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
yield return Color.HSVToRGB(h, s, v);
|
||||||
|
|
||||||
|
h = (h + h_step) % 1;
|
||||||
|
h_step = h_step_min + ((h_step - h_step_min) * h_step_mult);
|
||||||
|
v *= v_mult;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void Recalculate()
|
||||||
|
{
|
||||||
|
if (_root == null || !_visible) return;
|
||||||
|
|
||||||
|
var ctx = serializedObject.context as GameObject;
|
||||||
|
|
||||||
|
var avatarRoot = RuntimeUtil.FindAvatarTransformInParents(ctx.transform)?.gameObject;
|
||||||
|
if (ctx == null || avatarRoot == null) return;
|
||||||
|
|
||||||
|
var orderedPlugins = ParameterInfo.ForUI.GetParametersForObject(ctx)
|
||||||
|
.GroupBy(p => p.Plugin)
|
||||||
|
.Select(group => (group.Key, group.Sum(p => p.BitUsage)))
|
||||||
|
.OrderBy(group => group.Key.DisplayName)
|
||||||
|
.ToList();
|
||||||
|
|
||||||
|
var byPlugin = orderedPlugins
|
||||||
|
.Zip(Colors(), (kv, color) => (kv.Key.DisplayName, kv.Item2, kv.Key.ThemeColor ?? color))
|
||||||
|
.ToList();
|
||||||
|
|
||||||
|
int totalUsage = byPlugin.Sum(kv => kv.Item2);
|
||||||
|
|
||||||
|
int avatarTotalUsage =
|
||||||
|
ParameterInfo.ForUI.GetParametersForObject(avatarRoot).Sum(p => p.BitUsage);
|
||||||
|
|
||||||
|
int freeSpace = VRCExpressionParameters.MAX_PARAMETER_COST - avatarTotalUsage;
|
||||||
|
|
||||||
|
float avatarTotalPerc = avatarTotalUsage / (float)VRCExpressionParameters.MAX_PARAMETER_COST;
|
||||||
|
float freeSpacePerc = freeSpace / (float)VRCExpressionParameters.MAX_PARAMETER_COST;
|
||||||
|
|
||||||
|
if (avatarTotalUsage > totalUsage)
|
||||||
|
{
|
||||||
|
byPlugin.Add((Localization.S("ma_info.param_usage_ui.other_objects"), avatarTotalUsage - totalUsage,
|
||||||
|
Color.gray));
|
||||||
|
}
|
||||||
|
|
||||||
|
var bits_template = Localization.S("ma_info.param_usage_ui.bits_template");
|
||||||
|
byPlugin = byPlugin.Select((tuple, _) =>
|
||||||
|
(string.Format(bits_template, tuple.Item1, tuple.Item2), tuple.Item2, tuple.Item3)).ToList();
|
||||||
|
|
||||||
|
if (freeSpace > 0)
|
||||||
|
{
|
||||||
|
var free_space_label = Localization.S("ma_info.param_usage_ui.free_space");
|
||||||
|
byPlugin.Add((string.Format(free_space_label, freeSpace), freeSpace, Color.white));
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var child in _legendContainer.Children().ToList())
|
||||||
|
{
|
||||||
|
child.RemoveFromHierarchy();
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var child in _usageBoxContainer.Children().ToList())
|
||||||
|
{
|
||||||
|
child.RemoveFromHierarchy();
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var (label, usage, color) in byPlugin)
|
||||||
|
{
|
||||||
|
var colorBar = new VisualElement();
|
||||||
|
colorBar.style.backgroundColor = color;
|
||||||
|
colorBar.style.width =
|
||||||
|
new StyleLength(new Length(100.0f * usage / (float)VRCExpressionParameters.MAX_PARAMETER_COST,
|
||||||
|
LengthUnit.Percent));
|
||||||
|
_usageBoxContainer.Add(colorBar);
|
||||||
|
|
||||||
|
var entry = new VisualElement();
|
||||||
|
_legendContainer.Add(entry);
|
||||||
|
entry.AddToClassList("Entry");
|
||||||
|
|
||||||
|
var icon_outer = new VisualElement();
|
||||||
|
icon_outer.AddToClassList("IconOuter");
|
||||||
|
entry.Add(icon_outer);
|
||||||
|
|
||||||
|
var icon_inner = new VisualElement();
|
||||||
|
icon_inner.AddToClassList("IconInner");
|
||||||
|
icon_outer.Add(icon_inner);
|
||||||
|
icon_inner.style.backgroundColor = color;
|
||||||
|
|
||||||
|
var pluginLabel = new Label(label);
|
||||||
|
entry.Add(pluginLabel);
|
||||||
|
|
||||||
|
entry.style.borderBottomColor = color;
|
||||||
|
entry.style.borderTopColor = color;
|
||||||
|
entry.style.borderLeftColor = color;
|
||||||
|
entry.style.borderRightColor = color;
|
||||||
|
|
||||||
|
colorBar.style.borderBottomColor = color;
|
||||||
|
colorBar.style.borderTopColor = color;
|
||||||
|
colorBar.style.borderLeftColor = color;
|
||||||
|
colorBar.style.borderRightColor = color;
|
||||||
|
|
||||||
|
SetMouseHover(entry, colorBar);
|
||||||
|
SetMouseHover(colorBar, entry);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void SetMouseHover(VisualElement src, VisualElement other)
|
||||||
|
{
|
||||||
|
src.RegisterCallback<MouseEnterEvent>(ev => { other.AddToClassList("Hovering"); });
|
||||||
|
|
||||||
|
src.RegisterCallback<MouseLeaveEvent>(ev => { other.RemoveFromClassList("Hovering"); });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
13
Editor/ParamsUsage/ParamsUsageEditor.cs.meta
Normal file
13
Editor/ParamsUsage/ParamsUsageEditor.cs.meta
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: aedf0b915d844b2992b447f61bd56f54
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences:
|
||||||
|
- uss: {fileID: 7433441132597879392, guid: e6813d571517475dbf36efb2d266003a, type: 3}
|
||||||
|
- uxml: {fileID: 9197481963319205126, guid: 0d51876a8e634298aa6d0271bb820189, type: 3}
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
202
Editor/ParamsUsage/ParamsUsageUI.cs
Normal file
202
Editor/ParamsUsage/ParamsUsageUI.cs
Normal file
@ -0,0 +1,202 @@
|
|||||||
|
#region
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Reflection;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
|
using HarmonyLib;
|
||||||
|
using nadena.dev.ndmf.localization;
|
||||||
|
using UnityEditor;
|
||||||
|
using UnityEditor.UIElements;
|
||||||
|
using UnityEngine;
|
||||||
|
using UnityEngine.UIElements;
|
||||||
|
using Object = UnityEngine.Object;
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
namespace nadena.dev.modular_avatar.core.editor
|
||||||
|
{
|
||||||
|
internal class ParamsUsageUI : VisualElement
|
||||||
|
{
|
||||||
|
private static readonly Type editorElem = AccessTools.TypeByName("UnityEditor.UIElements.EditorElement");
|
||||||
|
private static readonly PropertyInfo editorElem_editor = AccessTools.Property(editorElem, "editor");
|
||||||
|
|
||||||
|
private class FoldoutState
|
||||||
|
{
|
||||||
|
public bool Visible;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static ConditionalWeakTable<VisualElement, FoldoutState> FoldoutStateHolder =
|
||||||
|
new ConditionalWeakTable<VisualElement, FoldoutState>();
|
||||||
|
|
||||||
|
private VisualElement _gameObjectEditorElement;
|
||||||
|
private Editor _parentEditor;
|
||||||
|
private Object _rawTarget;
|
||||||
|
private GameObject _target;
|
||||||
|
private ParamsUsageEditor _editor;
|
||||||
|
private FoldoutState _foldoutState;
|
||||||
|
|
||||||
|
private bool _recursing = false;
|
||||||
|
|
||||||
|
public ParamsUsageUI()
|
||||||
|
{
|
||||||
|
RegisterCallback<AttachToPanelEvent>(OnAttach);
|
||||||
|
RegisterCallback<DetachFromPanelEvent>(OnDetach);
|
||||||
|
|
||||||
|
LanguagePrefs.RegisterLanguageChangeCallback(this,
|
||||||
|
(self) => self.OnLanguageChangedCallback());
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnLanguageChangedCallback()
|
||||||
|
{
|
||||||
|
if (_editor != null)
|
||||||
|
{
|
||||||
|
BuildContent();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnDetach(DetachFromPanelEvent evt)
|
||||||
|
{
|
||||||
|
if (_recursing) return;
|
||||||
|
|
||||||
|
Clear();
|
||||||
|
|
||||||
|
if (_editor != null)
|
||||||
|
{
|
||||||
|
Object.DestroyImmediate(_editor);
|
||||||
|
_editor = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnAttach(AttachToPanelEvent evt)
|
||||||
|
{
|
||||||
|
if (_recursing) return;
|
||||||
|
|
||||||
|
Rebuild();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void Rebuild()
|
||||||
|
{
|
||||||
|
if (parent == null) return;
|
||||||
|
|
||||||
|
SetRedrawSensor();
|
||||||
|
|
||||||
|
if (_gameObjectEditorElement?.parent != parent)
|
||||||
|
{
|
||||||
|
_gameObjectEditorElement = null;
|
||||||
|
|
||||||
|
var kv = FindEditorElement();
|
||||||
|
if (kv != null)
|
||||||
|
{
|
||||||
|
var elem = kv.Value.Item1;
|
||||||
|
var index = kv.Value.Item2;
|
||||||
|
|
||||||
|
if (index != parent.Children().ToList().IndexOf(this))
|
||||||
|
{
|
||||||
|
_recursing = true;
|
||||||
|
var p = parent;
|
||||||
|
RemoveFromHierarchy();
|
||||||
|
p.Insert(index + 1, this);
|
||||||
|
_recursing = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
_gameObjectEditorElement = elem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_gameObjectEditorElement == null) return;
|
||||||
|
|
||||||
|
_parentEditor = editorElem_editor.GetValue(_gameObjectEditorElement) as Editor;
|
||||||
|
if (_parentEditor == null) return;
|
||||||
|
|
||||||
|
_rawTarget = _parentEditor.target;
|
||||||
|
_target = _rawTarget as GameObject;
|
||||||
|
|
||||||
|
if (_target == null) return;
|
||||||
|
|
||||||
|
Clear();
|
||||||
|
_redrawSensorActive = false;
|
||||||
|
BuildContent();
|
||||||
|
}
|
||||||
|
|
||||||
|
private (VisualElement, int)? FindEditorElement()
|
||||||
|
{
|
||||||
|
foreach (var (elem, index) in parent.Children().Select((e, i) => (e, i)))
|
||||||
|
{
|
||||||
|
if (elem.ClassListContains("game-object-inspector"))
|
||||||
|
{
|
||||||
|
return (elem, index);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool _redrawSensorActive = false;
|
||||||
|
|
||||||
|
private void SetRedrawSensor()
|
||||||
|
{
|
||||||
|
if (_redrawSensorActive) return;
|
||||||
|
|
||||||
|
Clear();
|
||||||
|
_redrawSensorActive = true;
|
||||||
|
Add(new IMGUIContainer(() => EditorApplication.delayCall += Rebuild));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void BuildContent()
|
||||||
|
{
|
||||||
|
Clear();
|
||||||
|
|
||||||
|
if (!FoldoutStateHolder.TryGetValue(parent, out _foldoutState))
|
||||||
|
{
|
||||||
|
_foldoutState = new FoldoutState();
|
||||||
|
FoldoutStateHolder.Add(parent, _foldoutState);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (RuntimeUtil.FindAvatarTransformInParents(_target.transform) == null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_editor = Editor.CreateEditorWithContext(new Object[] { ModularAvatarInformation.instance }, _target,
|
||||||
|
typeof(ParamsUsageEditor))
|
||||||
|
as ParamsUsageEditor;
|
||||||
|
|
||||||
|
if (_editor == null) return;
|
||||||
|
|
||||||
|
var inspectorElement = new InspectorElement(_editor);
|
||||||
|
|
||||||
|
Add(new IMGUIContainer(() =>
|
||||||
|
{
|
||||||
|
if (_gameObjectEditorElement?.parent != parent || _parentEditor == null ||
|
||||||
|
_parentEditor.target != _rawTarget)
|
||||||
|
{
|
||||||
|
EditorApplication.delayCall += Rebuild;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (Event.current.rawType)
|
||||||
|
{
|
||||||
|
case EventType.Repaint:
|
||||||
|
case EventType.MouseMove:
|
||||||
|
case EventType.Layout:
|
||||||
|
break;
|
||||||
|
case EventType.MouseDrag:
|
||||||
|
case EventType.DragUpdated:
|
||||||
|
case EventType.DragPerform:
|
||||||
|
case EventType.DragExited:
|
||||||
|
return;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
_foldoutState.Visible = EditorGUILayout.InspectorTitlebar(_foldoutState.Visible, _editor);
|
||||||
|
inspectorElement.style.display = _foldoutState.Visible ? DisplayStyle.Flex : DisplayStyle.None;
|
||||||
|
_editor.Visible = _foldoutState.Visible;
|
||||||
|
}));
|
||||||
|
_editor.Visible = _foldoutState.Visible;
|
||||||
|
Add(inspectorElement);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
3
Editor/ParamsUsage/ParamsUsageUI.cs.meta
Normal file
3
Editor/ParamsUsage/ParamsUsageUI.cs.meta
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 18364f2754ed43c3baba0f1e18ac03cd
|
||||||
|
timeCreated: 1710226452
|
7
Editor/ParamsUsage/assembly-info.cs
Normal file
7
Editor/ParamsUsage/assembly-info.cs
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
#region
|
||||||
|
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
[assembly: InternalsVisibleTo("nadena.dev.modular-avatar.harmony-patches")]
|
3
Editor/ParamsUsage/assembly-info.cs.meta
Normal file
3
Editor/ParamsUsage/assembly-info.cs.meta
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 6899d9fe550c492d887ce9e02d2a758b
|
||||||
|
timeCreated: 1710404112
|
@ -0,0 +1,31 @@
|
|||||||
|
{
|
||||||
|
"name": "nadena.dev.modular-avatar.param-introspection",
|
||||||
|
"rootNamespace": "",
|
||||||
|
"references": [
|
||||||
|
"GUID:fc900867c0f47cd49b6e2ae4ef907300",
|
||||||
|
"GUID:5ce33783346c3124990afbe7b0390a06",
|
||||||
|
"GUID:62ced99b048af7f4d8dfe4bed8373d76",
|
||||||
|
"GUID:5718fb738711cd34ea54e9553040911d",
|
||||||
|
"GUID:b906909fcc54f634db50f2cad0f988d9",
|
||||||
|
"GUID:901e56b065a857d4483a77f8cae73588"
|
||||||
|
],
|
||||||
|
"includePlatforms": [
|
||||||
|
"Editor"
|
||||||
|
],
|
||||||
|
"excludePlatforms": [],
|
||||||
|
"allowUnsafeCode": false,
|
||||||
|
"overrideReferences": false,
|
||||||
|
"precompiledReferences": [],
|
||||||
|
"autoReferenced": true,
|
||||||
|
"defineConstraints": [
|
||||||
|
"MODULAR_AVATAR_VRCSDK_AVATAR"
|
||||||
|
],
|
||||||
|
"versionDefines": [
|
||||||
|
{
|
||||||
|
"name": "com.vrchat.avatars",
|
||||||
|
"expression": "(0,999)",
|
||||||
|
"define": "MODULAR_AVATAR_VRCSDK_AVATAR"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"noEngineReferences": false
|
||||||
|
}
|
@ -0,0 +1,7 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: f906ad1132cf10c48a65d14ae0809457
|
||||||
|
AssemblyDefinitionImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
@ -1,12 +1,19 @@
|
|||||||
using System;
|
#region
|
||||||
|
|
||||||
|
using System;
|
||||||
using nadena.dev.modular_avatar.animation;
|
using nadena.dev.modular_avatar.animation;
|
||||||
|
using nadena.dev.modular_avatar.core.ArmatureAwase;
|
||||||
|
using nadena.dev.modular_avatar.core.editor.plugin;
|
||||||
using nadena.dev.modular_avatar.editor.ErrorReporting;
|
using nadena.dev.modular_avatar.editor.ErrorReporting;
|
||||||
using nadena.dev.ndmf;
|
using nadena.dev.ndmf;
|
||||||
using nadena.dev.ndmf.fluent;
|
using nadena.dev.ndmf.fluent;
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
|
using Object = UnityEngine.Object;
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
[assembly: ExportsPlugin(
|
[assembly: ExportsPlugin(
|
||||||
typeof(nadena.dev.modular_avatar.core.editor.plugin.PluginDefinition)
|
typeof(PluginDefinition)
|
||||||
)]
|
)]
|
||||||
|
|
||||||
namespace nadena.dev.modular_avatar.core.editor.plugin
|
namespace nadena.dev.modular_avatar.core.editor.plugin
|
||||||
@ -17,6 +24,9 @@ namespace nadena.dev.modular_avatar.core.editor.plugin
|
|||||||
public override string DisplayName => "Modular Avatar";
|
public override string DisplayName => "Modular Avatar";
|
||||||
public override Texture2D LogoTexture => LogoDisplay.LOGO_ASSET;
|
public override Texture2D LogoTexture => LogoDisplay.LOGO_ASSET;
|
||||||
|
|
||||||
|
// 00a0e9
|
||||||
|
public override Color? ThemeColor => new Color(0x00 / 255f, 0xa0 / 255f, 0xe9 / 255f, 1);
|
||||||
|
|
||||||
protected override void OnUnhandledException(Exception e)
|
protected override void OnUnhandledException(Exception e)
|
||||||
{
|
{
|
||||||
BuildReport.LogException(e);
|
BuildReport.LogException(e);
|
||||||
@ -82,11 +92,11 @@ namespace nadena.dev.modular_avatar.core.editor.plugin
|
|||||||
{
|
{
|
||||||
foreach (var component in ctx.AvatarRootTransform.GetComponentsInChildren<AvatarTagComponent>(true))
|
foreach (var component in ctx.AvatarRootTransform.GetComponentsInChildren<AvatarTagComponent>(true))
|
||||||
{
|
{
|
||||||
UnityEngine.Object.DestroyImmediate(component);
|
Object.DestroyImmediate(component);
|
||||||
}
|
}
|
||||||
foreach (var component in ctx.AvatarRootTransform.GetComponentsInChildren<ArmatureAwase.MAMoveIndependently>(true))
|
foreach (var component in ctx.AvatarRootTransform.GetComponentsInChildren<MAMoveIndependently>(true))
|
||||||
{
|
{
|
||||||
UnityEngine.Object.DestroyImmediate(component);
|
Object.DestroyImmediate(component);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
#if MA_VRCSDK3_AVATARS
|
#if MA_VRCSDK3_AVATARS
|
||||||
@ -140,7 +150,7 @@ namespace nadena.dev.modular_avatar.core.editor.plugin
|
|||||||
{
|
{
|
||||||
foreach (var component in obj.GetComponentsInChildren<AvatarTagComponent>(true))
|
foreach (var component in obj.GetComponentsInChildren<AvatarTagComponent>(true))
|
||||||
{
|
{
|
||||||
UnityEngine.Object.DestroyImmediate(component);
|
Object.DestroyImmediate(component);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
#if MA_VRCSDK3_AVATARS
|
#if MA_VRCSDK3_AVATARS
|
||||||
|
|
||||||
|
#region
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Collections.Immutable;
|
using System.Collections.Immutable;
|
||||||
@ -18,8 +20,33 @@ using Object = UnityEngine.Object;
|
|||||||
|
|
||||||
using UnityObject = UnityEngine.Object;
|
using UnityObject = UnityEngine.Object;
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
namespace nadena.dev.modular_avatar.core.editor
|
namespace nadena.dev.modular_avatar.core.editor
|
||||||
{
|
{
|
||||||
|
internal class ParameterRenameMappings
|
||||||
|
{
|
||||||
|
public static ParameterRenameMappings Get(ndmf.BuildContext ctx)
|
||||||
|
{
|
||||||
|
return ctx.GetState<ParameterRenameMappings>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Dictionary<(ModularAvatarParameters, ParameterNamespace, string), string> Remappings =
|
||||||
|
new Dictionary<(ModularAvatarParameters, ParameterNamespace, string), string>();
|
||||||
|
|
||||||
|
private int internalParamIndex;
|
||||||
|
|
||||||
|
public string Remap(ModularAvatarParameters p, ParameterNamespace ns, string s)
|
||||||
|
{
|
||||||
|
var tuple = (p, ns, s);
|
||||||
|
|
||||||
|
if (Remappings.TryGetValue(tuple, out var mapping)) return mapping;
|
||||||
|
|
||||||
|
return s + "$$Internal_" + internalParamIndex++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
internal class DefaultValues
|
internal class DefaultValues
|
||||||
{
|
{
|
||||||
public ImmutableDictionary<string, float> InitialValueOverrides;
|
public ImmutableDictionary<string, float> InitialValueOverrides;
|
||||||
@ -609,6 +636,8 @@ namespace nadena.dev.modular_avatar.core.editor
|
|||||||
ref ImmutableDictionary<string, string> prefixRemaps
|
ref ImmutableDictionary<string, string> prefixRemaps
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
|
var remapper = ParameterRenameMappings.Get(_context.PluginBuildContext);
|
||||||
|
|
||||||
ImmutableDictionary<string, ParameterInfo> parameterInfos = ImmutableDictionary<string, ParameterInfo>.Empty;
|
ImmutableDictionary<string, ParameterInfo> parameterInfos = ImmutableDictionary<string, ParameterInfo>.Empty;
|
||||||
|
|
||||||
foreach (var param in p.parameters)
|
foreach (var param in p.parameters)
|
||||||
@ -618,7 +647,9 @@ namespace nadena.dev.modular_avatar.core.editor
|
|||||||
var remapTo = param.remapTo;
|
var remapTo = param.remapTo;
|
||||||
if (param.internalParameter)
|
if (param.internalParameter)
|
||||||
{
|
{
|
||||||
remapTo = param.nameOrPrefix + "$$Internal_" + internalParamIndex++;
|
remapTo = remapper.Remap(p,
|
||||||
|
param.isPrefix ? ParameterNamespace.PhysBonesPrefix : ParameterNamespace.Animator,
|
||||||
|
param.nameOrPrefix);
|
||||||
}
|
}
|
||||||
else if (string.IsNullOrWhiteSpace(remapTo))
|
else if (string.IsNullOrWhiteSpace(remapTo))
|
||||||
{
|
{
|
||||||
|
@ -7,3 +7,4 @@ using System.Runtime.CompilerServices;
|
|||||||
[assembly: InternalsVisibleTo("net.fushizen.xdress")]
|
[assembly: InternalsVisibleTo("net.fushizen.xdress")]
|
||||||
[assembly: InternalsVisibleTo("net.fushizen.xdress.editor")]
|
[assembly: InternalsVisibleTo("net.fushizen.xdress.editor")]
|
||||||
[assembly: InternalsVisibleTo("nadena.dev.modular-avatar.harmony-patches")]
|
[assembly: InternalsVisibleTo("nadena.dev.modular-avatar.harmony-patches")]
|
||||||
|
[assembly: InternalsVisibleTo("nadena.dev.modular-avatar.param-introspection")]
|
@ -1,10 +1,12 @@
|
|||||||
{
|
{
|
||||||
"name": "nadena.dev.modular-avatar.core.editor",
|
"name": "nadena.dev.modular-avatar.core.editor",
|
||||||
|
"rootNamespace": "",
|
||||||
"references": [
|
"references": [
|
||||||
"nadena.dev.modular-avatar.core",
|
"nadena.dev.modular-avatar.core",
|
||||||
"VRC.SDK3A",
|
"VRC.SDK3A",
|
||||||
"VRC.SDKBase",
|
"VRC.SDKBase",
|
||||||
"nadena.dev.ndmf"
|
"nadena.dev.ndmf",
|
||||||
|
"nadena.dev.ndmf.vrchat"
|
||||||
],
|
],
|
||||||
"includePlatforms": [
|
"includePlatforms": [
|
||||||
"Editor"
|
"Editor"
|
||||||
|
@ -9,3 +9,4 @@ using System.Runtime.CompilerServices;
|
|||||||
[assembly: InternalsVisibleTo("net.fushizen.xdress.editor")]
|
[assembly: InternalsVisibleTo("net.fushizen.xdress.editor")]
|
||||||
[assembly: InternalsVisibleTo("Tests")]
|
[assembly: InternalsVisibleTo("Tests")]
|
||||||
[assembly: InternalsVisibleTo("nadena.dev.modular-avatar.harmony-patches")]
|
[assembly: InternalsVisibleTo("nadena.dev.modular-avatar.harmony-patches")]
|
||||||
|
[assembly: InternalsVisibleTo("nadena.dev.modular-avatar.param-introspection")]
|
@ -16,6 +16,6 @@
|
|||||||
},
|
},
|
||||||
"vpmDependencies": {
|
"vpmDependencies": {
|
||||||
"com.vrchat.avatars": ">=3.4.0",
|
"com.vrchat.avatars": ">=3.4.0",
|
||||||
"nadena.dev.ndmf": ">=1.3.6 <2.0.0-a"
|
"nadena.dev.ndmf": ">=1.4.0-rc.0 <2.0.0-a"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user