From 777780c7357081527f14a243e6b5799583b4fdf7 Mon Sep 17 00:00:00 2001
From: Jared Williams <accounts@jaredwilliams.com.au>
Date: Sat, 18 Jan 2025 14:26:39 +0800
Subject: [PATCH] Output invalid materials

---
 Components/VRCQuestifyerSwitchMaterials.cs    |  7 +++
 .../VRCQuestifyerAvatarEditor.cs              | 58 ++++++++++++++++++-
 2 files changed, 64 insertions(+), 1 deletion(-)

diff --git a/Components/VRCQuestifyerSwitchMaterials.cs b/Components/VRCQuestifyerSwitchMaterials.cs
index 620f1d3..50a384b 100644
--- a/Components/VRCQuestifyerSwitchMaterials.cs
+++ b/Components/VRCQuestifyerSwitchMaterials.cs
@@ -24,6 +24,13 @@ public struct MaterialSwitch {
     public bool addQuestSuffix = true;
     public bool useToonShader = false;
 
+    public void Init() {
+        var transformToUse = this.overrideTarget != null ? this.overrideTarget : this.transform;
+        var renderer = transformToUse.GetComponent<Renderer>();
+
+        materialSwitches = new MaterialSwitch[renderer.sharedMaterials.Length];
+    }
+
     public override void Apply() {
         Debug.Log("VRCQuestifyer :: Switch materials - apply");
 
diff --git a/Editor/ComponentEditors/VRCQuestifyerAvatarEditor.cs b/Editor/ComponentEditors/VRCQuestifyerAvatarEditor.cs
index a684270..760ffc5 100644
--- a/Editor/ComponentEditors/VRCQuestifyerAvatarEditor.cs
+++ b/Editor/ComponentEditors/VRCQuestifyerAvatarEditor.cs
@@ -47,7 +47,13 @@ public override void RenderGUI() {
 
         EditorGUI.BeginDisabledGroup(!canOverrideTarget);
         EditorGUILayout.ObjectField("Target", vrcAvatarDescriptor, typeof(VRCAvatarDescriptor));
-        CustomGUI.ItalicLabel("Leave blank to use this object");
+
+        if (canOverrideTarget) {
+            CustomGUI.ItalicLabel("Leave blank to use this object");
+        } else {
+            CustomGUI.ItalicLabel("You cannot override this target");
+        }
+
         EditorGUI.EndDisabledGroup();
         
         CustomGUI.LineGap();
@@ -158,6 +164,55 @@ void RenderComponentValidationIssues() {
         }
     }
 
+    void RenderMaterialIssues() {
+        var component = target as VRCQuestifyerAvatar;
+        var vrcAvatarDescriptor = Utils.FindComponentInAncestor<VRCAvatarDescriptor>(component.transform);
+
+        List<Renderer> renderers = Utils.FindAllComponents<Renderer>(vrcAvatarDescriptor.transform);
+
+        foreach (var renderer in renderers) {
+            var materials = renderer.sharedMaterials;
+            var isInvalid = true;
+            
+            var switchMaterialsComponent = renderer.gameObject.GetComponent<VRCQuestifyerSwitchMaterials>();
+
+            if (switchMaterialsComponent != null) {
+                continue;
+            }
+
+            foreach (var material in materials) {
+                if (material == null || Common.GetIsMaterialUsingWhitelistedShader(material)) {
+                    continue;
+                }
+
+                isInvalid = true;
+            }
+
+            if (!isInvalid) {
+                continue;
+            }
+
+            EditorGUILayout.BeginHorizontal();
+
+            if (CustomGUI.TinyButton("Ping")) {
+                Utils.Ping(renderer.gameObject);
+            }
+
+            if (CustomGUI.TinyButton("View")) {
+                Utils.Inspect(renderer.gameObject);
+            }
+
+            if (CustomGUI.TinyButton("+Swi")) {
+                switchMaterialsComponent = renderer.gameObject.AddComponent<VRCQuestifyerSwitchMaterials>();
+                switchMaterialsComponent.Init();
+            }
+
+            CustomGUI.Label($"Renderer \"{renderer.gameObject.name}\" has at least one invalid material");
+
+            EditorGUILayout.EndHorizontal();
+        }
+    }
+
     void RenderConstraintIssues() {
         var component = target as VRCQuestifyerAvatar;
         var vrcAvatarDescriptor = Utils.FindComponentInAncestor<VRCAvatarDescriptor>(component.transform);
@@ -326,6 +381,7 @@ void RenderIssues() {
         CustomGUI.MediumLabel("Issues");
 
         RenderComponentValidationIssues();
+        RenderMaterialIssues();
         RenderConstraintIssues();
         RenderPhysBoneIssues();
         RenderContactIssues();