//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);
    }
    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();
            }
        }
    }