private static void RemoveMissingComponents() { var i18n = VRCQuestToolsSettings.I18nResource; var obj = Selection.activeGameObject; var count = VRCSDKUtility.CountMissingComponentsInChildren(obj, true); Debug.Log($"[{VRCQuestTools.Name}] {obj.name} has {count} missing scripts in children"); if (count == 0) { EditorUtility.DisplayDialog(VRCQuestTools.Name, i18n.NoMissingComponentsMessage(obj.name), "OK"); return; } var needsToUnpackPrefab = PrefabUtility.IsPartOfPrefabInstance(obj); var message = i18n.MissingRemoverConfirmationMessage(obj.name); if (needsToUnpackPrefab) { message += $" ({i18n.UnpackPrefabMessage})"; } if (!EditorUtility.DisplayDialog(VRCQuestTools.Name, message, "OK", i18n.CancelLabel)) { return; } if (needsToUnpackPrefab) { Undo.SetCurrentGroupName("Remove Missing Components"); // Somehow unpacking is needed to apply changes to the scene file. PrefabUtility.UnpackPrefabInstance(obj, PrefabUnpackMode.OutermostRoot, InteractionMode.UserAction); Debug.Log($"[{VRCQuestTools.Name}] {obj.name} has been unpacked"); } VRCSDKUtility.RemoveMissingComponentsInChildren(obj, true); }
#pragma warning restore SA1600 // Elements should be documented /// <summary> /// Covert the avatar for Quest. /// </summary> /// <param name="avatar">Avatar to convert.</param> /// <param name="assetsDirectory">Root directory to save.</param> /// <param name="generateQuestTextures">Whether to generate textures.</param> /// <param name="maxTextureSize">Max textures size. 0 for no limits.</param> /// <param name="remover">ComponentRemover object.</param> /// <param name="progressCallback">Callback to show progress.</param> /// <returns>Converted avatar.</returns> internal virtual Tuple <VRChatAvatar, string> ConvertForQuest(VRChatAvatar avatar, string assetsDirectory, bool generateQuestTextures, int maxTextureSize, ComponentRemover remover, ProgressCallback progressCallback) { // Convert materials and generate textures. var convertedMaterials = ConvertMaterialsForToonLit(avatar.Materials, assetsDirectory); if (generateQuestTextures) { var generatedTextures = GenrateToonLitTextures(avatar.Materials, assetsDirectory, maxTextureSize, progressCallback.onTextureProgress); foreach (var tex in generatedTextures) { if (convertedMaterials.ContainsKey(tex.Key)) { convertedMaterials[tex.Key].mainTexture = tex.Value; } } AssetDatabase.SaveAssets(); } // Duplicate the original gameobject. var questAvatarObject = UnityEngine.Object.Instantiate(avatar.AvatarDescriptor.gameObject); // Convert animator controllers and their animation clips. if (avatar.HasAnimatedMaterials) { var convertedAnimationClips = ConvertAnimationClipsForQuest(avatar.GetRuntimeAnimatorControllers(), assetsDirectory, convertedMaterials, progressCallback.onAnimationClipProgress); var convertedAnimatorControllers = ConvertAnimatorControllersForQuest(avatar.GetRuntimeAnimatorControllers(), assetsDirectory, convertedAnimationClips, progressCallback.onRuntimeAnimatorProgress); // Apply converted animator controllers. #if VRC_SDK_VRCSDK3 var layers = questAvatarObject.GetComponent <VRC.SDK3.Avatars.Components.VRCAvatarDescriptor>().baseAnimationLayers; for (int i = 0; i < layers.Length; i++) { if (!layers[i].isDefault && layers[i].animatorController != null) { if (convertedAnimatorControllers.ContainsKey(layers[i].animatorController)) { layers[i].animatorController = convertedAnimatorControllers[layers[i].animatorController]; } } } #endif foreach (var animator in questAvatarObject.GetComponentsInChildren <Animator>(true)) { if (animator.runtimeAnimatorController != null) { if (convertedAnimatorControllers.ContainsKey(animator.runtimeAnimatorController)) { animator.runtimeAnimatorController = convertedAnimatorControllers[animator.runtimeAnimatorController]; } } } } // Apply converted materials to renderers. // Apply AFTER animator controllers because original animation clips overwrite sharedMaterials. foreach (var renderer in questAvatarObject.GetComponentsInChildren <Renderer>(true)) { renderer.sharedMaterials = renderer.sharedMaterials.Select(m => { if (m == null) { return(null); } if (convertedMaterials.ContainsKey(m)) { return(convertedMaterials[m]); } return(m); }).ToArray(); } VRCSDKUtility.RemoveMissingComponentsInChildren(questAvatarObject, true); remover.RemoveUnsupportedComponentsInChildren(questAvatarObject, true); questAvatarObject.name = avatar.AvatarDescriptor.gameObject.name + " (Quest)"; questAvatarObject.SetActive(true); var prefabName = $"{assetsDirectory}/{questAvatarObject.name}.prefab"; return(new Tuple <VRChatAvatar, string>(new VRChatAvatar(questAvatarObject.GetComponent <VRC_AvatarDescriptor>()), prefabName)); }