mirror of
https://github.com/bdunderscore/modular-avatar.git
synced 2025-03-09 23:34:56 +08:00
feat: Menu Item automatic values (#1098)
This commit is contained in:
parent
c63128095e
commit
0ee291076f
@ -54,6 +54,7 @@ namespace nadena.dev.modular_avatar.core.editor
|
||||
private readonly SerializedProperty _prop_isSynced;
|
||||
private readonly SerializedProperty _prop_isSaved;
|
||||
private readonly SerializedProperty _prop_isDefault;
|
||||
private readonly SerializedProperty _prop_automaticValue;
|
||||
|
||||
public bool AlwaysExpandContents = false;
|
||||
public bool ExpandContents = false;
|
||||
@ -105,6 +106,7 @@ namespace nadena.dev.modular_avatar.core.editor
|
||||
_prop_isSynced = obj.FindProperty(nameof(ModularAvatarMenuItem.isSynced));
|
||||
_prop_isSaved = obj.FindProperty(nameof(ModularAvatarMenuItem.isSaved));
|
||||
_prop_isDefault = obj.FindProperty(nameof(ModularAvatarMenuItem.isDefault));
|
||||
_prop_automaticValue = obj.FindProperty(nameof(ModularAvatarMenuItem.automaticValue));
|
||||
|
||||
_previewGUI = new MenuPreviewGUI(redraw);
|
||||
}
|
||||
@ -180,6 +182,7 @@ namespace nadena.dev.modular_avatar.core.editor
|
||||
_prop_isSynced = _control.FindPropertyRelative(nameof(ModularAvatarMenuItem.isSynced));
|
||||
_prop_isSaved = _control.FindPropertyRelative(nameof(ModularAvatarMenuItem.isSaved));
|
||||
_prop_isDefault = _control.FindPropertyRelative(nameof(ModularAvatarMenuItem.isDefault));
|
||||
_prop_automaticValue = null;
|
||||
|
||||
_prop_submenuSource = null;
|
||||
_prop_otherObjSource = null;
|
||||
@ -225,7 +228,7 @@ namespace nadena.dev.modular_avatar.core.editor
|
||||
|
||||
EditorGUILayout.PropertyField(_texture, G("menuitem.prop.icon"));
|
||||
EditorGUILayout.PropertyField(_type, G("menuitem.prop.type"));
|
||||
EditorGUILayout.PropertyField(_value, G("menuitem.prop.value"));
|
||||
DoValueField();
|
||||
|
||||
_parameterGUI.DoGUI(true);
|
||||
|
||||
@ -462,6 +465,8 @@ namespace nadena.dev.modular_avatar.core.editor
|
||||
if (knownParameter != null && knownParameter.Source is ModularAvatarMenuItem)
|
||||
isDefaultByKnownParam = null;
|
||||
|
||||
if (_prop_automaticValue?.boolValue == true) isDefaultByKnownParam = null;
|
||||
|
||||
Object controller = knownParameter?.Source;
|
||||
|
||||
// If we can't figure out what to reference the parameter names to, or if they're controlled by something
|
||||
@ -549,6 +554,55 @@ namespace nadena.dev.modular_avatar.core.editor
|
||||
EditorGUILayout.EndHorizontal();
|
||||
}
|
||||
|
||||
private void DoValueField()
|
||||
{
|
||||
var value_label = G("menuitem.prop.value");
|
||||
var auto_label = G("menuitem.prop.automatic_value");
|
||||
|
||||
if (_prop_automaticValue == null)
|
||||
{
|
||||
EditorGUILayout.PropertyField(_value, value_label);
|
||||
return;
|
||||
}
|
||||
|
||||
var toggleSize = EditorStyles.toggle.CalcSize(new GUIContent());
|
||||
var autoLabelSize = EditorStyles.label.CalcSize(auto_label);
|
||||
|
||||
var style = EditorStyles.numberField;
|
||||
var rect = EditorGUILayout.GetControlRect(true, EditorGUIUtility.singleLineHeight, style);
|
||||
|
||||
var valueRect = rect;
|
||||
valueRect.xMax -= toggleSize.x + autoLabelSize.x + 4;
|
||||
|
||||
var autoRect = rect;
|
||||
autoRect.xMin = valueRect.xMax + 4;
|
||||
|
||||
var suppressValue = _prop_automaticValue.boolValue || _prop_automaticValue.hasMultipleDifferentValues;
|
||||
|
||||
using (new EditorGUI.DisabledScope(suppressValue))
|
||||
{
|
||||
if (suppressValue)
|
||||
{
|
||||
EditorGUI.TextField(valueRect, value_label, "", style);
|
||||
}
|
||||
else
|
||||
{
|
||||
EditorGUI.BeginChangeCheck();
|
||||
EditorGUI.PropertyField(valueRect, _value, value_label);
|
||||
if (EditorGUI.EndChangeCheck()) _prop_automaticValue.boolValue = false;
|
||||
}
|
||||
}
|
||||
|
||||
EditorGUI.BeginProperty(autoRect, auto_label, _prop_automaticValue);
|
||||
EditorGUI.BeginChangeCheck();
|
||||
|
||||
EditorGUI.showMixedValue = _prop_automaticValue.hasMultipleDifferentValues;
|
||||
var autoValue = EditorGUI.ToggleLeft(autoRect, auto_label, _prop_automaticValue.boolValue);
|
||||
|
||||
if (EditorGUI.EndChangeCheck()) _prop_automaticValue.boolValue = autoValue;
|
||||
EditorGUI.EndProperty();
|
||||
}
|
||||
|
||||
private List<ModularAvatarMenuItem> FindSiblingMenuItems(SerializedObject serializedObject)
|
||||
{
|
||||
if (serializedObject == null || serializedObject.isEditingMultipleObjects) return null;
|
||||
|
@ -187,6 +187,8 @@
|
||||
"menuitem.prop.type.tooltip": "The type of this item",
|
||||
"menuitem.prop.value": "Value",
|
||||
"menuitem.prop.value.tooltip": "The value to set the parameter to when this control is used",
|
||||
"menuitem.prop.automatic_value": "Auto",
|
||||
"menuitem.prop.automatic_value.tooltip": "Automatically set this control to a unique value",
|
||||
"menuitem.prop.parameter": "Parameter",
|
||||
"menuitem.prop.label": "Label",
|
||||
"menuitem.prop.submenu_asset": "Submenu Asset",
|
||||
|
@ -197,6 +197,8 @@
|
||||
"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": "横パラメーター名",
|
||||
|
@ -63,6 +63,17 @@ namespace nadena.dev.modular_avatar.core.editor
|
||||
_computeContext.Observe(mami, c => (c.Control?.parameter, c.Control?.type, c.Control?.value, c.isDefault));
|
||||
|
||||
var mami_condition = ParameterAssignerPass.AssignMenuItemParameter(mami, _simulationInitialStates);
|
||||
|
||||
if (mami_condition != null &&
|
||||
ForceMenuItems.TryGetValue(mami_condition.Parameter, out var forcedMenuItem))
|
||||
{
|
||||
var enable = forcedMenuItem == mami;
|
||||
mami_condition.InitialValue = 0.5f;
|
||||
mami_condition.ParameterValueLo = enable ? 0 : 999f;
|
||||
mami_condition.ParameterValueHi = 1000;
|
||||
mami_condition.IsConstant = true;
|
||||
}
|
||||
|
||||
if (mami_condition != null) conditions.Add(mami_condition);
|
||||
}
|
||||
|
||||
|
@ -20,6 +20,9 @@ namespace nadena.dev.modular_avatar.core.editor
|
||||
private Dictionary<string, float> _simulationInitialStates;
|
||||
|
||||
public ImmutableDictionary<string, float> ForcePropertyOverrides { get; set; } = ImmutableDictionary<string, float>.Empty;
|
||||
|
||||
public ImmutableDictionary<string, ModularAvatarMenuItem> ForceMenuItems { get; set; } =
|
||||
ImmutableDictionary<string, ModularAvatarMenuItem>.Empty;
|
||||
|
||||
public ReactiveObjectAnalyzer(ndmf.BuildContext context)
|
||||
{
|
||||
@ -46,8 +49,9 @@ namespace nadena.dev.modular_avatar.core.editor
|
||||
{
|
||||
var mami = obj?.GetComponent<ModularAvatarMenuItem>();
|
||||
if (mami == null) return null;
|
||||
|
||||
return ParameterAssignerPass.AssignMenuItemParameter(mami, _simulationInitialStates)?.Parameter;
|
||||
|
||||
return ParameterAssignerPass.AssignMenuItemParameter(mami, _simulationInitialStates, ForceMenuItems)
|
||||
?.Parameter;
|
||||
}
|
||||
|
||||
public struct AnalysisResult
|
||||
@ -68,6 +72,8 @@ namespace nadena.dev.modular_avatar.core.editor
|
||||
var analysis = new ReactiveObjectAnalyzer(ctx);
|
||||
analysis.ForcePropertyOverrides = ctx.Observe(ROSimulator.PropertyOverrides, a=>a, (a,b) => false)
|
||||
?? ImmutableDictionary<string, float>.Empty;
|
||||
analysis.ForceMenuItems = ctx.Observe(ROSimulator.MenuItemOverrides, a => a, (a, b) => false)
|
||||
?? ImmutableDictionary<string, ModularAvatarMenuItem>.Empty;
|
||||
return analysis.Analyze(root);
|
||||
});
|
||||
}
|
||||
@ -101,7 +107,7 @@ namespace nadena.dev.modular_avatar.core.editor
|
||||
FindMaterialSetters(shapes, root);
|
||||
|
||||
ApplyInitialStateOverrides(shapes);
|
||||
AnalyzeConstants(shapes);
|
||||
AnalyzeConstants(shapes);
|
||||
ResolveToggleInitialStates(shapes);
|
||||
PreprocessShapes(shapes, out result.InitialStates, out result.DeletedShapes);
|
||||
result.Shapes = shapes;
|
||||
|
@ -75,7 +75,7 @@ namespace nadena.dev.modular_avatar.core.editor
|
||||
{
|
||||
if (condition.IsConstant) continue;
|
||||
|
||||
if (!initialValues.ContainsKey(condition.Parameter))
|
||||
if (!initialValues.ContainsKey(condition.Parameter) && condition.InitialValue > -999f)
|
||||
initialValues[condition.Parameter] = condition.InitialValue;
|
||||
}
|
||||
}
|
||||
|
@ -47,11 +47,14 @@ namespace nadena.dev.modular_avatar.core.editor
|
||||
|
||||
var paramIndex = 0;
|
||||
|
||||
var declaredParams = context.AvatarDescriptor.expressionParameters.parameters.Select(p => p.name)
|
||||
.ToHashSet();
|
||||
var declaredParams = context.AvatarDescriptor.expressionParameters.parameters
|
||||
.GroupBy(p => p.name).Select(l => l.First())
|
||||
.ToDictionary(p => p.name);
|
||||
|
||||
Dictionary<string, VRCExpressionParameters.Parameter> newParameters = new();
|
||||
Dictionary<string, int> nextParamValue = new();
|
||||
|
||||
Dictionary<string, List<ModularAvatarMenuItem>> _mamiByParam = new();
|
||||
foreach (var mami in context.AvatarRootTransform.GetComponentsInChildren<ModularAvatarMenuItem>(true))
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(mami.Control?.parameter?.name))
|
||||
@ -64,51 +67,97 @@ namespace nadena.dev.modular_avatar.core.editor
|
||||
name = $"__MA/AutoParam/{mami.gameObject.name}${paramIndex++}"
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
var paramName = mami.Control.parameter.name;
|
||||
|
||||
if (!declaredParams.Contains(paramName))
|
||||
if (!_mamiByParam.TryGetValue(paramName, out var mamiList))
|
||||
{
|
||||
newParameters.TryGetValue(paramName, out var existingNewParam);
|
||||
var wantedType = existingNewParam?.valueType ?? VRCExpressionParameters.ValueType.Bool;
|
||||
mamiList = new List<ModularAvatarMenuItem>();
|
||||
_mamiByParam[paramName] = mamiList;
|
||||
}
|
||||
|
||||
if (wantedType != VRCExpressionParameters.ValueType.Float &&
|
||||
(mami.Control.value > 1.01 || mami.Control.value < -0.01))
|
||||
wantedType = VRCExpressionParameters.ValueType.Int;
|
||||
mamiList.Add(mami);
|
||||
}
|
||||
|
||||
if (Mathf.Abs(Mathf.Round(mami.Control.value) - mami.Control.value) > 0.01f)
|
||||
wantedType = VRCExpressionParameters.ValueType.Float;
|
||||
foreach (var (paramName, list) in _mamiByParam)
|
||||
{
|
||||
// Assign automatic values first
|
||||
float defaultValue;
|
||||
if (declaredParams.TryGetValue(paramName, out var p))
|
||||
{
|
||||
defaultValue = p.defaultValue;
|
||||
}
|
||||
else
|
||||
{
|
||||
defaultValue = list.FirstOrDefault(m => m.isDefault && !m.automaticValue)?.Control?.value ?? 0;
|
||||
|
||||
if (existingNewParam == null)
|
||||
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
|
||||
defaultValue = 1;
|
||||
}
|
||||
|
||||
HashSet<int> usedValues = new();
|
||||
usedValues.Add((int)defaultValue);
|
||||
|
||||
foreach (var item in list)
|
||||
if (!item.automaticValue && Mathf.Abs(item.Control.value - Mathf.Round(item.Control.value)) < 0.01f)
|
||||
usedValues.Add(Mathf.RoundToInt(item.Control.value));
|
||||
|
||||
var nextValue = 1;
|
||||
|
||||
var canBeBool = true;
|
||||
var canBeInt = true;
|
||||
var isSaved = true;
|
||||
var isSynced = true;
|
||||
|
||||
foreach (var mami in list)
|
||||
{
|
||||
if (mami.automaticValue)
|
||||
{
|
||||
existingNewParam = new VRCExpressionParameters.Parameter
|
||||
if (mami.isDefault)
|
||||
{
|
||||
name = paramName,
|
||||
valueType = wantedType,
|
||||
saved = mami.isSaved,
|
||||
defaultValue = -1,
|
||||
networkSynced = mami.isSynced
|
||||
};
|
||||
newParameters[paramName] = existingNewParam;
|
||||
}
|
||||
else
|
||||
{
|
||||
existingNewParam.valueType = wantedType;
|
||||
mami.Control.value = defaultValue;
|
||||
}
|
||||
else
|
||||
{
|
||||
while (usedValues.Contains(nextValue)) nextValue++;
|
||||
|
||||
mami.Control.value = nextValue;
|
||||
usedValues.Add(nextValue);
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: warn on inconsistent configuration
|
||||
existingNewParam.saved = existingNewParam.saved || mami.isSaved;
|
||||
existingNewParam.networkSynced = existingNewParam.networkSynced || mami.isSynced;
|
||||
existingNewParam.defaultValue = mami.isDefault ? mami.Control.value : existingNewParam.defaultValue;
|
||||
if (Mathf.Abs(mami.Control.value - Mathf.Round(mami.Control.value)) > 0.01f)
|
||||
canBeInt = false;
|
||||
else
|
||||
canBeBool &= mami.Control.value is >= 0 and <= 1;
|
||||
|
||||
isSaved &= mami.isSaved;
|
||||
isSynced &= mami.isSynced;
|
||||
}
|
||||
|
||||
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,
|
||||
saved = isSaved,
|
||||
defaultValue = defaultValue,
|
||||
networkSynced = isSynced
|
||||
};
|
||||
newParameters[paramName] = newParam;
|
||||
}
|
||||
}
|
||||
|
||||
if (newParameters.Count > 0)
|
||||
{
|
||||
foreach (var p in newParameters)
|
||||
if (p.Value.defaultValue < 0)
|
||||
p.Value.defaultValue = 0;
|
||||
|
||||
var expParams = context.AvatarDescriptor.expressionParameters;
|
||||
if (!context.IsTemporaryAsset(expParams))
|
||||
{
|
||||
@ -120,15 +169,22 @@ namespace nadena.dev.modular_avatar.core.editor
|
||||
}
|
||||
}
|
||||
|
||||
internal static ControlCondition AssignMenuItemParameter(ModularAvatarMenuItem mami, Dictionary<string, float> simulationInitialStates = null)
|
||||
internal static ControlCondition AssignMenuItemParameter(
|
||||
ModularAvatarMenuItem mami,
|
||||
Dictionary<string, float> simulationInitialStates = null,
|
||||
IDictionary<string, ModularAvatarMenuItem> isDefaultOverrides = null)
|
||||
{
|
||||
var paramName = mami?.Control?.parameter?.name;
|
||||
if (mami?.Control != null && simulationInitialStates != null && ShouldAssignParametersToMami(mami))
|
||||
{
|
||||
paramName = "___AutoProp/" + mami.Control?.parameter?.name;
|
||||
if (paramName == "___AutoProp/") paramName += mami.GetInstanceID();
|
||||
paramName = mami.Control?.parameter?.name;
|
||||
if (string.IsNullOrEmpty(paramName)) paramName = "___AutoProp/" + mami.GetInstanceID();
|
||||
|
||||
if (mami.isDefault)
|
||||
var isDefault = mami.isDefault;
|
||||
if (isDefaultOverrides?.TryGetValue(paramName, out var target) == true)
|
||||
isDefault = ReferenceEquals(mami, target);
|
||||
|
||||
if (isDefault)
|
||||
{
|
||||
simulationInitialStates[paramName] = mami.Control.value;
|
||||
} else if (!simulationInitialStates.ContainsKey(paramName))
|
||||
@ -144,7 +200,10 @@ namespace nadena.dev.modular_avatar.core.editor
|
||||
Parameter = paramName,
|
||||
DebugName = mami.gameObject.name,
|
||||
IsConstant = false,
|
||||
InitialValue = mami.isDefault ? mami.Control.value : -999, // TODO
|
||||
// Note: This slightly odd-looking value is key to making the Auto checkbox work for editor previews;
|
||||
// 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,
|
||||
DebugReference = mami,
|
||||
|
@ -15,6 +15,7 @@ namespace nadena.dev.modular_avatar.core.editor.Simulator
|
||||
internal class ROSimulator : EditorWindow, IHasCustomMenu
|
||||
{
|
||||
public static PublishedValue<ImmutableDictionary<string, float>> PropertyOverrides = new(null);
|
||||
public static PublishedValue<ImmutableDictionary<string, ModularAvatarMenuItem>> MenuItemOverrides = new(null);
|
||||
|
||||
internal static string ROOT_PATH = "Packages/nadena.dev.modular-avatar/Editor/ReactiveObjects/Simulator/";
|
||||
private static string USS = ROOT_PATH + "ROSimulator.uss";
|
||||
@ -64,6 +65,7 @@ namespace nadena.dev.modular_avatar.core.editor.Simulator
|
||||
private void OnEnable()
|
||||
{
|
||||
PropertyOverrides.Value = ImmutableDictionary<string, float>.Empty;
|
||||
MenuItemOverrides.Value = ImmutableDictionary<string, ModularAvatarMenuItem>.Empty;
|
||||
EditorApplication.delayCall += LoadUI;
|
||||
Selection.selectionChanged += SelectionChanged;
|
||||
is_enabled = true;
|
||||
@ -79,6 +81,7 @@ namespace nadena.dev.modular_avatar.core.editor.Simulator
|
||||
EditorApplication.delayCall += () =>
|
||||
{
|
||||
PropertyOverrides.Value = null;
|
||||
MenuItemOverrides.Value = null;
|
||||
};
|
||||
}
|
||||
|
||||
@ -106,6 +109,25 @@ namespace nadena.dev.modular_avatar.core.editor.Simulator
|
||||
|
||||
EditorApplication.delayCall += RefreshUI;
|
||||
}
|
||||
|
||||
private void UpdateMenuItemOverride(string prop, ModularAvatarMenuItem item, bool? value)
|
||||
{
|
||||
if (value == null)
|
||||
{
|
||||
MenuItemOverrides.Value = MenuItemOverrides.Value.Remove(prop);
|
||||
}
|
||||
else if (value.Value)
|
||||
{
|
||||
MenuItemOverrides.Value = MenuItemOverrides.Value.SetItem(prop, item);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (MenuItemOverrides.Value.TryGetValue(prop, out var existing) && ReferenceEquals(existing, item))
|
||||
MenuItemOverrides.Value = MenuItemOverrides.Value.SetItem(prop, null);
|
||||
}
|
||||
|
||||
EditorApplication.delayCall += RefreshUI;
|
||||
}
|
||||
|
||||
private void UpdatePropertyOverride(string prop, bool? value)
|
||||
{
|
||||
@ -209,6 +231,7 @@ namespace nadena.dev.modular_avatar.core.editor.Simulator
|
||||
|
||||
var analysis = new ReactiveObjectAnalyzer(_lastComputeContext);
|
||||
analysis.ForcePropertyOverrides = PropertyOverrides.Value;
|
||||
analysis.ForceMenuItems = MenuItemOverrides.Value;
|
||||
var result = analysis.Analyze(avatar.gameObject);
|
||||
|
||||
SetThisObjectOverrides(analysis);
|
||||
@ -227,11 +250,38 @@ namespace nadena.dev.modular_avatar.core.editor.Simulator
|
||||
private void SetThisObjectOverrides(ReactiveObjectAnalyzer analysis)
|
||||
{
|
||||
BindOverrideToParameter("this-obj-override", analysis.GetGameObjectStateProperty(currentSelection), 1);
|
||||
BindOverrideToParameter("this-menu-override", analysis.GetMenuItemProperty(currentSelection),
|
||||
currentSelection.GetComponent<ModularAvatarMenuItem>()?.Control?.value ?? 1
|
||||
);
|
||||
currentSelection.TryGetComponent<ModularAvatarMenuItem>(out var mami);
|
||||
BindOverrideToMenuItem("this-menu-override", mami);
|
||||
}
|
||||
|
||||
private void BindOverrideToMenuItem(string overrideElemName, ModularAvatarMenuItem mami)
|
||||
{
|
||||
var elem = e_debugInfo.Q<VisualElement>(overrideElemName);
|
||||
var soc = elem.Q<StateOverrideController>();
|
||||
|
||||
if (mami == null)
|
||||
{
|
||||
elem.style.display = DisplayStyle.None;
|
||||
return;
|
||||
}
|
||||
|
||||
var prop = ParameterAssignerPass.AssignMenuItemParameter(mami)?.Parameter;
|
||||
if (prop == null)
|
||||
{
|
||||
elem.style.display = DisplayStyle.None;
|
||||
return;
|
||||
}
|
||||
|
||||
elem.style.display = DisplayStyle.Flex;
|
||||
|
||||
if (MenuItemOverrides.Value.TryGetValue(prop, out var overrideValue))
|
||||
soc.SetWithoutNotify(ReferenceEquals(mami, overrideValue));
|
||||
else
|
||||
soc.SetWithoutNotify(null);
|
||||
|
||||
soc.OnStateOverrideChanged += value => { UpdateMenuItemOverride(prop, mami, value); };
|
||||
}
|
||||
|
||||
private void BindOverrideToParameter(string overrideElemName, string property, float targetValue)
|
||||
{
|
||||
var elem = e_debugInfo.Q<VisualElement>(overrideElemName);
|
||||
@ -460,9 +510,24 @@ namespace nadena.dev.modular_avatar.core.editor.Simulator
|
||||
{
|
||||
targetValue = Mathf.Round((condition.ParameterValueLo + condition.ParameterValueHi) / 2);
|
||||
}
|
||||
|
||||
soc.OnStateOverrideChanged += value => UpdatePropertyOverride(prop, value, targetValue);
|
||||
|
||||
|
||||
if (condition.DebugReference is ModularAvatarMenuItem mami)
|
||||
{
|
||||
bool? menuOverride = null;
|
||||
|
||||
if (MenuItemOverrides.Value.TryGetValue(prop, out var target))
|
||||
{
|
||||
menuOverride = ReferenceEquals(mami, target);
|
||||
soc.SetWithoutNotify(menuOverride);
|
||||
}
|
||||
|
||||
soc.OnStateOverrideChanged += value => { UpdateMenuItemOverride(prop, mami, value); };
|
||||
}
|
||||
else
|
||||
{
|
||||
soc.OnStateOverrideChanged += value => UpdatePropertyOverride(prop, value, targetValue);
|
||||
}
|
||||
|
||||
var active = condition.InitiallyActive;
|
||||
var active_label = active ? "active" : "inactive";
|
||||
active_label = "ro_sim.state." + active_label;
|
||||
|
@ -1,6 +1,5 @@
|
||||
#if MA_VRCSDK3_AVATARS
|
||||
|
||||
using System;
|
||||
using System.Linq;
|
||||
using nadena.dev.modular_avatar.core.menu;
|
||||
using UnityEngine;
|
||||
@ -43,6 +42,13 @@ namespace nadena.dev.modular_avatar.core
|
||||
/// </summary>
|
||||
public bool isDefault;
|
||||
|
||||
/// <summary>
|
||||
/// If true, the value for this toggle or button menu item will be automatically selected.
|
||||
/// Typically, this will be zero for the default menu item, then subsequent menu items will be allocated
|
||||
/// sequentially in hierarchy order.
|
||||
/// </summary>
|
||||
public bool automaticValue;
|
||||
|
||||
private void Reset()
|
||||
{
|
||||
Control = new VRCExpressionsMenu.Control();
|
||||
@ -51,6 +57,7 @@ namespace nadena.dev.modular_avatar.core
|
||||
isSaved = true;
|
||||
isSynced = true;
|
||||
isDefault = false;
|
||||
automaticValue = true;
|
||||
|
||||
MenuSource = SubmenuSource.Children;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user