public void SetVisibility(CollisionViewerParam p_visibilityParams)
 {
     if (m_collider != null)
     {
         bool t_isVisible = (p_visibilityParams & m_params) == m_params;
         gameObject.SetActive(t_isVisible);
         if (m_parentRenderer)
         {
             m_parentRenderer.enabled = !t_isVisible;
         }
     }
 }
    //TODO : Keep track of the renderer state (enable or not)
    //Instead of simply disabling it then re-enabling it
    //It could keep track if the collider it follow if it is disable-enable
    //We could set the reverse state for the renderer at the first script that run an Update
    //Then at the last script that run an Update, chech the state, and store it.
    //This way it could prevent some problem when entering shop/houses, etc

    //Create and initialize a CollisionFollower to a GameObject
    public static CollisionViewerFollower CreateAndAttachTo(GameObject p_gameObject, CollisionViewerParam p_params, Collider p_collider, MeshRenderer p_parentRenderer, CollisionViewerParam p_visibilityParams)
    {
        CollisionViewerFollower t_follower = p_gameObject.AddComponent <CollisionViewerFollower>();

        t_follower.m_params         = p_params;
        t_follower.m_collider       = p_collider;
        t_follower.m_parentRenderer = p_parentRenderer;

        //Extra for Capsule
        if (p_collider is CapsuleCollider)
        {
            t_follower.m_childCylinder   = p_gameObject.transform.GetChild(0).gameObject;
            t_follower.m_childSphereUp   = p_gameObject.transform.GetChild(1).gameObject;
            t_follower.m_childSphereDown = p_gameObject.transform.GetChild(2).gameObject;
        }

        t_follower.SetVisibility(p_visibilityParams);
        return(t_follower);
    }
    private void Start()
    {
        GameObject _CreatePrefab(string p_name, Mesh p_mesh)
        {
            GameObject t_gameObject = new GameObject(p_name);

            MeshRenderer t_renderer = t_gameObject.AddComponent <MeshRenderer>();

            t_renderer.enabled                   = true;
            t_renderer.shadowCastingMode         = UnityEngine.Rendering.ShadowCastingMode.Off;
            t_renderer.receiveShadows            = false;
            t_renderer.lightProbeUsage           = UnityEngine.Rendering.LightProbeUsage.Off;
            t_renderer.reflectionProbeUsage      = UnityEngine.Rendering.ReflectionProbeUsage.Off;
            t_renderer.allowOcclusionWhenDynamic = false;

            MeshFilter t_filter = t_gameObject.AddComponent <MeshFilter>();

            t_filter.mesh = p_mesh;

            return(t_gameObject);
        }

        //Initialize
        if (m_instance == null)
        {
            //This is now the singleton instance
            m_instance = this;

            //Settings Keys
            m_keyCodeEnable = KeyCode.R;

            m_keyCodeShowSolid   = KeyCode.T;
            m_keyCodeShowTrigger = KeyCode.Y;

            m_keyCodeShowCube    = KeyCode.None;    //None by default for now (but is supported)
            m_keyCodeShowCapsule = KeyCode.None;    //None by default for now (but is supported)
            m_keyCodeShowSphere  = KeyCode.None;    //None by default for now (but is supported)

            m_keyCodeOpacityUp   = KeyCode.F;
            m_keyCodeOpacityDown = KeyCode.G;

            //Settings Colors
            m_colorAlpha                   = 0.5f;
            m_colorCollisionSolid          = new Color(0f, 1f, 0f, m_colorAlpha);
            m_colorCollisionTrigger        = new Color(1f, 0f, 0f, m_colorAlpha);
            m_colorCollisionTriggerRespawn = new Color(0f, 0f, 1f, m_colorAlpha);

            //Toggles
            m_isEnable         = false;
            m_visibilityParams = CollisionViewerParam.ALL;

            //Shaders
            m_shaderTransparant = Shader.Find("Transparent/Diffuse");

            //Materials
            m_materialCollisionSolid                = new Material(m_shaderTransparant);
            m_materialCollisionSolid.color          = m_colorCollisionSolid;
            m_materialCollisionTrigger              = new Material(m_shaderTransparant);
            m_materialCollisionTrigger.color        = m_colorCollisionTrigger;
            m_materialCollisionTriggerRespawn       = new Material(m_shaderTransparant);
            m_materialCollisionTriggerRespawn.color = m_colorCollisionTriggerRespawn;

            //Meshes
            //Retreive Primitive Meshes (From Primitive Type)
            //NOTE : Not retreiving the Capsule mesh, since it ues 1 Cylinder and 1 Sphere instead
            //       Because if it use Capsule, when the object is scaled, it is wrong
            MeshFilter t_tempMeshFilter;
            GameObject t_cube = GameObject.CreatePrimitive(PrimitiveType.Cube);
            t_tempMeshFilter = t_cube.GetComponent <MeshFilter>();
            Mesh t_meshCube = (t_tempMeshFilter) ? t_tempMeshFilter.sharedMesh : null;

            GameObject t_cylinder = GameObject.CreatePrimitive(PrimitiveType.Cylinder);
            t_tempMeshFilter = t_cylinder.GetComponent <MeshFilter>();
            Mesh t_meshCylinder = (t_tempMeshFilter) ? t_tempMeshFilter.sharedMesh : null;

            GameObject t_sphere = GameObject.CreatePrimitive(PrimitiveType.Sphere);
            t_tempMeshFilter = t_sphere.GetComponent <MeshFilter>();
            Mesh t_meshSphere = (t_tempMeshFilter) ? t_tempMeshFilter.sharedMesh : null;

            Mesh t_meshCylinderWithoutTopBot = CreateCylinderMesh(20, 0.5f, 1f);
            Mesh t_meshShpereHalfUp          = CreateHalfSphereMesh(20, 10, 0.5f, true);
            Mesh t_meshShpereHalfDown        = CreateHalfSphereMesh(20, 10, 0.5f, false);

            //Destroy Primitive, no longer have a need to for those
            Destroy(t_cube);
            Destroy(t_cylinder);
            Destroy(t_sphere);

            //Prefabs
            GameObject t_gameObject = null;
            m_prefCube = _CreatePrefab(PREFIX_COLLISION_VIEWER_OBJECT_NAME + "Cube", t_meshCube);

            //Special Case for Capsule (Do 1 Cyllidner + 2 Sphere)
            m_prefCapsule = _CreatePrefab(PREFIX_COLLISION_VIEWER_OBJECT_NAME + "Capsule", null);
            t_gameObject  = _CreatePrefab(PREFIX_COLLISION_VIEWER_OBJECT_NAME + "CapsuleSubCylinder", t_meshCylinderWithoutTopBot);
            t_gameObject.transform.parent = m_prefCapsule.transform;
            t_gameObject = _CreatePrefab(PREFIX_COLLISION_VIEWER_OBJECT_NAME + "CapsuleSubSphereUp", t_meshShpereHalfUp);
            t_gameObject.transform.parent = m_prefCapsule.transform;
            t_gameObject = _CreatePrefab(PREFIX_COLLISION_VIEWER_OBJECT_NAME + "CapsuleSubSphereDown", t_meshShpereHalfDown);
            t_gameObject.transform.parent = m_prefCapsule.transform;

            m_prefCylinder = _CreatePrefab(PREFIX_COLLISION_VIEWER_OBJECT_NAME + "Cylinder", t_meshCylinder);
            m_prefSphere   = _CreatePrefab(PREFIX_COLLISION_VIEWER_OBJECT_NAME + "Sphere", t_meshSphere);

            //Special case, the mesh will be assigned depending of the mesh of the collider retreived
            m_prefPolygon = _CreatePrefab(PREFIX_COLLISION_VIEWER_OBJECT_NAME + "_Polygon", null);

            //Prefabs : Prevent destruction on load of new scene and etc
            DontDestroyOnLoad(m_prefCube);
            DontDestroyOnLoad(m_prefCapsule);
            DontDestroyOnLoad(m_prefCylinder);
            DontDestroyOnLoad(m_prefSphere);
            DontDestroyOnLoad(m_prefPolygon);

            //Prefabs : Disable
            m_prefCube.SetActive(false);
            m_prefCapsule.SetActive(false);
            m_prefCylinder.SetActive(false);
            m_prefSphere.SetActive(false);
            m_prefPolygon.SetActive(false);

            //CollisionViewerFollower List
            m_followers = new List <CollisionViewerFollower>();
        }
        else if (this != m_instance)
        {
            Destroy(this);
        }
    }
    void Update()
    {
        //Toggle for enable/disable CollisionViewer
        if (Input.GetKeyDown(m_keyCodeEnable))
        {
            m_isEnable = !m_isEnable;
            CollisionViewerParam t_params = m_isEnable ? m_visibilityParams : CollisionViewerParam.NONE;
            //Cleanup null entry just in case
            m_followers.RemoveAll(x => x == null);
            for (int i = 0; i < m_followers.Count; ++i)
            {
                m_followers[i].SetVisibility(t_params);
                m_followers[i].gameObject.SetActive(m_isEnable);
            }
        }

        if (m_isEnable)
        {
            //Cleanup Follower to be safe
            //Since I do not know how ALL the game code works.
            //It is to prevent having millions of objects no longer used
            for (int i = 0; i < m_followers.Count; ++i)
            {
                if (m_followers[i] != null && m_followers[i].CanBeDestroy())
                {
                    Destroy(m_followers[i].gameObject);
                    m_followers[i] = null;
                }
            }
            m_followers.RemoveAll(x => x == null);

            //Check if colliders need a CollisionFollower
            Collider[] t_colliders = GameObject.FindObjectsOfType <Collider>();
            for (int i = 0; i < t_colliders.Length; ++i)
            {
                //Current collider
                Collider t_collider = t_colliders[i];

                //Check if there is already a CollisionFollower for this Collider
                if (m_followers.Find(x => x.FollowThisCollider(t_collider)) != null)
                {
                    continue;
                }

                //Reach here => Current Collider not already retreived, prepare it to add a CollisionFollower
                //Setup values
                GameObject           t_prefabUsed = null;
                Mesh                 t_meshFound  = null;
                CollisionViewerParam t_param      = CollisionViewerParam.NONE;

                //Retreive the Collider type
                //NOTE : Bug Fables does not seems to use any TerrainCollider, since it does not found the Class for it in dnSpy...?
                //Box Collider
                if (t_collider is BoxCollider)
                {
                    t_param     += (int)CollisionViewerParam.CUBE;
                    t_prefabUsed = m_prefCube;
                }
                //Capsule Collider
                else if (t_collider is CapsuleCollider)
                {
                    t_param     += (int)CollisionViewerParam.CAPSULE;
                    t_prefabUsed = m_prefCapsule;
                }
                //Sphere Collider
                else if (t_collider is SphereCollider)
                {
                    t_param     += (int)CollisionViewerParam.SPHERE;
                    t_prefabUsed = m_prefSphere;
                }
                //Mesh-Polygon Collider
                else if (t_collider is MeshCollider)
                {
                    t_param    += (int)CollisionViewerParam.POLYGON;
                    t_meshFound = ((MeshCollider)t_collider).sharedMesh;
                    if (t_meshFound != null)
                    {
                        t_prefabUsed = m_prefPolygon;
                    }
                }

                //If found, create a GameObject, and attach it a CollisionFollower for it
                if (t_prefabUsed != null)
                {
                    //Prepare the new object
                    GameObject t_child = Instantiate(t_prefabUsed);
                    t_child.SetActive(true);

                    //Extra instructions for Polygon type
                    if (t_prefabUsed == m_prefPolygon)
                    {
                        t_child.GetComponent <MeshFilter>().mesh = t_meshFound;
                    }

                    //Ajust transform values
                    {
                        t_child.transform.position = t_collider.transform.position;
                        t_child.transform.rotation = t_collider.transform.rotation;
                        t_child.transform.parent   = t_collider.transform;
                        //Correcting scale (You CAN'T simply do t_child.transform.localScale = new Vector3(1f,1f,1f);
                        Vector3 scale = t_child.transform.localScale;
                        scale.Set(1f, 1f, 1f);
                        t_child.transform.localScale = scale;
                    }

                    //Change Material depending if is a Trigger or a Solid Collider
                    {
                        Material t_material = null;
                        if (t_collider.isTrigger)
                        {
                            if (t_collider.CompareTag("Respawn"))
                            {
                                t_material = m_materialCollisionTriggerRespawn;
                            }
                            else
                            {
                                t_material = m_materialCollisionTrigger;
                            }
                            t_param += (int)CollisionViewerParam.TRIGGER;
                        }
                        else
                        {
                            t_material = m_materialCollisionSolid;
                            t_param   += (int)CollisionViewerParam.SOLID;
                        }
                        t_child.GetComponent <MeshRenderer>().material = t_material;
                        //Extra instructions for Capsule (Because 1 Cylinder, 2 Spheres)
                        if (t_prefabUsed == m_prefCapsule)
                        {
                            t_child.transform.GetChild(0).GetComponent <MeshRenderer>().material = t_material;
                            t_child.transform.GetChild(1).GetComponent <MeshRenderer>().material = t_material;
                            t_child.transform.GetChild(2).GetComponent <MeshRenderer>().material = t_material;
                        }
                    }

                    //Attempt to evaluate what category this collider is used for
                    //Checking stuff like : tag name, object name, MonoBehaviour script type attached to it, etc!
                    {
                        //TODO : TEST
                        //Camera Limiter
                        if (t_collider.GetComponent <CamLimiter>() != null)
                        {
                            t_param += (int)CollisionViewerParam.CAMERA_MANIPULATION;
                        }
                        //TODO : TEST
                        //Fake Wall
                        else if (t_collider.GetComponent <FakeWall>() != null)
                        {
                            t_param += (int)CollisionViewerParam.FAKE_WALL;
                        }
                        //TODO : TEST
                        //Stealth (Thief / Wasp stealth?)
                        else if (t_collider.GetComponent <StealthCheck>() != null)
                        {
                            t_param += (int)CollisionViewerParam.STEALTH_CHECK;
                        }
                        //TODO : TEST
                        //Respawn location
                        //Reference : Is used in the script : PlayerControl
                        else if (t_collider.CompareTag("Respawn"))
                        {
                            t_param += (int)CollisionViewerParam.RESPAWN_LOCATION;
                        }
                        //Default
                        else
                        {
                            t_param += (int)CollisionViewerParam.UNKNOWN_OR_DEFAULT_CATEGORY;
                        }
                    }

                    //Attempt to get parent Renderer (So we can disable the graphics related to this collision)
                    //TODO : To fix for some objects, maybe later, it is good enough for now
                    MeshRenderer t_parentRenderer = null;
                    {
                        t_parentRenderer = t_colliders[i].GetComponent <MeshRenderer>();
                    }

                    //Create a CollisionViewerFollower and Add to the list
                    m_followers.Add(CollisionViewerFollower.CreateAndAttachTo(t_child, t_param, t_collider, t_parentRenderer, m_visibilityParams));
                }
            }

            //Check for Visibility Change
            CollisionViewerParam t_visibilityParams = CollisionViewerParam.NONE;
            t_visibilityParams ^= Input.GetKeyDown(m_keyCodeShowSolid) ? CollisionViewerParam.SOLID : CollisionViewerParam.NONE;
            t_visibilityParams ^= Input.GetKeyDown(m_keyCodeShowTrigger) ? CollisionViewerParam.TRIGGER : CollisionViewerParam.NONE;
            t_visibilityParams ^= Input.GetKeyDown(m_keyCodeShowCube) ? CollisionViewerParam.CUBE : CollisionViewerParam.NONE;
            t_visibilityParams ^= Input.GetKeyDown(m_keyCodeShowCapsule) ? CollisionViewerParam.CAPSULE : CollisionViewerParam.NONE;
            t_visibilityParams ^= Input.GetKeyDown(m_keyCodeShowSphere) ? CollisionViewerParam.SPHERE : CollisionViewerParam.NONE;
            //If it changed, update all Follower visibility
            if (t_visibilityParams != CollisionViewerParam.NONE)
            {
                m_visibilityParams ^= t_visibilityParams;
                for (int i = 0; i < m_followers.Count; ++i)
                {
                    m_followers[i].SetVisibility(m_visibilityParams);
                }
            }

            //Check for Opacity Change
            int t_opacityChange = 0;
            if (Input.GetKey(m_keyCodeOpacityUp))
            {
                ++t_opacityChange;
            }
            if (Input.GetKey(m_keyCodeOpacityDown))
            {
                --t_opacityChange;
            }
            //If it changed, update alpha
            if (t_opacityChange != 0)
            {
                SetColorAlpha(m_colorAlpha + (t_opacityChange * 0.02f));
            }

            //Update the CollisionFollower
            for (int i = 0; i < m_followers.Count; ++i)
            {
                m_followers[i].ManualUpdate();
            }
        }
    }