From 19a69230516a965e8a01fce9fbb640c245b926bc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E3=82=89=E3=81=84=E3=81=A1=E3=81=A1=E3=82=83=E3=82=93?= Date: Sat, 3 Dec 2022 13:32:40 +0900 Subject: [PATCH] Add validation for menu icons. (#130) --- .../Editor/Inspector/MenuInstallerEditor.cs | 48 +++++++++++++++++-- .../Editor/Localization/en.json | 2 + .../Editor/Localization/ja.json | 2 + .../nadena.dev.modular-avatar/Editor/Util.cs | 29 +++++++++++ 4 files changed, 77 insertions(+), 4 deletions(-) diff --git a/Packages/nadena.dev.modular-avatar/Editor/Inspector/MenuInstallerEditor.cs b/Packages/nadena.dev.modular-avatar/Editor/Inspector/MenuInstallerEditor.cs index 45b98d7d..c7dba388 100644 --- a/Packages/nadena.dev.modular-avatar/Editor/Inspector/MenuInstallerEditor.cs +++ b/Packages/nadena.dev.modular-avatar/Editor/Inspector/MenuInstallerEditor.cs @@ -5,6 +5,7 @@ using UnityEngine; using VRC.SDK3.Avatars.Components; using VRC.SDK3.Avatars.ScriptableObjects; using static nadena.dev.modular_avatar.core.editor.Localization; +using static nadena.dev.modular_avatar.core.editor.Util; namespace nadena.dev.modular_avatar.core.editor { @@ -118,13 +119,26 @@ namespace nadena.dev.modular_avatar.core.editor } _devFoldout = EditorGUILayout.Foldout(_devFoldout, G("menuinstall.devoptions")); - if (_devFoldout) + if (_devFoldout) { + SerializedProperty menuToAppendProperty = serializedObject.FindProperty(nameof(ModularAvatarMenuInstaller.menuToAppend)); + switch (ValidateExpressionMenuIcon((VRCExpressionsMenu)menuToAppendProperty.objectReferenceValue)) + { + case ValidateExpressionMenuIconResult.Success: + break; + case ValidateExpressionMenuIconResult.TooLarge: + EditorGUILayout.HelpBox(S("menuinstall.menu_icon_too_large"), MessageType.Error); + break; + case ValidateExpressionMenuIconResult.Uncompressed: + EditorGUILayout.HelpBox(S("menuinstall.menu_icon_uncompressed"), MessageType.Error); + break; + default: + throw new ArgumentOutOfRangeException(); + } + EditorGUI.indentLevel++; EditorGUILayout.PropertyField( - serializedObject.FindProperty(nameof(ModularAvatarMenuInstaller.menuToAppend)), - new GUIContent(G("menuinstall.srcmenu")) - ); + menuToAppendProperty, new GUIContent(G("menuinstall.srcmenu"))); EditorGUI.indentLevel--; } @@ -190,5 +204,31 @@ namespace nadena.dev.modular_avatar.core.editor { return _avatarMenus == null || _avatarMenus.Contains(menu); } + + private static ValidateExpressionMenuIconResult ValidateExpressionMenuIcon(VRCExpressionsMenu menu) + { + if (menu == null) return ValidateExpressionMenuIconResult.Success; + + foreach (VRCExpressionsMenu.Control control in menu.controls) + { + // Control + ValidateExpressionMenuIconResult result = Util.ValidateExpressionMenuIcon(control.icon); + if (result != ValidateExpressionMenuIconResult.Success) return result; + + // Labels + foreach (VRCExpressionsMenu.Control.Label label in control.labels) + { + ValidateExpressionMenuIconResult labelResult = Util.ValidateExpressionMenuIcon(label.icon); + if (labelResult != ValidateExpressionMenuIconResult.Success) return labelResult; + } + + // SubMenu + if (control.type != VRCExpressionsMenu.Control.ControlType.SubMenu) continue; + ValidateExpressionMenuIconResult subMenuResult = ValidateExpressionMenuIcon(control.subMenu); + if (subMenuResult != ValidateExpressionMenuIconResult.Success) return subMenuResult; + } + + return ValidateExpressionMenuIconResult.Success; + } } } \ No newline at end of file diff --git a/Packages/nadena.dev.modular-avatar/Editor/Localization/en.json b/Packages/nadena.dev.modular-avatar/Editor/Localization/en.json index 64ef7078..557d0e21 100644 --- a/Packages/nadena.dev.modular-avatar/Editor/Localization/en.json +++ b/Packages/nadena.dev.modular-avatar/Editor/Localization/en.json @@ -9,6 +9,8 @@ "menuinstall.showcontents": "Show menu contents", "menuinstall.showcontents.notselected": "No menu selected", "menuinstall.devoptions": "Prefab Developer Options", + "menuinstall.menu_icon_too_large" : "The icon set in the menu is too large than 256 pixels.", + "menuinstall.menu_icon_uncompressed" : "The icon set in the menu is not set for compression.", "menuinstall.srcmenu": "Menu to Install", "params.autodetect_header": " Autodetected Parameters ", "params.internal": "Internal", diff --git a/Packages/nadena.dev.modular-avatar/Editor/Localization/ja.json b/Packages/nadena.dev.modular-avatar/Editor/Localization/ja.json index ffd5693d..31c0c651 100644 --- a/Packages/nadena.dev.modular-avatar/Editor/Localization/ja.json +++ b/Packages/nadena.dev.modular-avatar/Editor/Localization/ja.json @@ -9,6 +9,8 @@ "menuinstall.showcontents": "メニュー内容を表示", "menuinstall.showcontents.notselected": "メニューが選択されていません", "menuinstall.devoptions": "プレハブ開発者向け設定", + "menuinstall.menu_icon_too_large" : "メニューに設定されているアイコンが256ピクセルより大きすぎます。", + "menuinstall.menu_icon_uncompressed" : "メニューに設定されているアイコンが圧縮設定されていません。", "menuinstall.srcmenu": "インストールされるメニュー", "params.autodetect_header": " 自動検出されたパラメーター ", "params.internal": "内部値", diff --git a/Packages/nadena.dev.modular-avatar/Editor/Util.cs b/Packages/nadena.dev.modular-avatar/Editor/Util.cs index 6c0551f9..21a608a1 100644 --- a/Packages/nadena.dev.modular-avatar/Editor/Util.cs +++ b/Packages/nadena.dev.modular-avatar/Editor/Util.cs @@ -27,6 +27,7 @@ using System.Reflection; using JetBrains.Annotations; using UnityEditor; using UnityEditor.Animations; +using UnityEngine; using VRC.SDKBase.Editor.BuildPipeline; using Object = UnityEngine.Object; @@ -138,5 +139,33 @@ namespace nadena.dev.modular_avatar.core.editor return avatarValidation; } + + private const int MAX_EXPRESSION_TEXTURE_SIZE = 256; + + public enum ValidateExpressionMenuIconResult + { + Success, + TooLarge, + Uncompressed + } + + public static ValidateExpressionMenuIconResult ValidateExpressionMenuIcon(Texture2D icon) + { + string path = AssetDatabase.GetAssetPath(icon); + TextureImporter importer = AssetImporter.GetAtPath(path) as TextureImporter; + if (importer == null) return ValidateExpressionMenuIconResult.Success; + TextureImporterPlatformSettings settings = importer.GetDefaultPlatformTextureSettings(); + + // Max texture size; + if ((icon.width > MAX_EXPRESSION_TEXTURE_SIZE || icon.height > MAX_EXPRESSION_TEXTURE_SIZE) && + settings.maxTextureSize > MAX_EXPRESSION_TEXTURE_SIZE) return ValidateExpressionMenuIconResult.TooLarge; + + // Compression + if (settings.textureCompression == TextureImporterCompression.Uncompressed) return ValidateExpressionMenuIconResult.Uncompressed; + return ValidateExpressionMenuIconResult.Success; + } + + + } } \ No newline at end of file