/*
    * SHARED
    */
    //>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>FIXED UPDATE
    private void FixedUpdate() {
        float speed = 0f;

        //If this is running at the local player (client with authoritative control or host client)
        //We run normal FPS controller (prediction)
        if(isLocalPlayer) {
            //This must be before move to check if move grounded the character
            m_PreviouslyGrounded = m_CharacterController.isGrounded;

            currentStamp = Network.time;
            //Store crouch input to send to server
            //We do this before reading input so that we can compare with the current crouch state
            bool sendCrouch = m_isCrouching;

            //Input from user or simulated
            if(inputSimulation) {
                SimInput(out speed);
            }
            else {
                GetInput(out speed);
            }

            //Store jump input to send to server
            //We need to store this here because player movement will clear m_Jump
            bool sendJump = m_Jump;

            // Store transform values
            //This is also used for the host to know if it moved to send change messages
            Vector3 prevPosition = transform.position;
            Quaternion prevRotation = transform.rotation;

            // Store collision values
            CollisionFlags lastFlag = m_CollisionFlags;

            //If we have predicion, we use the input here to move the character
            if(prediction) {
                //Move the player object
                PlayerMovement(speed);
            }

            //Client sound and camera
            ProgressStepCycle(speed);

            if(!m_PreviouslyGrounded && m_CharacterController.isGrounded) {
                StartCoroutine(m_JumpBob.DoBobCycle());
                PlayLandingSound();
            }

            //OWNER CLIENTS THAT ARE NOT THE HOST
            //CLIENTS THAT ARE NOT THE SERVER
            if(!isServer) {
                bool crouchChange = m_isCrouching != sendCrouch;
                bool moved = Vector3.Distance(prevPosition, transform.position) > 0 || m_Input[0] || m_Input[1]
                    || m_Input[2] || m_Input[3];
                if(moved || sendJump || crouchChange || rotationChanged) {
                    //Store all inputs generated between msgs to send to server
                    Inputs inputs = new Inputs();
                    inputs.yaw = transform.rotation.eulerAngles.y;
                    inputs.pitch = m_firstPersonCharacter.rotation.eulerAngles.x;
                    inputs.wasd = m_Input;
                    inputs.move = moved;
                    inputs.walk = m_IsWalking;
                    inputs.rotate = rotationChanged;
                    inputs.jump = sendJump;
                    inputs.crouch = m_isCrouching;
                    inputs.timeStamp = currentStamp;
                    inputsList.Enqueue(inputs);
                    debugMovement dePos = new debugMovement();

                    // DEBUG POSITION
                    dePos.velocity = m_CharacterController.velocity;
                    dePos.position = transform.position;
                    debugClientPos.Enqueue(dePos);

                    //If we moved, then we need to store reconciliation
                    if(moved || sendJump || crouchChange) {
                        // Create reconciliation entry
                        ReconciliationEntry entry = new ReconciliationEntry();
                        entry.inputs = inputs;
                        entry.lastFlags = lastFlag;
                        entry.position = prevPosition;
                        entry.rotationYaw = transform.rotation.eulerAngles.y;
                        entry.grounded = m_PreviouslyGrounded;
                        entry.prevCrouching = m_PreviouslyCrouching;
                        AddReconciliation(entry);
                    }

                    //Clear the jump to send
                    sendJump = false;

                    //Clear rotation flag
                    rotationChanged = false;
                    
                }
            }

            //HOST CLIENT
            if (isServer) {
                if(Vector3.Distance(transform.position, prevPosition) > 0 || rotationChanged) {
                    movementToSend = true;
                }
            }

            //Thread.Sleep(7);
        }
        /*
        * SERVER SIDE
        */
        else { //If we are on the server, we process commands from the client instead, and generate update messages
            if(isServer) {
                //Thread.Sleep(7);
                //Store state
                Vector3 lastPosition = transform.position;
                Quaternion lastCharacterRotation = transform.rotation;
                Quaternion lastCameraRotation = m_firstPersonCharacter.rotation;

                //Create the struct to read possible input to calculate
                Inputs inputs;
                inputs.rotate = false;

                //If we have inputs, get them and simulate on the server
                if(inputsList.Count > 0) {
                    while(inputsList.Count > 0) {
                        inputs = inputsList.Dequeue();

                        m_IsWalking = inputs.walk;
                        m_Input = inputs.wasd;
                        m_isCrouching = inputs.crouch;
                        m_Jump = inputs.jump;
                        currentStamp = inputs.timeStamp;

                        //If need to, apply rotation
                        if(inputs.rotate) {
                            transform.rotation = Quaternion.Euler(transform.rotation.x, inputs.yaw, transform.rotation.z);
                            m_firstPersonCharacter.rotation = Quaternion.Euler(inputs.pitch, m_firstPersonCharacter.rotation.eulerAngles.y, m_firstPersonCharacter.rotation.eulerAngles.z);
                        }

                        //If need to, simulate movement
                        if(inputs.move) {
                            //Server-side method to the speed out of input from clients
                            CalcSpeed(out speed);
                            //Move the player object
                            PlayerMovement(speed);
                        }

                        //Check if something changed and store
                        //This prevents movement skipping
                        if(Vector3.Distance(transform.position, lastPosition) > 0 || inputs.rotate) {
                            movementToSend = true;
                        }

                    }
                }

                m_PreviouslyGrounded = m_CharacterController.isGrounded;
            }
        }
    }
    /*
     * SHARED
     */
    //>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>FIXED UPDATE
    private void FixedUpdate()
    {
        float speed = 0f;

        //If this is running at the local player (client with authoritative control or host client)
        //We run normal FPS controller (prediction)
        if (isLocalPlayer)
        {
            //This must be before move to check if move grounded the character
            m_PreviouslyGrounded = m_CharacterController.isGrounded;

            currentStamp = Network.time;
            //Store crouch input to send to server
            //We do this before reading input so that we can compare with the current crouch state
            bool sendCrouch = m_isCrouching;

            //Input from user or simulated
            if (inputSimulation)
            {
                SimInput(out speed);
            }
            else
            {
                GetInput(out speed);
            }

            //Store jump input to send to server
            //We need to store this here because player movement will clear m_Jump
            bool sendJump = m_Jump;

            // Store transform values
            //This is also used for the host to know if it moved to send change messages
            Vector3    prevPosition = transform.position;
            Quaternion prevRotation = transform.rotation;

            // Store collision values
            CollisionFlags lastFlag = m_CollisionFlags;

            //If we have predicion, we use the input here to move the character
            if (prediction)
            {
                //Move the player object
                PlayerMovement(speed);
            }

            //Client sound and camera
            ProgressStepCycle(speed);

            if (!m_PreviouslyGrounded && m_CharacterController.isGrounded)
            {
                StartCoroutine(m_JumpBob.DoBobCycle());
                PlayLandingSound();
            }

            //OWNER CLIENTS THAT ARE NOT THE HOST
            //CLIENTS THAT ARE NOT THE SERVER
            if (!isServer)
            {
                bool crouchChange = m_isCrouching != sendCrouch;
                bool moved        = Vector3.Distance(prevPosition, transform.position) > 0 || m_Input[0] || m_Input[1] ||
                                    m_Input[2] || m_Input[3];
                if (moved || sendJump || crouchChange || rotationChanged)
                {
                    //Store all inputs generated between msgs to send to server
                    Inputs inputs = new Inputs();
                    inputs.yaw       = transform.rotation.eulerAngles.y;
                    inputs.pitch     = m_firstPersonCharacter.rotation.eulerAngles.x;
                    inputs.wasd      = m_Input;
                    inputs.move      = moved;
                    inputs.walk      = m_IsWalking;
                    inputs.rotate    = rotationChanged;
                    inputs.jump      = sendJump;
                    inputs.crouch    = m_isCrouching;
                    inputs.timeStamp = currentStamp;
                    inputsList.Enqueue(inputs);
                    debugMovement dePos = new debugMovement();

                    // DEBUG POSITION
                    dePos.velocity = m_CharacterController.velocity;
                    dePos.position = transform.position;
                    debugClientPos.Enqueue(dePos);

                    //If we moved, then we need to store reconciliation
                    if (moved || sendJump || crouchChange)
                    {
                        // Create reconciliation entry
                        ReconciliationEntry entry = new ReconciliationEntry();
                        entry.inputs        = inputs;
                        entry.lastFlags     = lastFlag;
                        entry.position      = prevPosition;
                        entry.rotationYaw   = transform.rotation.eulerAngles.y;
                        entry.grounded      = m_PreviouslyGrounded;
                        entry.prevCrouching = m_PreviouslyCrouching;
                        AddReconciliation(entry);
                    }

                    //Clear the jump to send
                    sendJump = false;

                    //Clear rotation flag
                    rotationChanged = false;
                }
            }

            //HOST CLIENT
            if (isServer)
            {
                if (Vector3.Distance(transform.position, prevPosition) > 0 || rotationChanged)
                {
                    movementToSend = true;
                }
            }

            //Thread.Sleep(7);
        }

        /*
         * SERVER SIDE
         */
        else   //If we are on the server, we process commands from the client instead, and generate update messages
        {
            if (isServer)
            {
                //Thread.Sleep(7);
                //Store state
                Vector3    lastPosition          = transform.position;
                Quaternion lastCharacterRotation = transform.rotation;
                Quaternion lastCameraRotation    = m_firstPersonCharacter.rotation;

                //Create the struct to read possible input to calculate
                Inputs inputs;
                inputs.rotate = false;

                //If we have inputs, get them and simulate on the server
                if (inputsList.Count > 0)
                {
                    while (inputsList.Count > 0)
                    {
                        inputs = inputsList.Dequeue();

                        m_IsWalking   = inputs.walk;
                        m_Input       = inputs.wasd;
                        m_isCrouching = inputs.crouch;
                        m_Jump        = inputs.jump;
                        currentStamp  = inputs.timeStamp;

                        //If need to, apply rotation
                        if (inputs.rotate)
                        {
                            transform.rotation = Quaternion.Euler(transform.rotation.x, inputs.yaw, transform.rotation.z);
                            m_firstPersonCharacter.rotation = Quaternion.Euler(inputs.pitch, m_firstPersonCharacter.rotation.eulerAngles.y, m_firstPersonCharacter.rotation.eulerAngles.z);
                        }

                        //If need to, simulate movement
                        if (inputs.move)
                        {
                            //Server-side method to the speed out of input from clients
                            CalcSpeed(out speed);
                            //Move the player object
                            PlayerMovement(speed);
                        }

                        //Check if something changed and store
                        //This prevents movement skipping
                        if (Vector3.Distance(transform.position, lastPosition) > 0 || inputs.rotate)
                        {
                            movementToSend = true;
                        }
                    }
                }

                m_PreviouslyGrounded = m_CharacterController.isGrounded;
            }
        }
    }