Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
『VRChatBlockedComponentsRemover.cs』 VRChatのOculust Quest版のアバターにおいて、使用できないコンポーネントを削除します。 https://twitter.com/esperecyan/status/1185926369441509381
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
using UnityEditor;
namespace Esperecyan.Unity.VRChatBlockedComponentsRemover
{
/// <summary>
/// VRChatのOculust Quest版のアバターにおいて、使用できないコンポーネントを削除します。
/// </summary>
/// <remarks>
/// 1. Unityの「Assets」フォルダ内に「Editor」フォルダを作り、その中にこのスクリプトファイル「VRChatBlockedComponentsRemover.cs」を入れる
/// 2. Hierarchey上で、Quest未対応コンポーネントを削除するアバターを選択する
/// 3. VRChat SDK ▸ Utilities ▸ Remove blocked components on Quest
///
/// 動作確認バージョン: Unity 2018.4.20f1, VRChat SDK2 2019.09.18.12.05, VRChat SDK3-Avatar 2020.08.13.17.48
/// SPDX-License-Identifier: MPL-2.0
/// (Mozilla Public License 2.0) <https://spdx.org/licenses/MPL-2.0.html>
/// Author: 100の人
/// 配布元: <https://twitter.com/esperecyan/status/1185926369441509381>
/// 旧称: VRChatUnsupportedComponentsRemover.cs
/// </remarks>
public class VRChatBlockedComponentsRemover
{
private const string NameAndVersion = "VRChatBlockedComponentsRemover.cs-1.1.0";
private const string MenuItemName = "VRChat SDK/Utilities/Remove blocked components on Quest";
private const string MenuItemNameIncludingAnimators
= MenuItemName + " and Animator components without root and Body";
private static readonly IEnumerable<string> ComponentTypeWhiteListOnQuest = new[] {
"UnityEngine.Transform",
"UnityEngine.Animator",
"VRC.Core.PipelineManager",
"VRCSDK2.VRC_AvatarDescriptor",
"VRC.SDK3.Avatars.Components.VRCAvatarDescriptor",
"VRCSDK2.VRC_AvatarVariations",
"VRC.SDK3.Components.VRCAvatarVariations",
"NetworkMetadata",
"RootMotion.FinalIK.IKExecutionOrder",
"RootMotion.FinalIK.VRIK",
"RootMotion.FinalIK.FullBodyBipedIK",
"RootMotion.FinalIK.LimbIK",
"RootMotion.FinalIK.AimIK",
"RootMotion.FinalIK.BipedIK",
"RootMotion.FinalIK.GrounderIK",
"RootMotion.FinalIK.GrounderFBBIK",
"RootMotion.FinalIK.GrounderVRIK",
"RootMotion.FinalIK.GrounderQuadruped",
"RootMotion.FinalIK.TwistRelaxer",
"RootMotion.FinalIK.ShoulderRotator",
"RootMotion.FinalIK.FBBIKArmBending",
"RootMotion.FinalIK.FBBIKHeadEffector",
"RootMotion.FinalIK.FABRIK",
"RootMotion.FinalIK.FABRIKChain",
"RootMotion.FinalIK.FABRIKRoot",
"RootMotion.FinalIK.CCDIK",
"RootMotion.FinalIK.RotationLimit",
"RootMotion.FinalIK.RotationLimitHinge",
"RootMotion.FinalIK.RotationLimitPolygonal",
"RootMotion.FinalIK.RotationLimitSpline",
"UnityEngine.SkinnedMeshRenderer",
"LimbIK",
"AvatarAnimation",
"LoadingAvatarTextureAnimation",
"UnityEngine.MeshFilter",
"UnityEngine.MeshRenderer",
"UnityEngine.Animation",
"UnityEngine.ParticleSystem",
"UnityEngine.ParticleSystemRenderer",
"UnityEngine.TrailRenderer",
"UnityEngine.FlareLayer",
"UnityEngine.GUILayer",
"AvatarCustomAudioLimiter",
"UnityEngine.EllipsoidParticleEmitter",
"UnityEngine.ParticleRenderer",
"UnityEngine.ParticleAnimator",
"UnityEngine.MeshParticleEmitter",
"UnityEngine.LineRenderer",
"VRCSDK2.VRC_IKFollower",
"VRC_IKFollowerInternal",
"RealisticEyeMovements.EyeAndHeadAnimator",
"RealisticEyeMovements.LookTargetController",
"AvatarAudioSourceFilter",
"VRCSDK2.VRC_Station",
"VRC.SDK3.Avatars.Components.VRCStation",
"VRC_StationInternal",
"VRC.AvatarPerformanceComponentSettings",
};
private static readonly string AutoBlinkMeshName = "Body";
/// <summary>
/// VRChatのOculust Quest版のアバターにおいて、付いているとアップロードができなくなるコンポーネントを削除します。
/// </summary>
/// <param name="avatars">Hierarchyのルートにあって、<see cref="VRC_AvatarDescriptor"/>コンポーネントが付いているオブジェクト。</param>
/// <param name="removeAnimators"><see cref="Animator"/>コンポーネントも削除する場合は <c>true</c>。
/// ただし、ルート、およびルート直下の「Body」という名前のオブジェクトに付いているAnimatorは削除しません。</param>
public static void Remove(IEnumerable<GameObject> avatars, bool removeAnimators = false)
{
foreach (GameObject avatar in avatars)
{
foreach (var component in avatar.GetComponentsInChildren<Component>(true).Where(component =>
!VRChatBlockedComponentsRemover.ComponentTypeWhiteListOnQuest.Contains(component.GetType().FullName)
|| removeAnimators && component is Animator
&& !VRChatBlockedComponentsRemover.IsImportantAnimator(component as Animator)))
{
if (component is Camera)
{
Object.DestroyImmediate(component.GetComponent<FlareLayer>());
}
Object.DestroyImmediate(component);
}
}
}
[MenuItem(VRChatBlockedComponentsRemover.MenuItemName, true)]
[MenuItem(VRChatBlockedComponentsRemover.MenuItemNameIncludingAnimators, true)]
private static bool AllSelectedObjectsIsAvatarForVRChat()
{
if (Selection.gameObjects.Length == 0)
{
return false;
}
foreach (GameObject gameObject in Selection.gameObjects) {
if (!gameObject.activeInHierarchy
|| !gameObject.GetComponent("VRCSDK2.VRC_AvatarDescriptor")
&& !gameObject.GetComponent("VRC.SDK3.Avatars.Components.VRCAvatarDescriptor")
|| gameObject.transform.root != gameObject.transform)
{
return false;
}
}
return true;
}
[MenuItem(VRChatBlockedComponentsRemover.MenuItemName, false, 1112)]
private static void RemoveExcludingAniamtors()
{
VRChatBlockedComponentsRemover.RemoveComponents(includingAnimators: false);
}
[MenuItem(VRChatBlockedComponentsRemover.MenuItemNameIncludingAnimators, false, 1112)]
private static void RemoveIncludingAnimators()
{
VRChatBlockedComponentsRemover.RemoveComponents(includingAnimators: true);
}
private static bool IsImportantAnimator(Animator animator)
{
return animator.transform == animator.transform.root
|| animator.transform.parent == animator.transform.root
&& animator.name == VRChatBlockedComponentsRemover.AutoBlinkMeshName;
}
private static void RemoveComponents(bool includingAnimators)
{
IEnumerable<GameObject> avatars = Selection.gameObjects;
VRChatBlockedComponentsRemover.Remove(avatars: avatars, removeAnimators: true);
EditorUtility.DisplayDialog(
VRChatBlockedComponentsRemover.NameAndVersion,
"Removed blocked components on Quest from:\n\n"
+ string.Join("\n", avatars.Select(avatar => avatar.name).ToArray()),
"OK"
);
}
}
}
fileFormatVersion: 2
guid: bb9fd2b711c83ff48aeca3491fdc4d52
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.