//Reconciliation methods
    private void AddReconciliation(ReconciliationEntry entry)
    {
        reconciliationList.Add(entry);

        //Limit the list size
        if (reconciliationList.Count > maxReconciliationEntries)
        {
            reconciliationList.RemoveAt(0);
        }
    }
    /*
    * 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;
            }
        }
    }
    //Reconciliation methods
    private void AddReconciliation(ReconciliationEntry entry) {
        reconciliationList.Add(entry);

        //Limit the list size
        if(reconciliationList.Count > maxReconciliationEntries)
            reconciliationList.RemoveAt(0);
    }
    private void RpcClientReceivePosition(double inputStamp, Vector3 pos, Vector3 movementVector)
    {
        if (reconciliation && isLocalPlayer) // RECONCILIATION for owner players
        //Check if this stamp is in the list
        {
            if (reconciliationList.Count == 0)
            {
                //Nothing to reconciliate, apply server position
                //Debug.Log(transform.position.ToString() + " : " + pos.ToString()); NUNCA REMOVER
                transform.position = pos;
            }
            else
            {
                //Reconciliation starting
                //Debug.Log("Stamp received from server: "+inputStamp);

                //Get the oldest recorded input from the player
                ReconciliationEntry firstEntry = reconciliationList[0];

                //Debug.Log("The local reconciliation lists starts at: " + firstEntry.inputs.timeStamp);
                //Debug.Log("The current position (local start position - before prediction) is: " + firstEntry.trans.position);
                //Debug.Log("The position the server sent is: " + pos);
                //Debug.Log("The current position (local end position - after prediction) is: " + transform.position);
                string  debugError             = "";
                float   serverCalculationError = 0f;
                Vector3 predicted = transform.position;

                //If the incoming position is too old, ignore
                if (inputStamp < firstEntry.inputs.timeStamp)
                {
                    debugError += "Ignored! " + inputStamp + " first in list was " + firstEntry.inputs.timeStamp + "\n";
                    return;
                }

                int oldListSize = reconciliationList.Count;

                //Remove all older stamps
                reconciliationList.RemoveAll(
                    entry => entry.inputs.timeStamp <= inputStamp
                    );

                //debugError += "Removed: " + (reconciliationList.Count - oldListSize) + ", reconciliation list size: " + reconciliationList.Count + ", old list size: " + oldListSize + "\n";

                //Save current collision flags
                CollisionFlags cflags = m_CollisionFlags;
                //Save m_Jump
                bool prevJump = m_Jump;

                // Apply the received position
                transform.position = pos;
                //Apply 'de' received movement
                m_MoveDir = movementVector;

                float threshold = 0.0001f;

                // Reapply all the inputs that aren't processed by the server yet.
                int count = 0;
                if (reconciliationList.Count > 0)
                {
                    //debugError += "The first position for reconciliation is: " + reconciliationList[0].position + "\n";
                    //Get the lastest collision flags
                    m_CollisionFlags = reconciliationList[0].lastFlags;

                    //We use the next stamp because we save state before move
                    //Debug
                    firstEntry             = reconciliationList[0];
                    serverCalculationError = Vector3.Distance(firstEntry.position, pos);
                    //Debug.Log("SStamp: "+inputStamp+" CStamp: "+ clientForServerStamp.inputs.timeStamp);

                    float speed = 0f;
                    foreach (ReconciliationEntry e in reconciliationList)
                    {
                        Inputs i = e.inputs;
                        m_Input               = i.wasd;
                        m_IsWalking           = i.walk;
                        m_isCrouching         = i.crouch;
                        m_Jump                = i.jump;
                        m_PreviouslyCrouching = e.prevCrouching;

                        CalcSpeed(out speed);

                        PlayerMovement(speed, e.grounded, e.position, e.rotationYaw);
                        debugError += "(" + (count++) + ")Intermediate rec position: " + transform.position + "\n";
                    }
                }

                debugError += "The final reconciliated position is: " + transform.position + "\n";
                debugError += "The predicted position was: " + predicted + "\n";

                //Check if the server calculated the position in a wrong way

                if (serverCalculationError > threshold)
                {
                    Debug.Log("[Server position sim failure " + inputStamp + "] Error (distance): " + serverCalculationError);
                }

                //Check if predicted is different from renconciliated
                float recError = Vector3.Distance(predicted, transform.position);
                if (recError > threshold)
                {
                    debugError += "Total error: " + recError + "\n";
                    debugError += "(Logging only errors above: " + threshold + ")";
                    if (serverCalculationError > threshold)
                    {
                        Debug.Log("[Reconciliation error due to server error] Log:\n" + debugError);
                    }
                    else
                    {
                        Debug.Log("[Reconciliation error] Log:\n" + debugError);
                    }
                }

                //Restore collision flags
                m_CollisionFlags = cflags;
                //Restore jump state
                m_Jump = prevJump;
            }
        }
        else
        {
            //NO RECONCILIATION
            //When the position arrives from the server, since server is priority,
            //set the local pos to it
            transform.position = pos;
        }
    }
    /*
     * 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) {
            long timestamp = System.DateTime.UtcNow.Ticks;
            //Store crouch input to send to server
            bool sendCrouch = m_isCrouching;

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

            //This is for the host to know if it moved to send change messages
            Vector3 lastPosition = transform.position;

            //Store jump input to send to server
            bool sendJump = m_Jump;

            // Store transform values
            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 || isServer) {
                //Move the player object
                MovePlayer(speed);
            }

            //Client sound and camera
            ProgressStepCycle(speed);

            //OWNER CLIENTS THAT ARE NOT THE HOST
            //CLIENTS THAT ARE NOT THE SERVER
            if (!isServer) {
                bool crouchChange = m_isCrouching != sendCrouch;
                bool moved = m_CharacterController.velocity.sqrMagnitude > 0 || m_Input[0] || m_Input[1]
                    || m_Input[2] || m_Input[3];
                if (moved || sendJump || crouchChange || rotationChanged) {
                    //Debug.Log("W: " + m_Input[0] + " A: " + m_Input[1] + " S: " + m_Input[2] + " D: " + m_Input[3]);
                    //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 = timestamp;
                    inputsList.Enqueue(inputs);

                    // Create reconciliation entry
                    ReconciliationEntry entry = new ReconciliationEntry();
                    entry.inputs = inputs;
                    entry.lastFlags = lastFlag;
                    entry.position = prevPosition;
                    entry.rotation = prevRotation;
                    AddReconciliation(entry);

                    //Clear the jump to send
                    sendJump = false;

                    //Clear rotation flag
                    rotationChanged = false;

                    //Debug.Log("InLst sz is: "+ inputsList.Count+ " Moved is: "+moved);
                }

                //Only send input at the network send interval
                if (dataStep > GetNetworkSendInterval()) {
                    dataStep = 0;

                    //Debug.Log("Sending messages to server");
                    int toSend = inputsList.Count;
                    //Send input to the server
                    while (inputsList.Count > 0) {
                        //Send the inputs done locally
                        Inputs i = inputsList.Dequeue();
                        if (i.move && i.rotate) {
                            //Debug.Log("Mov & Rot sent");
                           CmdProcessMovementAndRotation(i.timeStamp, i.wasd, i.walk, i.crouch, i.jump, i.pitch, i.yaw);
                        } else if (i.move) {
                            //Debug.Log("Mov sent");
                            CmdProcessMovement(i.timeStamp, i.wasd, i.walk, i.crouch, i.jump);
                        } else if (i.rotate) {
                            //Debug.Log("Rot sent");
                            CmdProcessRotation(i.timeStamp, i.pitch, i.yaw);
                        }
                    }
                    /*if (toSend > 0) {
                        Debug.Log(toSend + " messages sent to server");
                    }*/
                    //Clear the input list
                    inputsList.Clear();
                }

                dataStep += Time.fixedDeltaTime;
            }

            //This is for the host player to send its position to all other clients
            //HOST (THE CLIENT ON THE SERVER) CLIENT
            if (isServer) {
                if (dataStep > GetNetworkSendInterval()) {
                    dataStep = 0;
                    if (Vector3.Distance(transform.position, lastPosition) > 0 || rotationChanged) {
                        //Send the current server pos to all clients
                        RpcClientReceivePosition(timestamp, transform.position, m_MoveDir);
                        Debug.Log("Sent host pos");
                    }
                }
                dataStep += Time.fixedDeltaTime;
            }
        }
        /*
        * SERVER SIDE
        */
        else { //If we are on the server, we process commands from the client instead, and generate update messages
            if (isServer) {
                Inputs inputs;
                if (inputsList.Count == 0) {
                    //Check if the message is late
                    //If the message is too late and the list is empty
                    //Stop server simulation of the player
                    if (lastMassageTime > maxDelayBeforeServerSimStop)
                        return;

                    inputs = new Inputs();
                    inputs.walk = true;
                    inputs.crouch = m_isCrouching;
                    inputs.wasd = new bool[] { false, false, false, false };
                    inputs.jump = false;
                    inputs.rotate = false;
                    inputs.timeStamp = System.DateTime.UtcNow.Ticks;
                }
                else {
                    inputs = inputsList.Dequeue();
                    //Debug.Log("Removing : "+inputs.timeStamp);
                }

                Vector3 lastPosition = transform.position;
                Quaternion lastCharacterRotation = transform.rotation;
                Quaternion lastCameraRotation = m_firstPersonCharacter.rotation;

                m_IsWalking = inputs.walk;
                m_Input = inputs.wasd;
                m_isCrouching = inputs.crouch;
                m_Jump = inputs.jump;
                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);
                }
                currentReconciliationStamp = inputs.timeStamp;

                CalcSpeed(out speed); //Server-side method to the speed out of input from clients

                //Move the player object
                MovePlayer(speed);

                if (dataStep > GetNetworkSendInterval()) {
                    if (Vector3.Distance(transform.position, lastPosition) > 0 || Quaternion.Angle(transform.rotation, lastCharacterRotation) > 0 || Quaternion.Angle(m_firstPersonCharacter.rotation, lastCameraRotation) > 0) {
                        RpcClientReceivePosition(currentReconciliationStamp, transform.position, m_MoveDir);
                        //Debug.Log("Sent client pos "+dataStep + ", stamp: " + currentReconciliationStamp);
                    }
                    dataStep = 0;
                }
                dataStep += Time.fixedDeltaTime;
            }
        }
    }
    //Reconciliation methods
    private void AddReconciliation(ReconciliationEntry entry) {
        reconciliationList.Add(entry);

        //Limit the list size
        if (reconciliationList.Count > maxReconciliationEntries)
            reconciliationList.RemoveAt(0);

        //Debug.Log("Current reconciliation list size: " + reconciliationList.Count);
    }