@ -0,0 +1,805 @@
using System ;
using System.Collections.Generic ;
using JetBrains.Annotations ;
#if TextMeshPro
using TMPro ;
#endif
using UnityEngine ;
using UnityEngine.Audio ;
using UnityEngine.Playables ;
using UnityEngine.Timeline ;
using UnityEngine.UI ;
#if VRC_CLIENT
using ZLinq ;
#else
using System.Linq ;
#endif
namespace VRC.SDKBase.Validation
{
public static class WorldValidation
{
private static readonly Lazy < string > _debugCategoryName = new Lazy < string > ( InitializeLogging ) ;
private static string DebugCategoryName = > _debugCategoryName . Value ;
private static string InitializeLogging ( )
{
const string categoryName = "WorldValidation" ;
VRC . Core . Logger . DescribeCategory ( categoryName , VRC . Core . Logger . Color . red ) ;
VRC . Core . Logger . EnableCategory ( categoryName ) ;
return categoryName ;
}
static string [ ] ComponentTypeWhiteList = null ;
public enum WhiteListConfiguration
{
None ,
VRCSDK2 ,
VRCSDK3 ,
Unchanged
}
static WhiteListConfiguration ComponentTypeWhiteListConfiguration = WhiteListConfiguration . None ;
static readonly string [ ] ComponentTypeWhiteListCommon = new string [ ]
{
#if UNITY_STANDALONE
"UnityEngine.Rendering.PostProcessing.PostProcessDebug" ,
"UnityEngine.Rendering.PostProcessing.PostProcessLayer" ,
"UnityEngine.Rendering.PostProcessing.PostProcessVolume" ,
#endif
"VRC.Core.PipelineManager" ,
"UiInputField" ,
"VRCProjectSettings" ,
"DynamicBone" ,
"DynamicBoneCollider" ,
"TMPro.TMP_Dropdown" ,
"TMPro.TMP_InputField" ,
"TMPro.TMP_ScrollbarEventHandler" ,
"TMPro.TMP_SelectionCaret" ,
"TMPro.TMP_SpriteAnimator" ,
"TMPro.TMP_SubMesh" ,
"TMPro.TMP_SubMeshUI" ,
"TMPro.TMP_Text" ,
"TMPro.TextMeshPro" ,
"TMPro.TextMeshProUGUI" ,
"TMPro.TextContainer" ,
"TMPro.TMP_Dropdown+DropdownItem" ,
"UnityEngine.EventSystems.EventSystem" ,
"UnityEngine.EventSystems.EventTrigger" ,
"UnityEngine.EventSystems.UIBehaviour" ,
"UnityEngine.EventSystems.BaseInput" ,
"UnityEngine.EventSystems.BaseInputModule" ,
"UnityEngine.EventSystems.PointerInputModule" ,
"UnityEngine.EventSystems.StandaloneInputModule" ,
"UnityEngine.EventSystems.TouchInputModule" ,
"UnityEngine.EventSystems.BaseRaycaster" ,
"UnityEngine.EventSystems.PhysicsRaycaster" ,
"UnityEngine.UI.Button" ,
"UnityEngine.UI.Dropdown" ,
"UnityEngine.UI.Dropdown+DropdownItem" ,
"UnityEngine.UI.Graphic" ,
"UnityEngine.UI.GraphicRaycaster" ,
"UnityEngine.UI.Image" ,
"UnityEngine.UI.InputField" ,
"UnityEngine.UI.Mask" ,
"UnityEngine.UI.MaskableGraphic" ,
"UnityEngine.UI.RawImage" ,
"UnityEngine.UI.RectMask2D" ,
"UnityEngine.UI.Scrollbar" ,
"UnityEngine.UI.ScrollRect" ,
"UnityEngine.UI.Selectable" ,
"UnityEngine.UI.Slider" ,
"UnityEngine.UI.Text" ,
"UnityEngine.UI.Toggle" ,
"UnityEngine.UI.ToggleGroup" ,
"UnityEngine.UI.AspectRatioFitter" ,
"UnityEngine.UI.CanvasScaler" ,
"UnityEngine.UI.ContentSizeFitter" ,
"UnityEngine.UI.GridLayoutGroup" ,
"UnityEngine.UI.HorizontalLayoutGroup" ,
"UnityEngine.UI.HorizontalOrVerticalLayoutGroup" ,
"UnityEngine.UI.LayoutElement" ,
"UnityEngine.UI.LayoutGroup" ,
"UnityEngine.UI.VerticalLayoutGroup" ,
"UnityEngine.UI.BaseMeshEffect" ,
"UnityEngine.UI.Outline" ,
"UnityEngine.UI.PositionAsUV1" ,
"UnityEngine.UI.Shadow" ,
"OVRLipSync" ,
"OVRLipSyncContext" ,
"OVRLipSyncContextBase" ,
"OVRLipSyncContextCanned" ,
"OVRLipSyncContextMorphTarget" ,
"OVRLipSyncContextTextureFlip" ,
"ONSPReflectionZone" ,
"OculusSpatializerUnity" ,
"ONSPAmbisonicsNative" ,
"ONSPAudioSource" ,
"RootMotion.FinalIK.BipedIK" ,
"RootMotion.FinalIK.FingerRig" ,
"RootMotion.FinalIK.Grounder" ,
"RootMotion.FinalIK.GrounderBipedIK" ,
"RootMotion.FinalIK.GrounderFBBIK" ,
"RootMotion.FinalIK.GrounderIK" ,
"RootMotion.FinalIK.GrounderQuadruped" ,
"RootMotion.FinalIK.GrounderVRIK" ,
"RootMotion.FinalIK.AimIK" ,
"RootMotion.FinalIK.CCDIK" ,
"RootMotion.FinalIK.FABRIK" ,
"RootMotion.FinalIK.FABRIKRoot" ,
"RootMotion.FinalIK.FullBodyBipedIK" ,
"RootMotion.FinalIK.IK" ,
"RootMotion.FinalIK.IKExecutionOrder" ,
"RootMotion.FinalIK.LegIK" ,
"RootMotion.FinalIK.LimbIK" ,
"RootMotion.FinalIK.LookAtIK" ,
"RootMotion.FinalIK.TrigonometricIK" ,
"RootMotion.FinalIK.VRIK" ,
"RootMotion.FinalIK.FBBIKArmBending" ,
"RootMotion.FinalIK.FBBIKHeadEffector" ,
"RootMotion.FinalIK.TwistRelaxer" ,
"RootMotion.FinalIK.InteractionObject" ,
"RootMotion.FinalIK.InteractionSystem" ,
"RootMotion.FinalIK.InteractionTarget" ,
"RootMotion.FinalIK.InteractionTrigger" ,
"RootMotion.FinalIK.GenericPoser" ,
"RootMotion.FinalIK.HandPoser" ,
"RootMotion.FinalIK.Poser" ,
"RootMotion.FinalIK.RagdollUtility" ,
"RootMotion.FinalIK.RotationLimit" ,
"RootMotion.FinalIK.RotationLimitAngle" ,
"RootMotion.FinalIK.RotationLimitHinge" ,
"RootMotion.FinalIK.RotationLimitPolygonal" ,
"RootMotion.FinalIK.RotationLimitSpline" ,
"RootMotion.FinalIK.AimPoser" ,
"RootMotion.FinalIK.Amplifier" ,
"RootMotion.FinalIK.BodyTilt" ,
"RootMotion.FinalIK.HitReaction" ,
"RootMotion.FinalIK.HitReactionVRIK" ,
"RootMotion.FinalIK.Inertia" ,
"RootMotion.FinalIK.OffsetModifier" ,
"RootMotion.FinalIK.OffsetModifierVRIK" ,
"RootMotion.FinalIK.OffsetPose" ,
"RootMotion.FinalIK.Recoil" ,
"RootMotion.FinalIK.ShoulderRotator" ,
"RootMotion.Dynamics.AnimationBlocker" ,
"RootMotion.Dynamics.BehaviourBase" ,
"RootMotion.Dynamics.BehaviourFall" ,
"RootMotion.Dynamics.BehaviourPuppet" ,
"RootMotion.Dynamics.JointBreakBroadcaster" ,
"RootMotion.Dynamics.MuscleCollisionBroadcaster" ,
"RootMotion.Dynamics.PressureSensor" ,
"RootMotion.Dynamics.Prop" ,
"RootMotion.Dynamics.PropRoot" ,
"RootMotion.Dynamics.PuppetMaster" ,
"RootMotion.Dynamics.PuppetMasterSettings" ,
// TODO: remove these if they are only needed in editor
"RootMotion.Dynamics.BipedRagdollCreator" ,
"RootMotion.Dynamics.RagdollCreator" ,
"RootMotion.Dynamics.RagdollEditor" ,
//
"RootMotion.SolverManager" ,
"RootMotion.TriggerEventBroadcaster" ,
"UnityEngine.WindZone" ,
"UnityEngine.Tilemaps.Tilemap" ,
"UnityEngine.Tilemaps.TilemapRenderer" ,
"UnityEngine.Terrain" ,
"UnityEngine.Tree" ,
"UnityEngine.SpriteMask" ,
"UnityEngine.Grid" ,
"UnityEngine.GridLayout" ,
"UnityEngine.AudioSource" ,
"UnityEngine.AudioReverbZone" ,
"UnityEngine.AudioLowPassFilter" ,
"UnityEngine.AudioHighPassFilter" ,
"UnityEngine.AudioDistortionFilter" ,
"UnityEngine.AudioEchoFilter" ,
"UnityEngine.AudioChorusFilter" ,
"UnityEngine.AudioReverbFilter" ,
"UnityEngine.AudioListener" , // will be force-disabled on load, but can't be removed since it's a dependency for some of the above
"UnityEngine.Playables.PlayableDirector" ,
"UnityEngine.TerrainCollider" ,
"UnityEngine.Canvas" ,
"UnityEngine.CanvasGroup" ,
"UnityEngine.CanvasRenderer" ,
"UnityEngine.TextMesh" ,
"UnityEngine.Animator" ,
"UnityEngine.AI.NavMeshAgent" ,
"UnityEngine.AI.NavMeshObstacle" ,
#if UNITY_6000_0_OR_NEWER
"Unity.AI.Navigation.NavMeshLink" ,
#else
"UnityEngine.AI.OffMeshLink" ,
#endif
"UnityEngine.Cloth" ,
"UnityEngine.WheelCollider" ,
"UnityEngine.Rigidbody" ,
"UnityEngine.Joint" ,
"UnityEngine.HingeJoint" ,
"UnityEngine.SpringJoint" ,
"UnityEngine.FixedJoint" ,
"UnityEngine.CharacterJoint" ,
"UnityEngine.ConfigurableJoint" ,
"UnityEngine.ConstantForce" ,
"UnityEngine.Collider" ,
"UnityEngine.BoxCollider" ,
"UnityEngine.SphereCollider" ,
"UnityEngine.MeshCollider" ,
"UnityEngine.CapsuleCollider" ,
"UnityEngine.CharacterController" ,
"UnityEngine.ParticleSystem" ,
"UnityEngine.ParticleSystemRenderer" ,
"UnityEngine.BillboardRenderer" ,
"UnityEngine.Camera" ,
"UnityEngine.FlareLayer" ,
"UnityEngine.SkinnedMeshRenderer" ,
"UnityEngine.Renderer" ,
"UnityEngine.TrailRenderer" ,
"UnityEngine.LineRenderer" ,
"UnityEngine.GUIElement" ,
"UnityEngine.GUILayer" ,
"UnityEngine.Light" ,
"UnityEngine.LightProbeGroup" ,
"UnityEngine.LightProbeProxyVolume" ,
"UnityEngine.LODGroup" ,
"UnityEngine.ReflectionProbe" ,
"UnityEngine.SpriteRenderer" ,
"UnityEngine.Transform" ,
"UnityEngine.RectTransform" ,
"UnityEngine.Rendering.SortingGroup" ,
"UnityEngine.Projector" ,
"UnityEngine.OcclusionPortal" ,
"UnityEngine.OcclusionArea" ,
"UnityEngine.LensFlare" ,
"UnityEngine.Skybox" ,
"UnityEngine.MeshFilter" ,
"UnityEngine.Halo" ,
"UnityEngine.MeshRenderer" ,
"UnityEngine.Collider2D" ,
"UnityEngine.Rigidbody2D" ,
"UnityEngine.CompositeCollider2D" ,
"UnityEngine.ConstantForce2D" ,
"UnityEngine.AreaEffector2D" ,
"UnityEngine.CapsuleCollider2D" ,
"UnityEngine.DistanceJoint2D" ,
"UnityEngine.EdgeCollider2D" ,
"UnityEngine.Effector2D" ,
"UnityEngine.BoxCollider2D" ,
"UnityEngine.CircleCollider2D" ,
"UnityEngine.FixedJoint2D" ,
"UnityEngine.HingeJoint2D" ,
"UnityEngine.FrictionJoint2D" ,
"UnityEngine.PlatformEffector2D" ,
"UnityEngine.PointEffector2D" ,
"UnityEngine.PolygonCollider2D" ,
"UnityEngine.SliderJoint2D" ,
"UnityEngine.SurfaceEffector2D" ,
"UnityEngine.RelativeJoint2D" ,
"UnityEngine.TargetJoint2D" ,
"UnityEngine.WheelJoint2D" ,
"UnityEngine.Joint2D" ,
"UnityEngine.ParticleSystemForceField"
} ;
static readonly string [ ] ComponentTypeWhiteListSdk2 = new string [ ]
{
#if UNITY_STANDALONE
"VRCSDK2.VRC_CustomRendererBehaviour" ,
"VRCSDK2.VRC_MidiNoteIn" ,
"VRCSDK2.scripts.Scenes.VRC_Panorama" ,
"VRCSDK2.VRC_Water" ,
"UnityStandardAssets.Water.WaterBasic" ,
"UnityStandardAssets.Water.Displace" ,
"UnityStandardAssets.Water.GerstnerDisplace" ,
"UnityStandardAssets.Water.PlanarReflection" ,
"UnityStandardAssets.Water.SpecularLighting" ,
"UnityStandardAssets.Water.Water" ,
"UnityStandardAssets.Water.WaterBase" ,
"UnityStandardAssets.Water.WaterTile" ,
#endif
"VRCSDK2.VRCTriggerRelay" ,
"VRCSDK2.VRC_AudioBank" ,
"VRCSDK2.VRC_DataStorage" ,
"VRCSDK2.VRC_EventHandler" ,
"VRCSDK2.VRC_IKFollower" ,
"VRCSDK2.VRC_Label" ,
"VRCSDK2.VRC_KeyEvents" ,
"VRCSDK2.VRC_PhysicsRoot" ,
"VRCSDK2.VRC_CombatSystem" ,
"VRCSDK2.VRC_DestructibleStandard" ,
"VRC_VisualDamage" ,
"VRCSDK2.VRC_OscButtonIn" ,
"VRCSDK2.VRC_GunStats" ,
"VRCSDK2.VRC_JukeBox" ,
"VRCSDK2.VRC_AddDamage" ,
"VRCSDK2.VRC_AddHealth" ,
"VRCSDK2.VRC_AvatarCalibrator" ,
"VRCSDK2.VRC_AvatarPedestal" ,
"VRCSDK2.VRC_NPCSpawn" ,
"VRCSDK2.VRC_ObjectSpawn" ,
"VRCSDK2.VRC_ObjectSync" ,
"VRCSDK2.VRC_Pickup" ,
"VRCSDK2.VRC_PortalMarker" ,
"VRCSDK2.VRC_SlideShow" ,
"VRCSDK2.VRC_SpatialAudioSource" ,
"VRCSDK2.VRC_StationInput" ,
"VRCSDK2.VRC_SyncAnimation" ,
"VRCSDK2.VRC_SyncVideoPlayer" ,
"VRCSDK2.VRC_SyncVideoStream" ,
"VRCSDK2.VRC_VideoScreen" ,
"VRCSDK2.VRC_VideoSpeaker" ,
"VRCSDK2.VRC_PlayerAudioOverride" ,
"VRCSDK2.VRC_MirrorReflection" ,
"VRCSDK2.VRC_PlayerMods" ,
"VRCSDK2.VRC_SceneDescriptor" ,
"VRCSDK2.VRC_SceneResetPosition" ,
"VRCSDK2.VRC_SceneSmoothShift" ,
"VRCSDK2.VRC_SpecialLayer" ,
"VRCSDK2.VRC_Station" ,
"VRCSDK2.VRC_StereoObject" ,
"VRCSDK2.VRC_TimedEvents" ,
"VRCSDK2.VRC_Trigger" ,
"VRCSDK2.VRC_TriggerColliderEventTrigger" ,
"VRCSDK2.VRC_UseEvents" ,
"VRCSDK2.VRC_UiShape" ,
"UnityEngine.Animation" ,
#if ! UNITY_2019_4_OR_NEWER
"UnityEngine.GUIText" ,
"UnityEngine.GUITexture" ,
#endif
"UnityEngine.Video.VideoPlayer" ,
"PhysSound.PhysSoundBase" ,
"PhysSound.PhysSoundObject" ,
"PhysSound.PhysSoundTempAudio" ,
"PhysSound.PhysSoundTempAudioPool" ,
"PhysSound.PhysSoundTerrain" ,
"RealisticEyeMovements.EyeAndHeadAnimator" ,
"RealisticEyeMovements.LookTargetController" ,
"UnityStandardAssets.Cameras.AbstractTargetFollower" ,
"UnityStandardAssets.Cameras.AutoCam" ,
"UnityStandardAssets.Cameras.FreeLookCam" ,
"UnityStandardAssets.Cameras.HandHeldCam" ,
"UnityStandardAssets.Cameras.LookatTarget" ,
"UnityStandardAssets.Cameras.PivotBasedCameraRig" ,
"UnityStandardAssets.Cameras.ProtectCameraFromWallClip" ,
"UnityStandardAssets.Cameras.TargetFieldOfView" ,
"UnityStandardAssets.Characters.FirstPerson.FirstPersonController" ,
"UnityStandardAssets.Characters.FirstPerson.HeadBob" ,
"UnityStandardAssets.Characters.FirstPerson.RigidbodyFirstPersonController" ,
"UnityStandardAssets.Vehicles.Ball.Ball" ,
"UnityStandardAssets.Vehicles.Ball.BallUserControl" ,
"UnityStandardAssets.Characters.ThirdPerson.AICharacterControl" ,
"UnityStandardAssets.Characters.ThirdPerson.ThirdPersonCharacter" ,
"UnityStandardAssets.Characters.ThirdPerson.ThirdPersonUserControl" ,
"UnityStandardAssets.CrossPlatformInput.AxisTouchButton" ,
"UnityStandardAssets.CrossPlatformInput.ButtonHandler" ,
"UnityStandardAssets.CrossPlatformInput.InputAxisScrollbar" ,
"UnityStandardAssets.CrossPlatformInput.Joystick" ,
"UnityStandardAssets.CrossPlatformInput.MobileControlRig" ,
"UnityStandardAssets.CrossPlatformInput.TiltInput" ,
"UnityStandardAssets.CrossPlatformInput.TouchPad" ,
"UnityStandardAssets.Effects.AfterburnerPhysicsForce" ,
"UnityStandardAssets.Effects.ExplosionFireAndDebris" ,
"UnityStandardAssets.Effects.ExplosionPhysicsForce" ,
"UnityStandardAssets.Effects.Explosive" ,
"UnityStandardAssets.Effects.ExtinguishableParticleSystem" ,
"UnityStandardAssets.Effects.FireLight" ,
"UnityStandardAssets.Effects.Hose" ,
"UnityStandardAssets.Effects.ParticleSystemMultiplier" ,
"UnityStandardAssets.Effects.SmokeParticles" ,
"UnityStandardAssets.Effects.WaterHoseParticles" ,
"UnityStandardAssets.Utility.ActivateTrigger" ,
"UnityStandardAssets.Utility.AutoMoveAndRotate" ,
"UnityStandardAssets.Utility.DragRigidbody" ,
"UnityStandardAssets.Utility.DynamicShadowSettings" ,
"UnityStandardAssets.Utility.FollowTarget" ,
"UnityStandardAssets.Utility.FPSCounter" ,
"UnityStandardAssets.Utility.ObjectResetter" ,
"UnityStandardAssets.Utility.ParticleSystemDestroyer" ,
#if ! UNITY_2019_4_OR_NEWER
"UnityStandardAssets.Utility.SimpleActivatorMenu" ,
#endif
"UnityStandardAssets.Utility.SimpleMouseRotator" ,
"UnityStandardAssets.Utility.SmoothFollow" ,
"UnityStandardAssets.Utility.TimedObjectActivator" ,
"UnityStandardAssets.Utility.TimedObjectDestructor" ,
"UnityStandardAssets.Utility.WaypointCircuit" ,
"UnityStandardAssets.Utility.WaypointProgressTracker" ,
"UnityStandardAssets.Vehicles.Aeroplane.AeroplaneAiControl" ,
"UnityStandardAssets.Vehicles.Aeroplane.AeroplaneAudio" ,
"UnityStandardAssets.Vehicles.Aeroplane.AeroplaneController" ,
"UnityStandardAssets.Vehicles.Aeroplane.AeroplaneControlSurfaceAnimator" ,
"UnityStandardAssets.Vehicles.Aeroplane.AeroplanePropellerAnimator" ,
"UnityStandardAssets.Vehicles.Aeroplane.AeroplaneUserControl2Axis" ,
"UnityStandardAssets.Vehicles.Aeroplane.AeroplaneUserControl4Axis" ,
"UnityStandardAssets.Vehicles.Aeroplane.JetParticleEffect" ,
"UnityStandardAssets.Vehicles.Aeroplane.LandingGear" ,
"UnityStandardAssets.Vehicles.Car.BrakeLight" ,
"UnityStandardAssets.Vehicles.Car.CarAIControl" ,
"UnityStandardAssets.Vehicles.Car.CarAudio" ,
"UnityStandardAssets.Vehicles.Car.CarController" ,
"UnityStandardAssets.Vehicles.Car.CarSelfRighting" ,
"UnityStandardAssets.Vehicles.Car.CarUserControl" ,
"UnityStandardAssets.Vehicles.Car.Mudguard" ,
"UnityStandardAssets.Vehicles.Car.SkidTrail" ,
"UnityStandardAssets.Vehicles.Car.Suspension" ,
"UnityStandardAssets.Vehicles.Car.WheelEffects" ,
"RenderHeads.Media.AVProVideo.ApplyToMaterial" ,
"RenderHeads.Media.AVProVideo.ApplyToMesh" ,
"RenderHeads.Media.AVProVideo.AudioOutput" ,
"RenderHeads.Media.AVProVideo.DisplayIMGUI" ,
"RenderHeads.Media.AVProVideo.DisplayUGUI" ,
"RenderHeads.Media.AVProVideo.MediaPlayer" ,
"RenderHeads.Media.AVProVideo.SubtitlesUGUI" ,
"AlphaButtonClickMask" ,
"EventSystemChecker"
} ;
static readonly string [ ] ComponentTypeWhiteListSdk3 = new string [ ]
{
"VRC.SDK3.VRCDestructibleStandard" ,
"VRC.SDK3.Components.VRCVisualDamage" ,
"VRC.SDK3.Components.VRCAvatarPedestal" ,
"VRC.SDK3.Components.VRCPickup" ,
"VRC.SDK3.Components.VRCPortalMarker" ,
"VRC.SDK3.Components.VRCSpatialAudioSource" ,
"VRC.SDK3.Components.VRCMirrorReflection" ,
"VRC.SDK3.Components.VRCSceneDescriptor" ,
"VRC.SDK3.Components.VRCStation" ,
"VRC.SDK3.Components.VRCUiShape" ,
"VRC.SDK3.Components.VRCObjectSync" ,
"VRC.SDK3.Components.VRCObjectPool" ,
"VRC.SDK3.Components.VRCInputFieldKeyboardOverride" ,
#if VRC_ENABLE_PLAYER_PERSISTENCE
"VRC.SDK3.Components.VRCPlayerObject" ,
#endif
#if VRC_ENABLE_PLAYER_PERSISTENCE | | VRC_ENABLE_INSTANCE_PERSISTENCE
"VRC.SDK3.Components.VRCEnablePersistence" ,
#endif
"VRC.SDK3.Video.Components.VRCUnityVideoPlayer" ,
"VRC.SDK3.Video.Components.AVPro.VRCAVProVideoPlayer" ,
"VRC.SDK3.Video.Components.AVPro.VRCAVProVideoScreen" ,
"VRC.SDK3.Video.Components.AVPro.VRCAVProVideoSpeaker" ,
"VRC.SDK3.Midi.VRCMidiListener" ,
"VRC.SDK3.Midi.VRCMidiPlayer" ,
"VRC.SDK3.Components.VRCCameraDollyAnimation" ,
"VRC.SDK3.Components.VRCCameraDollyPath" ,
"VRC.SDK3.Components.VRCCameraDollyPathPoint" ,
"VRC.Udon.UdonBehaviour" ,
"VRC.Udon.AbstractUdonBehaviourEventProxy" ,
"VRC.SDK3.Dynamics.PhysBone.Components.VRCPhysBone" ,
"VRC.SDK3.Dynamics.PhysBone.Components.VRCPhysBoneCollider" ,
"VRC.SDK3.Dynamics.PhysBone.Components.VRCPhysBoneRoot" ,
"VRC.SDK3.Dynamics.Constraint.Components.VRCAimConstraint" ,
"VRC.SDK3.Dynamics.Constraint.Components.VRCLookAtConstraint" ,
"VRC.SDK3.Dynamics.Constraint.Components.VRCParentConstraint" ,
"VRC.SDK3.Dynamics.Constraint.Components.VRCPositionConstraint" ,
"VRC.SDK3.Dynamics.Constraint.Components.VRCRotationConstraint" ,
"VRC.SDK3.Dynamics.Constraint.Components.VRCScaleConstraint" ,
"VRC.SDK3.Dynamics.Contact.Components.VRCContactSender" ,
"VRC.SDK3.Dynamics.Contact.Components.VRCContactReceiver" ,
"UnityEngine.Animations.AimConstraint" ,
"UnityEngine.Animations.LookAtConstraint" ,
"UnityEngine.Animations.ParentConstraint" ,
"UnityEngine.Animations.PositionConstraint" ,
"UnityEngine.Animations.RotationConstraint" ,
"UnityEngine.Animations.ScaleConstraint" ,
"UnityEngine.ParticleSystemForceField" ,
"Unity.AI.Navigation.NavMeshSurface" ,
"Unity.AI.Navigation.NavMeshLink" ,
"Unity.AI.Navigation.NavMeshModifier" ,
"Unity.AI.Navigation.NavMeshModifierVolume" ,
"Cinemachine.Cinemachine3rdPersonAim" ,
"Cinemachine.CinemachineBlendListCamera" ,
"Cinemachine.CinemachineBrain" ,
"Cinemachine.CinemachineCameraOffset" ,
"Cinemachine.CinemachineClearShot" ,
"Cinemachine.CinemachineCollider" ,
"Cinemachine.CinemachineConfiner" ,
"Cinemachine.CinemachineDollyCart" ,
"Cinemachine.CinemachineExternalCamera" ,
"Cinemachine.CinemachineFollowZoom" ,
"Cinemachine.CinemachineFreeLook" ,
"Cinemachine.CinemachineMixingCamera" ,
"Cinemachine.CinemachinePath" ,
"Cinemachine.CinemachinePipeline" ,
"Cinemachine.CinemachinePixelPerfect" ,
"Cinemachine.CinemachineRecomposer" ,
"Cinemachine.CinemachineSmoothPath" ,
"Cinemachine.CinemachineStateDrivenCamera" ,
"Cinemachine.CinemachineStoryboard" ,
"Cinemachine.CinemachineTargetGroup" ,
"Cinemachine.CinemachineVirtualCamera" ,
"Cinemachine.Cinemachine3rdPersonFollow" ,
"Cinemachine.CinemachineBasicMultiChannelPerlin" ,
"Cinemachine.CinemachineComposer" ,
"Cinemachine.CinemachineFramingTransposer" ,
"Cinemachine.CinemachineGroupComposer" ,
"Cinemachine.CinemachineHardLockToTarget" ,
"Cinemachine.CinemachineHardLookAt" ,
"Cinemachine.CinemachineOrbitalTransposer" ,
"Cinemachine.CinemachinePOV" ,
"Cinemachine.CinemachineSameAsFollowTarget" ,
"Cinemachine.CinemachineTrackedDolly" ,
"Cinemachine.CinemachineTransposer" ,
"Cinemachine.CinemachineCore" ,
} ;
public static readonly string [ ] ShaderWhiteList = new string [ ]
{
"VRChat/Mobile/Standard Lite" ,
"VRChat/Mobile/Diffuse" ,
"VRChat/Mobile/Bumped Diffuse" ,
"VRChat/Mobile/Bumped Mapped Specular" ,
"VRChat/Mobile/Toon Lit" ,
"VRChat/Mobile/MatCap Lit" ,
"VRChat/Mobile/Lightmapped" ,
"VRChat/Mobile/Skybox" ,
"VRChat/Mobile/Particles/Additive" ,
"VRChat/Mobile/Particles/Multiply" ,
"VRChat/Mobile/World/Supersampled UI" ,
"FX/MirrorReflection" ,
"UI/Default" ,
} ;
private static readonly HashSet < int > scannedObjects = new HashSet < int > ( ) ;
private static void ConfigureWhiteList ( WhiteListConfiguration config )
{
if ( ComponentTypeWhiteListConfiguration = = config | |
config = = WhiteListConfiguration . Unchanged )
{
return ;
}
List < string > concatenation = new List < string > ( ) ;
concatenation . AddRange ( ComponentTypeWhiteListCommon ) ;
switch ( config )
{
case WhiteListConfiguration . VRCSDK2 :
concatenation . AddRange ( ComponentTypeWhiteListSdk2 ) ;
break ;
case WhiteListConfiguration . VRCSDK3 :
concatenation . AddRange ( ComponentTypeWhiteListSdk3 ) ;
break ;
}
ComponentTypeWhiteListConfiguration = config ;
ComponentTypeWhiteList = concatenation . ToArray ( ) ;
}
[PublicAPI]
public static void RemoveIllegalComponents ( List < GameObject > targets , WhiteListConfiguration config , bool retry = true , HashSet < Type > tagWhitelistedTypes = null )
{
ConfigureWhiteList ( config ) ;
HashSet < Type > whitelist = ValidationUtils . WhitelistedTypes ( $"world{config}" , ComponentTypeWhiteList ) ;
// combine whitelist types from world tags with cached whitelist
tagWhitelistedTypes ? . UnionWith ( whitelist ) ;
foreach ( GameObject target in targets )
{
#if VRC_CLIENT
ValidationUtils . RemoveIllegalComponents ( target , tagWhitelistedTypes ? ? whitelist , retry , true ) ;
#else
ValidationUtils . RemoveIllegalComponents ( target , tagWhitelistedTypes ? ? whitelist , retry , true , excludeEditorOnly : true , allowRemovingAssets : false ) ;
#endif
SecurityScan ( target ) ;
AddScanned ( target ) ;
// Must be called after AddScanned to avoid infinite recursion.
ScanDropdownTemplates ( target , whitelist , config = = WhiteListConfiguration . VRCSDK3 ) ;
}
}
private static void AddScanned ( GameObject obj )
{
if ( obj = = null )
return ;
if ( ! scannedObjects . Contains ( obj . GetInstanceID ( ) ) )
scannedObjects . Add ( obj . GetInstanceID ( ) ) ;
for ( int idx = 0 ; idx < obj . transform . childCount ; + + idx )
AddScanned ( obj . transform . GetChild ( idx ) ? . gameObject ) ;
}
private static bool WasScanned ( GameObject obj )
{
return scannedObjects . Contains ( obj . GetInstanceID ( ) ) ;
}
[PublicAPI]
public static void ScanGameObject ( GameObject target , WhiteListConfiguration config )
{
if ( WasScanned ( target ) )
{
return ;
}
ConfigureWhiteList ( config ) ;
HashSet < Type > whitelist = ValidationUtils . WhitelistedTypes ( "world" + config , ComponentTypeWhiteList ) ;
ScanGameObject ( target , whitelist , config = = WhiteListConfiguration . VRCSDK3 ) ;
}
private static void ScanGameObject ( GameObject target , HashSet < Type > whitelist , bool isSDK3 )
{
if ( WasScanned ( target ) )
{
return ;
}
#if VRC_CLIENT
ValidationUtils . RemoveIllegalComponents ( target , whitelist ) ;
#else
ValidationUtils . RemoveIllegalComponents ( target , whitelist , excludeEditorOnly : true , allowRemovingAssets : false ) ;
#endif
SecurityScan ( target ) ;
#if VRC_CLIENT & & UDON
if ( isSDK3 )
{
Core . UnityEventFilter . FilterEvents ( target ) ;
}
#endif
AddScanned ( target ) ;
// Must be called after AddScanned to avoid infinite recursion.
ScanDropdownTemplates ( target , whitelist , isSDK3 ) ;
}
[PublicAPI]
public static void ClearScannedGameObjectCache ( )
{
scannedObjects . Clear ( ) ;
}
[PublicAPI]
public static IEnumerable < Shader > FindIllegalShaders ( GameObject target )
{
return ValidationUtils . FindIllegalShaders ( target , ShaderWhiteList ) ;
}
private static void SecurityScan ( GameObject target )
{
PlayableDirector [ ] playableDirectors = target . GetComponentsInChildren < PlayableDirector > ( true ) ;
foreach ( PlayableDirector playableDirector in playableDirectors )
{
StripPlayableDirectorWithPrefabs ( playableDirector ) ;
}
UnityEngine . Video . VideoPlayer [ ] videoPlayers = target . GetComponentsInChildren < UnityEngine . Video . VideoPlayer > ( true ) ;
foreach ( UnityEngine . Video . VideoPlayer videoPlayer in videoPlayers )
{
AddAudioSourceToVideoPlayer ( videoPlayer ) ;
}
}
private static void ScanDropdownTemplates ( GameObject target , HashSet < Type > whitelist , bool isSDK3 )
{
Dropdown [ ] dropdowns = target . GetComponentsInChildren < Dropdown > ( true ) ;
foreach ( Dropdown dropdown in dropdowns )
{
if ( dropdown = = null )
{
continue ;
}
RectTransform dropdownTemplate = dropdown . template ;
if ( dropdownTemplate = = null )
{
continue ;
}
ScanGameObject ( dropdownTemplate . transform . root . gameObject , whitelist , isSDK3 ) ;
}
#if TextMeshPro
TMP_Dropdown [ ] tmpDropdowns = target . GetComponentsInChildren < TMP_Dropdown > ( true ) ;
foreach ( TMP_Dropdown textMeshProDropdown in tmpDropdowns )
{
if ( textMeshProDropdown = = null )
{
continue ;
}
RectTransform dropdownTemplate = textMeshProDropdown . template ;
if ( dropdownTemplate = = null )
{
continue ;
}
ScanGameObject ( dropdownTemplate . transform . root . gameObject , whitelist , isSDK3 ) ;
}
#endif
}
private static void StripPlayableDirectorWithPrefabs ( PlayableDirector playableDirector )
{
if ( ! ( playableDirector . playableAsset is UnityEngine . Timeline . TimelineAsset timelineAsset ) )
return ;
var tracks = timelineAsset . GetOutputTracks ( ) . Concat ( timelineAsset . GetRootTracks ( ) ) ;
foreach ( TrackAsset track in tracks )
{
if ( ! ( track is ControlTrack ) )
continue ;
IEnumerable < TimelineClip > clips = track . GetClips ( ) ;
foreach ( TimelineClip clip in clips )
{
if ( clip . asset is ControlPlayableAsset controlPlayableAsset & & controlPlayableAsset . prefabGameObject ! = null )
{
UnityEngine . Object . Destroy ( playableDirector ) ;
VRC . Core . Logger . LogWarning ( "PlayableDirector containing prefab removed" , DebugCategoryName , playableDirector . gameObject ) ;
return ;
}
}
}
if ( ! playableDirector . playableGraph . IsValid ( ) )
return ;
var audioOutputCount = playableDirector . playableGraph . GetOutputCountByType < AudioPlayableOutput > ( ) ;
for ( int i = 0 ; i < audioOutputCount ; i + + )
{
var output = ( AudioPlayableOutput ) playableDirector . playableGraph . GetOutputByType < AudioPlayableOutput > ( i ) ;
if ( ! output . IsOutputValid ( ) ) continue ;
if ( output . GetTarget ( ) = = null )
{
// AudioPlayableOutput without a target source will bypass client volume controls.
VRC . Core . Logger . LogWarning ( "Fixing up AudioPlayableOutput without a target source." , DebugCategoryName , playableDirector . gameObject ) ;
var addedObj = new GameObject ( "AudioSource_For_" + playableDirector . name ) ;
var addedSrc = addedObj . AddComponent < AudioSource > ( ) ;
addedSrc . spatialize = false ;
addedSrc . bypassEffects = true ;
addedSrc . bypassListenerEffects = true ;
addedSrc . bypassReverbZones = true ;
addedSrc . spatialBlend = 0.0f ;
addedSrc . dopplerLevel = 0.0f ;
addedSrc . rolloffMode = AudioRolloffMode . Custom ;
addedSrc . SetCustomCurve ( AudioSourceCurveType . CustomRolloff , AnimationCurve . Constant ( 0 , 1 , 1 ) ) ;
#if VRC_CLIENT
addedSrc . outputAudioMixerGroup = VRCAudioManager . GetGameGroup ( ) ;
#endif
output . SetTarget ( addedSrc ) ;
}
}
}
private static void AddAudioSourceToVideoPlayer ( UnityEngine . Video . VideoPlayer videoPlayer )
{
// VideoPlayer objects with output mode set to "Direct" bypass client volume controls.
if ( videoPlayer . audioOutputMode = = UnityEngine . Video . VideoAudioOutputMode . Direct )
{
//if playback is happening (or will) you have to Stop() before you attach an AudioSource.
bool play_state = ( videoPlayer . isPlaying | | videoPlayer . playOnAwake ) ;
if ( play_state )
{
videoPlayer . Stop ( ) ;
}
AudioSource vp_src = videoPlayer . gameObject . AddComponent < AudioSource > ( ) ;
videoPlayer . audioOutputMode = UnityEngine . Video . VideoAudioOutputMode . AudioSource ;
for ( ushort i = 0 ; i < videoPlayer . audioTrackCount ; i + + )
{
videoPlayer . SetTargetAudioSource ( i , vp_src ) ;
}
if ( play_state )
{
videoPlayer . Play ( ) ;
}
VRC . Core . Logger . LogWarning ( "VideoPlayer using DIRECT audio output fixed." ) ;
}
}
}
}