fix: parent parameters can override child menu item default value

This commit is contained in:
nekobako 2024-09-13 02:56:31 +09:00
parent 3648348184
commit 0b2c8e7ac7
6 changed files with 107 additions and 59 deletions

View File

@ -88,7 +88,7 @@ namespace nadena.dev.modular_avatar.core.editor
IsAnimatorOnly = animatorOnly,
WantSynced = !p.localOnly,
IsHidden = p.internalParameter,
DefaultValue = p.defaultValue
DefaultValue = p.HasDefaultValue ? p.defaultValue : null
};
});
}

View File

@ -62,7 +62,7 @@ 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);
var mami_condition = ParameterAssignerPass.AssignMenuItemParameter(mami, _simulationInitialStates, context: _computeContext);
if (mami_condition != null &&
ForceMenuItems.TryGetValue(mami_condition.Parameter, out var forcedMenuItem))

View File

@ -61,7 +61,9 @@ namespace nadena.dev.modular_avatar.core.editor
var (paramName, value) = _context.Observe(mami, m => (m.Control.parameter.name, m.Control.value));
if (TryGetRegisteredParam(mami, paramName, out var providedParameter))
if (!_context.Observe(mami, m => m.automaticValue)
&& TryGetRegisteredParam(mami, paramName, out var providedParameter)
&& providedParameter.DefaultValue != null)
{
var defaultValue = providedParameter.DefaultValue ?? 0;
return Mathf.Abs(defaultValue - value) < 0.01f;

View File

@ -1,6 +1,7 @@
using System.Collections.Generic;
using System.Linq;
using nadena.dev.ndmf;
using nadena.dev.ndmf.preview;
using UnityEngine;
using VRC.SDK3.Avatars.ScriptableObjects;
@ -177,6 +178,7 @@ namespace nadena.dev.modular_avatar.core.editor
ModularAvatarMenuItem mami,
Dictionary<string, float> simulationInitialStates = null,
IDictionary<string, ModularAvatarMenuItem> isDefaultOverrides = null,
ComputeContext context = null,
bool? forceSimulation = null
)
{
@ -207,6 +209,10 @@ namespace nadena.dev.modular_avatar.core.editor
if (string.IsNullOrWhiteSpace(paramName)) return null;
var isEnabledForPreview = context != null
? new MenuItemPreviewCondition(context).IsEnabledForPreview(mami)
: mami.isDefault;
return new ControlCondition
{
Parameter = paramName,
@ -215,7 +221,7 @@ namespace nadena.dev.modular_avatar.core.editor
// 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,
InitialValue = isEnabledForPreview ? mami.Control.value : -999,
ParameterValueLo = mami.Control.value - 0.005f,
ParameterValueHi = mami.Control.value + 0.005f,
DebugReference = mami,

View File

@ -122,13 +122,6 @@ namespace nadena.dev.modular_avatar.core.editor
public void MergeChild(ParameterInfo info)
{
MergeCommon(info);
if (!ResolvedParameter.HasDefaultValue && info.ResolvedParameter.HasDefaultValue)
{
ResolvedParameter.defaultValue = info.ResolvedParameter.defaultValue;
ResolvedParameter.hasExplicitDefaultValue = info.ResolvedParameter.hasExplicitDefaultValue;
ResolvedParameter.m_overrideAnimatorDefaults = info.ResolvedParameter.m_overrideAnimatorDefaults;
}
}
void MergeCommon(ParameterInfo info)
@ -138,10 +131,27 @@ namespace nadena.dev.modular_avatar.core.editor
ResolvedParameter.syncType = info.ResolvedParameter.syncType;
} else if (ResolvedParameter.syncType != info.ResolvedParameter.syncType && info.ResolvedParameter.syncType != ParameterSyncType.NotSynced)
{
TypeConflict = true;
ConflictingSyncTypes = ConflictingSyncTypes
.Add(ResolvedParameter.syncType)
.Add(info.ResolvedParameter.syncType);
if (TypeSources.All(x => x is ModularAvatarMenuItem) && info.TypeSources.All(x => x is ModularAvatarMenuItem))
{
if (ResolvedParameter.syncType == ParameterSyncType.Bool || info.ResolvedParameter.syncType == ParameterSyncType.Float)
{
ResolvedParameter.syncType = info.ResolvedParameter.syncType;
}
}
else
{
TypeConflict = true;
ConflictingSyncTypes = ConflictingSyncTypes
.Add(ResolvedParameter.syncType)
.Add(info.ResolvedParameter.syncType);
}
}
if (!ResolvedParameter.HasDefaultValue && info.ResolvedParameter.HasDefaultValue)
{
ResolvedParameter.defaultValue = info.ResolvedParameter.defaultValue;
ResolvedParameter.hasExplicitDefaultValue = info.ResolvedParameter.hasExplicitDefaultValue;
ResolvedParameter.m_overrideAnimatorDefaults = info.ResolvedParameter.m_overrideAnimatorDefaults;
}
TypeSources.AddRange(info.TypeSources);
@ -317,19 +327,24 @@ namespace nadena.dev.modular_avatar.core.editor
)
{
var paramInfo = ndmf.ParameterInfo.ForContext(_context.PluginBuildContext);
ImmutableDictionary<string, ParameterInfo> rv = ImmutableDictionary<string, ParameterInfo>.Empty;
var p = obj.GetComponent<ModularAvatarParameters>();
if (p != null)
{
rv = BuildReport.ReportingObject(p, () => CollectParameters(p, paramInfo.GetParameterRemappingsAt(p, true)));
}
foreach (var merger in obj.GetComponents<ModularAvatarMergeAnimator>())
var pInfos = obj.TryGetComponent<ModularAvatarParameters>(out var p)
? BuildReport.ReportingObject(p, () => CollectParameters(p, paramInfo.GetParameterRemappingsAt(p, true)))
: Array.Empty<ParameterInfo>();
var mInfos = obj.TryGetComponent<ModularAvatarMenuItem>(out var m)
? BuildReport.ReportingObject(m, () => CollectParameters(m, paramInfo.GetParameterRemappingsAt(m, true)))
: Array.Empty<ParameterInfo>();
var rv = ImmutableDictionary<string, ParameterInfo>.Empty;
foreach (var info in Enumerable.Concat(pInfos, mInfos))
{
if (merger.deleteAttachedAnimator)
if (rv.TryGetValue(info.ResolvedParameter.nameOrPrefix, out var priorInfo))
{
break;
priorInfo.MergeSibling(info);
}
else
{
rv = rv.SetItem(info.ResolvedParameter.nameOrPrefix, info);
}
}
@ -417,27 +432,6 @@ namespace nadena.dev.modular_avatar.core.editor
break;
}
case ModularAvatarMenuItem menuItem:
{
var remaps = paramInfo.GetParameterRemappingsAt(obj);
if (menuItem.Control.parameter?.name != null &&
remaps.TryGetValue((ParameterNamespace.Animator, menuItem.Control.parameter.name), out var newVal))
{
menuItem.Control.parameter.name = newVal.ParameterName;
}
foreach (var subParam in menuItem.Control.subParameters ??
Array.Empty<VRCExpressionsMenu.Control.Parameter>())
{
if (subParam?.name != null && remaps.TryGetValue((ParameterNamespace.Animator, subParam.name), out var subNewVal))
{
subParam.name = subNewVal.ParameterName;
}
}
break;
}
}
});
}
@ -710,14 +704,10 @@ namespace nadena.dev.modular_avatar.core.editor
if (dirty) t.conditions = conditions;
}
private ImmutableDictionary<string, ParameterInfo> CollectParameters(ModularAvatarParameters p,
private IEnumerable<ParameterInfo> CollectParameters(ModularAvatarParameters p,
ImmutableDictionary<(ParameterNamespace, string), ParameterMapping> remaps
)
{
var remapper = ParameterRenameMappings.Get(_context.PluginBuildContext);
ImmutableDictionary<string, ParameterInfo> parameterInfos = ImmutableDictionary<string, ParameterInfo>.Empty;
foreach (var param in p.parameters)
{
if (param.isPrefix) continue;
@ -746,18 +736,59 @@ namespace nadena.dev.modular_avatar.core.editor
{
info.DefaultSources.Add(p);
}
if (parameterInfos.TryGetValue(remapTo, out var existing))
yield return info;
}
}
private IEnumerable<ParameterInfo> CollectParameters(ModularAvatarMenuItem m,
ImmutableDictionary<(ParameterNamespace, string), ParameterMapping> remaps
)
{
if (!string.IsNullOrEmpty(m.Control?.parameter?.name)
&& remaps.TryGetValue((ParameterNamespace.Animator, m.Control.parameter.name), out var mapping))
{
m.Control.parameter.name = mapping.ParameterName;
}
foreach (var subParam in m.Control?.subParameters ?? Array.Empty<VRCExpressionsMenu.Control.Parameter>())
{
if (!string.IsNullOrEmpty(subParam?.name)
&& remaps.TryGetValue((ParameterNamespace.Animator, subParam.name), out var subParamMapping))
{
existing.MergeSibling(info);
}
else
{
parameterInfos = parameterInfos.SetItem(remapTo, info);
subParam.name = subParamMapping.ParameterName;
}
}
return parameterInfos;
if (m.automaticValue) yield break;
if (string.IsNullOrWhiteSpace(m.Control?.parameter?.name)) yield break;
if (!ParameterAssignerPass.ShouldAssignParametersToMami(m)) yield break;
var info = new ParameterInfo()
{
ResolvedParameter = new()
{
nameOrPrefix = m.Control.parameter?.name,
remapTo = m.Control.parameter?.name,
syncType = m.ParameterSyncType,
saved = m.isSaved,
localOnly = !m.isSynced,
defaultValue = m.isDefault ? m.Control.value : 0,
hasExplicitDefaultValue = m.isDefault,
},
};
if (info.ResolvedParameter.syncType != ParameterSyncType.NotSynced)
{
info.TypeSources.Add(m);
}
if (info.ResolvedParameter.HasDefaultValue)
{
info.DefaultSources.Add(m);
}
yield return info;
}
// This is generic to simplify remapping parameter driver fields, some of which are 'object's.

View File

@ -181,6 +181,15 @@ namespace nadena.dev.modular_avatar.core
VRCExpressionParameters.ValueType.Float => AnimatorControllerParameterType.Float,
_ => 0,
};
internal ParameterSyncType ParameterSyncType
=> ExpressionParametersValueType switch
{
VRCExpressionParameters.ValueType.Bool => ParameterSyncType.Bool,
VRCExpressionParameters.ValueType.Int => ParameterSyncType.Int,
VRCExpressionParameters.ValueType.Float => ParameterSyncType.Float,
_ => 0,
};
}
}