using System; using System.Collections.Generic; using UnityEngine; using System.Reflection; namespace VRCSDK2.Validation { public static class ValidationUtils { public static void RemoveIllegalComponents(GameObject target, HashSet whitelist, bool retry = true, bool onlySceneObjects = false, bool logStripping = true) { IEnumerable foundComponents = FindIllegalComponents(target, whitelist); foreach(Component component in foundComponents) { if(component == null) { continue; } if (onlySceneObjects && component.GetInstanceID() < 0) { continue; } if (logStripping) { VRC.Core.Logger.LogWarning(string.Format("Removing {0} comp from {1}", component.GetType().Name, component.gameObject.name)); } RemoveComponent(component); } } public static IEnumerable FindIllegalComponents(GameObject target, HashSet whitelist) { List foundComponents = new List(); Component[] allComponents = target.GetComponentsInChildren(true); foreach(Component component in allComponents) { if(component == null) { continue; } Type componentType = component.GetType(); if(whitelist.Contains(componentType)) { continue; } foundComponents.Add(component); } return foundComponents; } private static readonly Dictionary _typeCache = new Dictionary(); private static readonly Dictionary> _whitelistCache = new Dictionary>(); public static HashSet WhitelistedTypes(string whitelistName, IEnumerable componentTypeWhitelist) { if (_whitelistCache.ContainsKey(whitelistName)) { return _whitelistCache[whitelistName]; } Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies(); HashSet whitelist = new HashSet(); foreach(string whitelistedTypeName in componentTypeWhitelist) { Type whitelistedType = GetTypeFromName(whitelistedTypeName, assemblies); if(whitelistedType == null) { continue; } if(whitelist.Contains(whitelistedType)) { continue; } whitelist.Add(whitelistedType); } AddDerivedClasses(whitelist); _whitelistCache[whitelistName] = whitelist; return _whitelistCache[whitelistName]; } public static HashSet WhitelistedTypes(string whitelistName, IEnumerable componentTypeWhitelist) { if (_whitelistCache.ContainsKey(whitelistName)) { return _whitelistCache[whitelistName]; } HashSet whitelist = new HashSet(); whitelist.UnionWith(componentTypeWhitelist); AddDerivedClasses(whitelist); _whitelistCache[whitelistName] = whitelist; return _whitelistCache[whitelistName]; } private static void AddDerivedClasses(HashSet whitelist) { Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies(); foreach(Assembly assembly in assemblies) { foreach(Type type in assembly.GetTypes()) { if(whitelist.Contains(type)) { continue; } if(!typeof(Component).IsAssignableFrom(type)) { continue; } Type currentType = type; while(currentType != typeof(object) && currentType != null) { if(whitelist.Contains(currentType)) { whitelist.Add(type); break; } currentType = currentType.BaseType; } } } } public static Type GetTypeFromName(string name, Assembly[] assemblies = null) { if (_typeCache.ContainsKey(name)) { return _typeCache[name]; } if (assemblies == null) { assemblies = AppDomain.CurrentDomain.GetAssemblies(); } foreach (Assembly assembly in assemblies) { Type found = assembly.GetType(name); if(found == null) { continue; } _typeCache[name] = found; return found; } //This is really verbose for some SDK scenes, eg. //If they don't have FinalIK installed #if VRC_CLIENT && UNITY_EDITOR Debug.LogWarningFormat("Could not find type {0}", name); #endif _typeCache[name] = null; return null; } private static void RemoveDependencies(Component component) { if (component == null) return; Component[] components = component.GetComponents(); if (components == null || components.Length == 0) return; System.Type compType = component.GetType(); foreach (var c in components) { if (c == null) continue; bool deleteMe = false; object[] requires = c.GetType().GetCustomAttributes(typeof(RequireComponent), true); if (requires == null || requires.Length == 0) continue; foreach (var r in requires) { RequireComponent rc = r as RequireComponent; if (rc == null) continue; if (rc.m_Type0 == compType || rc.m_Type1 == compType || rc.m_Type2 == compType) { deleteMe = true; break; } } if (deleteMe) RemoveComponent(c); } } public static void RemoveComponent(Component comp) { if (comp == null) return; RemoveDependencies(comp); #if VRC_CLIENT UnityEngine.Object.DestroyImmediate(comp, true); #else UnityEngine.Object.DestroyImmediate(comp, false); #endif } public static void RemoveComponentsOfType(GameObject target) where T : Component { if (target == null) return; foreach (T comp in target.GetComponentsInChildren(true)) { if (comp == null || comp.gameObject == null) continue; RemoveComponent(comp); } } } }