diff --git a/CHANGELOG-PRERELEASE.md b/CHANGELOG-PRERELEASE.md index bd642e9d..090fc202 100644 --- a/CHANGELOG-PRERELEASE.md +++ b/CHANGELOG-PRERELEASE.md @@ -8,12 +8,15 @@ The format is based on [Keep a Changelog]. ## [Unreleased] ### Added +- Regex mode for OSC Parameters in Asset Description `#1351` ### Changed ### Deprecated ### Removed +- Prefix, Suffix, and Contains mode for OSC Parameters in Asset Description `#1351` + - Please use regex mode instead ### Fixed diff --git a/CHANGELOG.md b/CHANGELOG.md index 926b0064..1f564d6b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -66,7 +66,7 @@ The format is based on [Keep a Changelog]. - However, in Unity 2020 and later, BlendShape manipulation load is mostly proportional to the number of moving vertices. - This means that increasing the number of vertices in a mesh which has BlendShapes does not increase the load of BlendShape manipulation much. - Therefore, we decided to automatically merge such meshes. -- Improved OSC Gimmick Support `#1306` +- Improved OSC Gimmick Support `#1306` `#1351` - We added two information for OSC Gimmick in Asset Description. - By defining parameters read / written by OSC Gimmick, your OSC Gimmick no longer breaks. - Automatically Merge Material Slot `#1334` diff --git a/Editor/AssetDescription.cs b/Editor/AssetDescription.cs index f8c3764d..39f11ad3 100644 --- a/Editor/AssetDescription.cs +++ b/Editor/AssetDescription.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Text.RegularExpressions; using nadena.dev.ndmf.localization; using UnityEditor; using UnityEngine; @@ -60,8 +61,51 @@ internal class AssetDescription : ScriptableObject class AssetDescriptionData { public HashSet meaninglessComponents = new(); - public HashSet parametersReadByExternalTools = new(); - public HashSet parametersChangedByExternalTools = new(); + public OscParameterInfo parametersReadByExternalTools = OscParameterInfo.New(); + public OscParameterInfo parametersChangedByExternalTools = OscParameterInfo.New(); + } + + internal struct OscParameterInfo + { + public HashSet ExactMatch; + public List RegexMatch; + + public static OscParameterInfo New() + { + return new OscParameterInfo + { + ExactMatch = new HashSet(), + RegexMatch = new List(), + }; + } + + public void Add(OscParameter parameter, AssetDescription desc) + { + if (parameter.name == "") return; + switch (parameter.matchMode) + { + case OscParameter.MatchMode.Exact: + ExactMatch.Add(parameter.name); + break; + case OscParameter.MatchMode.Regex: + try + { + _ = new Regex($"{parameter.name}", RegexOptions.CultureInvariant | RegexOptions.Compiled); + var regex = new Regex($"^(?:{parameter.name})$", RegexOptions.CultureInvariant | RegexOptions.Compiled); + RegexMatch.Add(regex); + } + catch (Exception e) + { + Debug.LogException( + new ArgumentException( + $"Invalid regex: {parameter.name} in asset description {desc.name}", e), desc); + } + + break; + default: + throw new ArgumentOutOfRangeException(); + } + } } static AssetDescriptionData LoadData() @@ -73,13 +117,12 @@ static AssetDescriptionData LoadData() if (GetMonoScriptFromGuid(component.guid, component.fileID) is MonoScript monoScript) data.meaninglessComponents.Add(monoScript.GetClass()); - data.parametersReadByExternalTools.UnionWith(description.parametersReadByExternalTools); - data.parametersChangedByExternalTools.UnionWith(description.parametersChangedByExternalTools); + foreach (var parameter in description.parametersReadByExternalTools) + data.parametersReadByExternalTools.Add(parameter, description); + foreach (var parameter in description.parametersChangedByExternalTools) + data.parametersChangedByExternalTools.Add(parameter, description); } - data.parametersReadByExternalTools.RemoveWhere(x => x.name == ""); - data.parametersChangedByExternalTools.RemoveWhere(x => x.name == ""); - return data; } @@ -95,8 +138,8 @@ private static IEnumerable GetAllAssetDescriptions() public static void Reload() => _data = LoadData(); public static HashSet GetMeaninglessComponents() => Data.meaninglessComponents; - public static HashSet GetParametersReadByExternalTools() => Data.parametersReadByExternalTools; - public static HashSet GetParametersChangedByExternalTools() => Data.parametersChangedByExternalTools; + public static OscParameterInfo GetParametersReadByExternalTools() => Data.parametersReadByExternalTools; + public static OscParameterInfo GetParametersChangedByExternalTools() => Data.parametersChangedByExternalTools; private static Object GetMonoScriptFromGuid(string guid, ulong fileid) { @@ -246,9 +289,7 @@ public struct OscParameter : IEquatable public enum MatchMode { Exact, - Prefix, - Suffix, - Contains, + Regex, } public bool Equals(OscParameter other) => name == other.name && matchMode == other.matchMode; @@ -278,6 +319,20 @@ public override void OnGUI(Rect position, SerializedProperty property, GUIConten else width = rect.width / 2 - 0.5f; + var color = GUI.color; + if (matchModeProperty.enumValueIndex == (int)OscParameter.MatchMode.Regex) + { + try + { + _ = new Regex($"{nameProperty.stringValue}", RegexOptions.CultureInvariant | RegexOptions.Compiled); + _ = new Regex($"^(?:{nameProperty.stringValue})$", RegexOptions.CultureInvariant | RegexOptions.Compiled); + } + catch + { + GUI.color = Color.red; + } + } + text = rect with { width = rect.width - width - 1 }; popup = rect with { x = rect.xMax - width, width = width }; @@ -285,6 +340,8 @@ public override void OnGUI(Rect position, SerializedProperty property, GUIConten var newName = EditorGUI.TextField(text, nameProperty.stringValue); if (EditorGUI.EndChangeCheck()) nameProperty.stringValue = newName; + + GUI.color = color; EditorGUI.BeginChangeCheck(); var newMatchMode = (OscParameter.MatchMode)EditorGUI.EnumPopup(popup, (OscParameter.MatchMode)matchModeProperty.enumValueIndex); diff --git a/Editor/Processors/TraceAndOptimize/ComponentDependencyCollector.cs b/Editor/Processors/TraceAndOptimize/ComponentDependencyCollector.cs index af3529d2..8ddb76e3 100644 --- a/Editor/Processors/TraceAndOptimize/ComponentDependencyCollector.cs +++ b/Editor/Processors/TraceAndOptimize/ComponentDependencyCollector.cs @@ -136,36 +136,12 @@ private static Predicate GetRootAnimatorParameters(GameObject rootGameOb // OSC and other External Tools Parameters var externalParameters = AssetDescription.GetParametersReadByExternalTools(); - var prefixes = new HashSet(); - var suffixes = new HashSet(); - var substrings = new HashSet(); - foreach (var externalParameter in externalParameters) - { - switch (externalParameter.matchMode) - { - case AssetDescription.OscParameter.MatchMode.Exact: - parameters.Add(externalParameter.name); - break; - case AssetDescription.OscParameter.MatchMode.Prefix: - prefixes.Add(externalParameter.name); - break; - case AssetDescription.OscParameter.MatchMode.Suffix: - suffixes.Add(externalParameter.name); - break; - case AssetDescription.OscParameter.MatchMode.Contains: - substrings.Add(externalParameter.name); - break; - default: - throw new ArgumentOutOfRangeException(); - } - } + parameters.UnionWith(externalParameters.ExactMatch); return parameter => { return parameters.Contains(parameter) || - prefixes.Any(prefix => parameter.StartsWith(prefix, StringComparison.Ordinal)) || - suffixes.Any(suffix => parameter.EndsWith(suffix, StringComparison.Ordinal)) || - substrings.Any(substring => parameter.Contains(substring, StringComparison.Ordinal)); + externalParameters.RegexMatch.Any(regex => regex.IsMatch(parameter)); }; }