mirror of
https://github.com/bdunderscore/modular-avatar.git
synced 2025-04-25 05:49:00 +08:00
support disabling different parameters based on attached actions
This commit is contained in:
parent
ed1ae08d04
commit
64d831672a
@ -1,12 +1,9 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Runtime.Serialization;
|
using System.Runtime.Serialization;
|
||||||
using Codice.CM.Common.Tree.Partial;
|
|
||||||
using nadena.dev.modular_avatar.core.menu;
|
using nadena.dev.modular_avatar.core.menu;
|
||||||
using NUnit.Framework;
|
|
||||||
using UnityEditor;
|
using UnityEditor;
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
using UnityEngine.UIElements;
|
|
||||||
using VRC.SDK3.Avatars.ScriptableObjects;
|
using VRC.SDK3.Avatars.ScriptableObjects;
|
||||||
using static nadena.dev.modular_avatar.core.editor.Localization;
|
using static nadena.dev.modular_avatar.core.editor.Localization;
|
||||||
|
|
||||||
@ -54,11 +51,23 @@ namespace nadena.dev.modular_avatar.core.editor
|
|||||||
|
|
||||||
private bool _hasActions;
|
private bool _hasActions;
|
||||||
|
|
||||||
private bool HasActions()
|
private bool HasActions(TargetParameter? p = null)
|
||||||
{
|
{
|
||||||
return _toggleGroup != null && _obj.targetObjects.Any(o =>
|
return _toggleGroup != null && _obj.targetObjects.Any(o =>
|
||||||
o is ModularAvatarMenuItem c && c.GetComponent<MenuAction>() != null
|
{
|
||||||
);
|
if (!(o is ModularAvatarMenuItem c)) return false;
|
||||||
|
if (p.HasValue)
|
||||||
|
{
|
||||||
|
foreach (var component in c.GetComponents<MenuAction>())
|
||||||
|
{
|
||||||
|
if (component.BindsParameter(p.Value)) return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public MenuItemCoreGUI(SerializedObject obj, Action redraw)
|
public MenuItemCoreGUI(SerializedObject obj, Action redraw)
|
||||||
@ -162,7 +171,7 @@ namespace nadena.dev.modular_avatar.core.editor
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_parameterGUI.DoGUI(!_hasActions);
|
_parameterGUI.DoGUI(!_hasActions || !HasActions(TargetParameter.BaseParameter));
|
||||||
|
|
||||||
EditorGUILayout.EndVertical();
|
EditorGUILayout.EndVertical();
|
||||||
|
|
||||||
@ -286,7 +295,8 @@ namespace nadena.dev.modular_avatar.core.editor
|
|||||||
{
|
{
|
||||||
EnsureParameterCount(1);
|
EnsureParameterCount(1);
|
||||||
|
|
||||||
_subParams[0].DoGUI(true, G("menuitem.param.rotation"));
|
_subParams[0].DoGUI(!_hasActions || !HasActions(TargetParameter.RadialParam),
|
||||||
|
G("menuitem.param.rotation"));
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -298,8 +308,10 @@ namespace nadena.dev.modular_avatar.core.editor
|
|||||||
EditorGUILayout.LabelField("Parameters", EditorStyles.boldLabel);
|
EditorGUILayout.LabelField("Parameters", EditorStyles.boldLabel);
|
||||||
EditorGUILayout.Space(2);
|
EditorGUILayout.Space(2);
|
||||||
|
|
||||||
_subParams[0].DoGUI(true, G("menuitem.param.horizontal"));
|
_subParams[0].DoGUI(!_hasActions || !HasActions(TargetParameter.Horizontal),
|
||||||
_subParams[1].DoGUI(true, G("menuitem.param.vertical"));
|
G("menuitem.param.horizontal"));
|
||||||
|
_subParams[1].DoGUI(!_hasActions || !HasActions(TargetParameter.Vertical),
|
||||||
|
G("menuitem.param.vertical"));
|
||||||
|
|
||||||
DoFourAxisLabels(false);
|
DoFourAxisLabels(false);
|
||||||
|
|
||||||
@ -396,10 +408,10 @@ namespace nadena.dev.modular_avatar.core.editor
|
|||||||
center.xMin += blockWidth;
|
center.xMin += blockWidth;
|
||||||
center.xMax -= blockWidth;
|
center.xMax -= blockWidth;
|
||||||
|
|
||||||
SingleLabel(0, up);
|
SingleLabel(0, up, TargetParameter.Up);
|
||||||
SingleLabel(1, right);
|
SingleLabel(1, right, TargetParameter.Right);
|
||||||
SingleLabel(2, down);
|
SingleLabel(2, down, TargetParameter.Down);
|
||||||
SingleLabel(3, left);
|
SingleLabel(3, left, TargetParameter.Left);
|
||||||
|
|
||||||
var rect_param_l = center;
|
var rect_param_l = center;
|
||||||
rect_param_l.yMin = rect_param_l.yMax - EditorGUIUtility.singleLineHeight;
|
rect_param_l.yMin = rect_param_l.yMax - EditorGUIUtility.singleLineHeight;
|
||||||
@ -409,7 +421,7 @@ namespace nadena.dev.modular_avatar.core.editor
|
|||||||
if (showParams) CenterLabel(rect_param_l, G("menuitem.prop.parameter"), EditorStyles.label);
|
if (showParams) CenterLabel(rect_param_l, G("menuitem.prop.parameter"), EditorStyles.label);
|
||||||
CenterLabel(rect_name_l, G("menuitem.prop.label"), EditorStyles.label);
|
CenterLabel(rect_name_l, G("menuitem.prop.label"), EditorStyles.label);
|
||||||
|
|
||||||
void SingleLabel(int index, Rect block)
|
void SingleLabel(int index, Rect block, TargetParameter parameter)
|
||||||
{
|
{
|
||||||
var prop_name = _labels[index].FindPropertyRelative(nameof(VRCExpressionsMenu.Control.Label.name));
|
var prop_name = _labels[index].FindPropertyRelative(nameof(VRCExpressionsMenu.Control.Label.name));
|
||||||
var prop_icon = _labels[index].FindPropertyRelative(nameof(VRCExpressionsMenu.Control.Label.icon));
|
var prop_icon = _labels[index].FindPropertyRelative(nameof(VRCExpressionsMenu.Control.Label.icon));
|
||||||
@ -426,7 +438,7 @@ namespace nadena.dev.modular_avatar.core.editor
|
|||||||
EditorGUI.PropertyField(rect_name, prop_name, GUIContent.none);
|
EditorGUI.PropertyField(rect_name, prop_name, GUIContent.none);
|
||||||
if (showParams)
|
if (showParams)
|
||||||
{
|
{
|
||||||
_subParams[index].DoGUI(rect_param, true, GUIContent.none);
|
_subParams[index].DoGUI(rect_param, !_hasActions || !HasActions(parameter), GUIContent.none);
|
||||||
}
|
}
|
||||||
|
|
||||||
var tex = prop_icon.objectReferenceValue as Texture;
|
var tex = prop_icon.objectReferenceValue as Texture;
|
||||||
|
@ -23,7 +23,7 @@ namespace nadena.dev.modular_avatar.core.editor
|
|||||||
_redraw = redraw;
|
_redraw = redraw;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void DoGUI(bool enabled = true, GUIContent label = null)
|
public void DoGUI(bool enabled, GUIContent label = null)
|
||||||
{
|
{
|
||||||
DoGUI(EditorGUILayout.GetControlRect(
|
DoGUI(EditorGUILayout.GetControlRect(
|
||||||
true,
|
true,
|
||||||
@ -31,7 +31,7 @@ namespace nadena.dev.modular_avatar.core.editor
|
|||||||
), enabled, label);
|
), enabled, label);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void DoGUI(Rect rect, bool enabled = true, GUIContent label = null)
|
public void DoGUI(Rect rect, bool enabled, GUIContent label = null)
|
||||||
{
|
{
|
||||||
label = label ?? G("menuitem.prop.parameter");
|
label = label ?? G("menuitem.prop.parameter");
|
||||||
|
|
||||||
|
@ -315,11 +315,11 @@ namespace nadena.dev.modular_avatar.core.editor
|
|||||||
void MergeCurves(
|
void MergeCurves(
|
||||||
IDictionary<MenuCurveBinding, (Component, AnimationCurve)> curves,
|
IDictionary<MenuCurveBinding, (Component, AnimationCurve)> curves,
|
||||||
ModularAvatarMenuItem item,
|
ModularAvatarMenuItem item,
|
||||||
Func<MenuAction, IDictionary<MenuCurveBinding, AnimationCurve>> getCurves,
|
Func<SwitchedMenuAction, IDictionary<MenuCurveBinding, AnimationCurve>> getCurves,
|
||||||
bool ignoreDuplicates
|
bool ignoreDuplicates
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
foreach (var action in item.GetComponents<MenuAction>())
|
foreach (var action in item.GetComponents<SwitchedMenuAction>())
|
||||||
{
|
{
|
||||||
var newCurves = getCurves(action);
|
var newCurves = getCurves(action);
|
||||||
|
|
||||||
|
@ -7,62 +7,8 @@ using Object = System.Object;
|
|||||||
|
|
||||||
namespace nadena.dev.modular_avatar.core
|
namespace nadena.dev.modular_avatar.core
|
||||||
{
|
{
|
||||||
public sealed class MenuCurveBinding
|
|
||||||
{
|
|
||||||
public readonly GameObject target;
|
|
||||||
public readonly Type type;
|
|
||||||
public readonly string property;
|
|
||||||
|
|
||||||
public MenuCurveBinding(GameObject target, Type type, string property)
|
|
||||||
{
|
|
||||||
this.target = target;
|
|
||||||
this.type = type;
|
|
||||||
this.property = property;
|
|
||||||
}
|
|
||||||
|
|
||||||
private bool Equals(MenuCurveBinding other)
|
|
||||||
{
|
|
||||||
return target == other.target && type == other.type && property == other.property;
|
|
||||||
}
|
|
||||||
|
|
||||||
public override bool Equals(object obj)
|
|
||||||
{
|
|
||||||
if (ReferenceEquals(null, obj)) return false;
|
|
||||||
if (ReferenceEquals(this, obj)) return true;
|
|
||||||
if (obj.GetType() != this.GetType()) return false;
|
|
||||||
return Equals((MenuCurveBinding) obj);
|
|
||||||
}
|
|
||||||
|
|
||||||
public override int GetHashCode()
|
|
||||||
{
|
|
||||||
unchecked
|
|
||||||
{
|
|
||||||
var hashCode = (target != null ? target.GetHashCode() : 0);
|
|
||||||
hashCode = (hashCode * 397) ^ (type != null ? type.GetHashCode() : 0);
|
|
||||||
hashCode = (hashCode * 397) ^ (property != null ? property.GetHashCode() : 0);
|
|
||||||
return hashCode;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public interface MenuAction
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Returns the curves applied when this action is active
|
|
||||||
/// </summary>
|
|
||||||
/// <returns></returns>
|
|
||||||
ImmutableDictionary<MenuCurveBinding, AnimationCurve> GetCurves();
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Returns the curves applied when this action is inactive (and no other actions override).
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="isDefault">True if this action is part of the default toggle option.</param>
|
|
||||||
/// <returns></returns>
|
|
||||||
ImmutableDictionary<MenuCurveBinding, AnimationCurve> GetInactiveCurves(bool isDefault);
|
|
||||||
}
|
|
||||||
|
|
||||||
[RequireComponent(typeof(ModularAvatarMenuItem))]
|
[RequireComponent(typeof(ModularAvatarMenuItem))]
|
||||||
public class ActionToggleObject : AvatarTagComponent, MenuAction
|
public class ActionToggleObject : AvatarTagComponent, SwitchedMenuAction
|
||||||
{
|
{
|
||||||
[Serializable]
|
[Serializable]
|
||||||
public class ObjectEntry
|
public class ObjectEntry
|
||||||
@ -102,5 +48,10 @@ namespace nadena.dev.modular_avatar.core
|
|||||||
}
|
}
|
||||||
).ToImmutableDictionary();
|
).ToImmutableDictionary();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public bool BindsParameter(TargetParameter parameter)
|
||||||
|
{
|
||||||
|
return parameter == TargetParameter.BaseParameter;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -0,0 +1,102 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Immutable;
|
||||||
|
using UnityEngine;
|
||||||
|
|
||||||
|
namespace nadena.dev.modular_avatar.core
|
||||||
|
{
|
||||||
|
public interface MenuAction
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Returns whether this action binds to the given parameter.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="parameter"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
bool BindsParameter(TargetParameter parameter);
|
||||||
|
}
|
||||||
|
|
||||||
|
public interface SwitchedMenuAction : MenuAction
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Returns the curves applied when this action is active
|
||||||
|
/// </summary>
|
||||||
|
/// <returns></returns>
|
||||||
|
ImmutableDictionary<MenuCurveBinding, AnimationCurve> GetCurves();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns the curves applied when this action is inactive (and no other actions override).
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="isDefault">True if this action is part of the default toggle option.</param>
|
||||||
|
/// <returns></returns>
|
||||||
|
ImmutableDictionary<MenuCurveBinding, AnimationCurve> GetInactiveCurves(bool isDefault);
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum TargetParameter
|
||||||
|
{
|
||||||
|
BaseParameter,
|
||||||
|
RadialParam,
|
||||||
|
Horizontal,
|
||||||
|
Vertical,
|
||||||
|
Up,
|
||||||
|
Right,
|
||||||
|
Down,
|
||||||
|
Left
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class TargetParameterExtension
|
||||||
|
{
|
||||||
|
public static int Index(this TargetParameter p)
|
||||||
|
{
|
||||||
|
switch (p)
|
||||||
|
{
|
||||||
|
case TargetParameter.BaseParameter:
|
||||||
|
return -1;
|
||||||
|
case TargetParameter.RadialParam: return 0;
|
||||||
|
case TargetParameter.Horizontal: return 0;
|
||||||
|
case TargetParameter.Vertical: return 1;
|
||||||
|
case TargetParameter.Up: return 0;
|
||||||
|
case TargetParameter.Right: return 1;
|
||||||
|
case TargetParameter.Down: return 2;
|
||||||
|
case TargetParameter.Left: return 3;
|
||||||
|
default: throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public sealed class MenuCurveBinding
|
||||||
|
{
|
||||||
|
public readonly GameObject target;
|
||||||
|
public readonly Type type;
|
||||||
|
public readonly string property;
|
||||||
|
|
||||||
|
public MenuCurveBinding(GameObject target, Type type, string property)
|
||||||
|
{
|
||||||
|
this.target = target;
|
||||||
|
this.type = type;
|
||||||
|
this.property = property;
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool Equals(MenuCurveBinding other)
|
||||||
|
{
|
||||||
|
return target == other.target && type == other.type && property == other.property;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool Equals(object obj)
|
||||||
|
{
|
||||||
|
if (ReferenceEquals(null, obj)) return false;
|
||||||
|
if (ReferenceEquals(this, obj)) return true;
|
||||||
|
if (obj.GetType() != this.GetType()) return false;
|
||||||
|
return Equals((MenuCurveBinding) obj);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override int GetHashCode()
|
||||||
|
{
|
||||||
|
unchecked
|
||||||
|
{
|
||||||
|
var hashCode = (target != null ? target.GetHashCode() : 0);
|
||||||
|
hashCode = (hashCode * 397) ^ (type != null ? type.GetHashCode() : 0);
|
||||||
|
hashCode = (hashCode * 397) ^ (property != null ? property.GetHashCode() : 0);
|
||||||
|
return hashCode;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,3 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 33005b045768474d8ae6f789aa03361b
|
||||||
|
timeCreated: 1677595006
|
Loading…
x
Reference in New Issue
Block a user