﻿using System;
using System.Collections.Generic;
using JetBrains.Annotations;
using UnityEngine;

namespace VRCSDK2.Validation
{
    public static class WorldValidation
    {
        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",
            "RenderHeads.Media.AVProVideo.ApplyToMaterial",
            "RenderHeads.Media.AVProVideo.ApplyToMesh",
            "RenderHeads.Media.AVProVideo.AudioOutput",
            "RenderHeads.Media.AVProVideo.CubemapCube",
            "RenderHeads.Media.AVProVideo.DebugOverlay",
            "RenderHeads.Media.AVProVideo.DisplayBackground",
            "RenderHeads.Media.AVProVideo.DisplayIMGUI",
            "RenderHeads.Media.AVProVideo.DisplayUGUI",
            "RenderHeads.Media.AVProVideo.MediaPlayer",
            "RenderHeads.Media.AVProVideo.StreamParser",
            "RenderHeads.Media.AVProVideo.SubtitlesUGUI",
            "RenderHeads.Media.AVProVideo.UpdateStereoMaterial",
            "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.BehaviourAnimatedStagger",
            "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.Video.VideoPlayer",
            "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.Playables.PlayableDirector",
            "UnityEngine.TerrainCollider",
            "UnityEngine.Canvas",
            "UnityEngine.CanvasGroup",
            "UnityEngine.CanvasRenderer",
            "UnityEngine.TextMesh",
            "UnityEngine.Animator",
            "UnityEngine.AI.NavMeshAgent",
            "UnityEngine.AI.NavMeshObstacle",
            "UnityEngine.AI.OffMeshLink",
            "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",
            "VirtualMarketplaceItem",
        };

        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_MirrorCamera",
            "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",
            "UnityEngine.GUIText",
            "UnityEngine.GUITexture",
            "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",
            "UnityStandardAssets.Utility.SimpleActivatorMenu",
            "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",
            "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.Udon.UdonBehaviour",
            "UnityEngine.Animations.AimConstraint",
            "UnityEngine.Animations.LookAtConstraint",
            "UnityEngine.Animations.ParentConstraint",
            "UnityEngine.Animations.PositionConstraint",
            "UnityEngine.Animations.RotationConstraint",
            "UnityEngine.Animations.ScaleConstraint",
            "UnityEngine.ParticleSystemForceField",
        };

        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",
            "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(IEnumerable<GameObject> targets, WhiteListConfiguration config, bool retry = true)
        {
            ConfigureWhiteList(config);
            HashSet<Type> whitelist = ValidationUtils.WhitelistedTypes("world" + config, ComponentTypeWhiteList);
            foreach(GameObject target in targets)
            {
                ValidationUtils.RemoveIllegalComponents(target, whitelist, retry, true);
                AddScanned(target);
            }
        }

        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", ComponentTypeWhiteList);
            ValidationUtils.RemoveIllegalComponents(target, whitelist);

            AddScanned(target);
        }

        [PublicAPI]
        public static void ClearScannedGameObjectCache()
        {
            scannedObjects.Clear();
        }

        [PublicAPI]
        public static IEnumerable<Shader> FindIllegalShaders(GameObject target)
        {
            return ShaderValidation.FindIllegalShaders(target, ShaderWhiteList);
        }
    }
}
