From 5d60921e326552c399d4fda73cf61406657b0979 Mon Sep 17 00:00:00 2001 From: Toys0125 Date: Sun, 25 Jan 2026 18:55:03 -0600 Subject: [PATCH 1/3] Added Enumator of types. --- .../Scripts/Editor/BasisAvatarValidator.cs | 59 +++++++++++++------ 1 file changed, 41 insertions(+), 18 deletions(-) diff --git a/Basis/Packages/com.basis.sdk/Scripts/Editor/BasisAvatarValidator.cs b/Basis/Packages/com.basis.sdk/Scripts/Editor/BasisAvatarValidator.cs index 7ff2cbacf..f9ec25288 100644 --- a/Basis/Packages/com.basis.sdk/Scripts/Editor/BasisAvatarValidator.cs +++ b/Basis/Packages/com.basis.sdk/Scripts/Editor/BasisAvatarValidator.cs @@ -146,14 +146,26 @@ public void CreatePassedPanel(VisualElement rootElement) rootElement.Add(passedPanel); } + public enum ValidationCategory + { + None, + Configuration, + GameObject, + Perfomance, + Security, + MissingReference + } + public class BasisValidationIssue { + public ValidationCategory Category { get; } public string Message { get; } public string FixLabel { get; } public Action Fix { get; } - public BasisValidationIssue(string message, Action fix = null, string fixLabel = "") + public BasisValidationIssue(string message, ValidationCategory category = ValidationCategory.None, Action fix = null, string fixLabel = "") { + Category = category; Message = message; Fix = fix; FixLabel = fixLabel; @@ -186,7 +198,7 @@ public bool ValidateAvatar(out List errors, out List errors, out List RemoveMissingScripts(Avatar.gameObject), "Remove missing scripts" )); @@ -220,7 +232,7 @@ public bool ValidateAvatar(out List errors, out List errors, out List errors, out List errors, out List 0) passes.Add("BlinkViseme Meta Data is assigned."); else - errors.Add(new BasisValidationIssue("BlinkViseme Meta Data is missing.", null)); + errors.Add(new BasisValidationIssue("BlinkViseme Meta Data is missing.", ValidationCategory.MissingReference, null)); if (Avatar.FaceVisemeMovement != null && Avatar.FaceVisemeMovement.Length > 0) passes.Add("FaceVisemeMovement Meta Data is assigned."); else - errors.Add(new BasisValidationIssue("FaceVisemeMovement Meta Data is missing.", null)); + errors.Add(new BasisValidationIssue("FaceVisemeMovement Meta Data is missing.", ValidationCategory.MissingReference, null)); // Face meshes if (Avatar.FaceBlinkMesh != null) passes.Add("FaceBlinkMesh is assigned."); else errors.Add(new BasisValidationIssue( - "FaceBlinkMesh is missing. Assign a skinned mesh.", + "FaceBlinkMesh is missing. Assign a skinned mesh.", ValidationCategory.MissingReference, FixAssignFaceMeshesFromChildren, "Auto-assign Face meshes" )); @@ -268,7 +280,7 @@ public bool ValidateAvatar(out List errors, out List errors, out List errors, out List errors, out List errors, out List errors, out List errors, out List warnings, ref { warnings.Add(new BasisValidationIssue( "Translation DoF is Eabled on one or more source models (Humanoid). This can cause retargeting issues.", + ValidationCategory.GameObject, FixTryCreateHumanoidAvatarOnSourceModels, "Disable Translation DoF + Humanoid Avatar on source models" )); @@ -597,6 +610,7 @@ public void CheckShaders(Renderer renderer, ref List error // Offer best-effort fallback: URP Lit if present else Standard if present errors.Add(new BasisValidationIssue( $"Material \"{mat.name}\" on \"{renderer.gameObject.name}\" is using an error/unsupported shader (pink).", + ValidationCategory.GameObject, () => FixMaterialShaderFallback(mat), "Set shader fallback (URP Lit / Standard)" )); @@ -676,6 +690,7 @@ public void CheckTextures(Renderer Renderer, ref List warn { warnings.Add(new BasisValidationIssue( $"Texture \"{tex.name}\" does not have Mip Maps enabled. This will negatively affect its performance ranking.", + ValidationCategory.Perfomance, () => { texImporter.mipmapEnabled = true; @@ -690,6 +705,7 @@ public void CheckTextures(Renderer Renderer, ref List warn { warnings.Add(new BasisValidationIssue( $"Texture \"{tex.name}\" does not have Streaming Mip Maps enabled. This will negatively affect its performance ranking.", + ValidationCategory.Perfomance, () => { texImporter.streamingMipmaps = true; @@ -702,7 +718,9 @@ public void CheckTextures(Renderer Renderer, ref List warn if (texImporter.maxTextureSize > MaxTextureSizeBeforeWarning) { warnings.Add(new BasisValidationIssue( + $"Texture \"{tex.name}\" is {texImporter.maxTextureSize} (should be <= {MaxTextureSizeBeforeWarning}). This will negatively affect its performance ranking.", + ValidationCategory.Perfomance, () => { texImporter.maxTextureSize = MaxTextureSizeBeforeWarning; @@ -726,6 +744,7 @@ public void CheckMesh(SkinnedMeshRenderer skinnedMeshRenderer, ref List Date: Sun, 25 Jan 2026 21:19:59 -0600 Subject: [PATCH 2/3] Added better Viewing of warnings, ability to select gameobjects with missing scripts, and Hopefully not lag the inspector while sitting doing nothing. --- .../Scripts/Editor/BasisAvatarValidator.cs | 192 ++++++++++++++---- 1 file changed, 157 insertions(+), 35 deletions(-) diff --git a/Basis/Packages/com.basis.sdk/Scripts/Editor/BasisAvatarValidator.cs b/Basis/Packages/com.basis.sdk/Scripts/Editor/BasisAvatarValidator.cs index f9ec25288..cf0025075 100644 --- a/Basis/Packages/com.basis.sdk/Scripts/Editor/BasisAvatarValidator.cs +++ b/Basis/Packages/com.basis.sdk/Scripts/Editor/BasisAvatarValidator.cs @@ -2,6 +2,7 @@ using System; using System.Collections.Generic; using System.IO; +using System.Linq; using UnityEditor; using UnityEngine; using UnityEngine.Rendering; @@ -14,7 +15,7 @@ public class BasisAvatarValidator private VisualElement errorPanel; private Label errorMessageLabel; - private VisualElement warningPanel; + private Dictionary warningPanels = new Dictionary(); private Label warningMessageLabel; private VisualElement passedPanel; @@ -36,7 +37,7 @@ public BasisAvatarValidator(BasisAvatar avatar, VisualElement root) Root = root; CreateErrorPanel(root); - CreateWarningPanel(root); + //CreateWarningPanel(root); CreatePassedPanel(root); EditorApplication.update += UpdateValidation; // Run per frame @@ -50,7 +51,7 @@ public void OnDestroy() private void UpdateValidation() { // Clear fix buttons each frame so they match current validation results - ClearFixButtons(Root); + //ClearFixButtons(Root); if (ValidateAvatar(out List errors, out List warnings, out List passes)) HideErrorPanel(); @@ -92,7 +93,7 @@ public void CreateErrorPanel(VisualElement rootElement) errorPanel.style.display = DisplayStyle.None; rootElement.Add(errorPanel); } - + /* public void CreateWarningPanel(VisualElement rootElement) { warningPanel = new VisualElement(); @@ -119,6 +120,7 @@ public void CreateWarningPanel(VisualElement rootElement) warningPanel.style.display = DisplayStyle.None; rootElement.Add(warningPanel); } + */ public void CreatePassedPanel(VisualElement rootElement) { @@ -162,13 +164,16 @@ public class BasisValidationIssue public string Message { get; } public string FixLabel { get; } public Action Fix { get; } + public UnityEngine.Object RelatedObject { get; } - public BasisValidationIssue(string message, ValidationCategory category = ValidationCategory.None, Action fix = null, string fixLabel = "") + public BasisValidationIssue(string message, ValidationCategory category = ValidationCategory.None, + Action fix = null, string fixLabel = "", UnityEngine.Object relatedObject = null) { Category = category; Message = message; Fix = fix; FixLabel = fixLabel; + RelatedObject = relatedObject; } } @@ -203,25 +208,19 @@ public bool ValidateAvatar(out List errors, out List(true); - for (int i = 0; i < components.Length; i++) - { - if (components[i] == null) missingCount++; - } - - if (missingCount == 0) - { - passes.Add("No missing scripts found in the scene."); - } - else + Transform[] children = Avatar.gameObject.GetComponentsInChildren(true); + foreach (Transform child in children) { - warnings.Add(new BasisValidationIssue( - "Missing script references found. Click to remove them.", ValidationCategory.MissingReference, + int count = GameObjectUtility.GetMonoBehavioursWithMissingScriptCount(child.gameObject); + if (count > 0) + { + warnings.Add(new BasisValidationIssue( + $"Missing script references found on {child.gameObject}. Click here to locate it.", ValidationCategory.MissingReference, () => RemoveMissingScripts(Avatar.gameObject), - "Remove missing scripts" - )); + "Remove missing scripts", + child.gameObject + )); + } } // Animator @@ -314,6 +313,17 @@ public bool ValidateAvatar(out List errors, out List(BasisAssetBundleObject.AssetBundleObject); + if (assetBundleObject != null) + { + if(assetBundleObject.UseCustomPassword && (assetBundleObject.UserSelectedPassword == null || assetBundleObject.UserSelectedPassword == "")) + { + errors.Add(new BasisValidationIssue( + "Can not have custom password be empty!", + ValidationCategory.Security, + null)); + } + } // Processing options if (Avatar.ProcessingAvatarOptions != null && Avatar.ProcessingAvatarOptions.RemoveUnusedBlendshapes == false) @@ -374,7 +384,7 @@ public bool ValidateAvatar(out List errors, out List warnings) { - List warningsList = new List(); + // 1. GENERATE SIGNATURE + // Create a simple string representing the current warnings (e.g. "Category:Message|Category:Message") + // If the list is huge, we can use a hash, but string join is usually fine for UI lists. + string currentSignature = string.Join("|", warnings.Select(w => $"{w.Category}:{w.Message}")); + + // 2. DIRTY CHECK + // If the data is exactly the same as the last frame, DO NOTHING. + if (currentSignature == _lastWarningSignature) return; + + // Data changed, save the new signature + _lastWarningSignature = currentSignature; + + // 3. REBUILD LOGIC + // (Optimization: Instead of warningPanel.Clear(), we hide existing ones and re-enable only what we need) - for (int i = 0; i < warnings.Count; i++) + // Reset all known panels to hidden initially (pool-like behavior) + foreach (var panel in warningPanels.Values) { - var issue = warnings[i]; - if (issue.Fix != null) + panel.style.display = DisplayStyle.None; + } + + int maxDisplayCount = 3; + var groupedIssues = warnings.GroupBy(w => w.Category); + + foreach (var group in groupedIssues) + { + ValidationCategory category = group.Key; + List issues = group.ToList(); + + // --- LAZY CREATION --- + // Only create the visual element if we've never seen this category before + if (!warningPanels.ContainsKey(category)) { - string actionTitle = string.IsNullOrWhiteSpace(issue.FixLabel) ? issue.Message : issue.FixLabel; - AutoFixButton(Root, issue.Fix, actionTitle, false); + VisualElement newPanel = CreateCategoryPanel(category); // Uses your helper method + Root.Add(newPanel); // Add to the main Root UI + warningPanels.Add(category, newPanel); } - if (!warningsList.Contains(issue.Message)) - warningsList.Add(issue.Message); - } + // Get the cached panel + VisualElement currentPanel = warningPanels[category]; + currentPanel.style.display = DisplayStyle.Flex; // Unhide it + + // --- UPDATE TEXT --- + Label messageLabel = currentPanel.Q