private void ApplyCorrectionsWithServerState(ServerStateMessage serverStateMessage, uint bufferSlot)
        {
            // rewind & replay

            StateProcessorComponent.ExecuteState(serverStateMessage.serverState);

            _correctionsMadeOnClient++;

            // capture the current predicted pos for smoothing
            Vector3    prevPosition = StateProcessorComponent.GetCurrentState().position + _clientPositionError;
            Quaternion prevRotation = StateProcessorComponent.GetCurrentState().rotation *_clientRotationError;

            uint rewindTickNumber = serverStateMessage.tickNumber;

            while (rewindTickNumber < _currentTickNumber)
            {
                bufferSlot = rewindTickNumber % _clientBufferSize;

                ClientStoreCurrentStateAndStep(ref _clientStateBuffer[bufferSlot], _clientInputBuffer[bufferSlot]);

                rewindTickNumber++;
            }

            //if the position error is greater than 2 meters, just snap
            if ((prevPosition - StateProcessorComponent.GetCurrentState().position).sqrMagnitude >= 4.0f)
            {
                _clientPositionError = Vector3.zero;
                _clientRotationError = Quaternion.identity;
            }
            else
            {
                _clientPositionError = prevPosition - StateProcessorComponent.GetCurrentState().position;
                _clientRotationError = Quaternion.Inverse(StateProcessorComponent.GetCurrentState().rotation) *
                                       prevRotation;
            }
        }
        public void OnServerStateUpdated()
        {
            _serverTickAccumulator++;

            if (_serverTickAccumulator >= _serverSnapshotRate)
            {
                _serverTickAccumulator = 0;

                ServerStateMessage serverStateMsg = new ServerStateMessage();
                serverStateMsg.packetId     = _serverPacketID;
                serverStateMsg.deliveryTime = _networkClock.CurrentTime;
                serverStateMsg.tickNumber   = _currentTickNumber;
                serverStateMsg.serverState  = StateProcessorComponent.GetCurrentState();

                //Send Message To Client
                NetworkServer.SendToClientOfPlayer(this.gameObject, _stateMessageReceivedID, serverStateMsg);
                _serverPacketID++;
            }

            //Send RPC Call to sync non local clients positions
            //TODO: Optimize this
            RpcTransformUpdate(StateProcessorComponent.GetCurrentState().position,
                               StateProcessorComponent.GetCurrentState().rotation);
        }
        void ClientUpdate()
        {
            _clientTimer += Time.deltaTime;

            while (_clientTimer >= Time.fixedDeltaTime)
            {
                _clientTimer -= Time.deltaTime;

                uint bufferSlot = _currentTickNumber % _clientBufferSize;

                _clientInputBuffer[bufferSlot] = InputProcessorComponent.GetCurrentInputs();

                // store state for this tick, then use current state + input to step simulation
                ClientStoreCurrentStateAndStep(ref _clientStateBuffer[bufferSlot],
                                               InputProcessorComponent.GetCurrentInputs());

                ClientPredictedMessage clientPredictedMessage = new ClientPredictedMessage();
                clientPredictedMessage.packetId        = _clientPacketID;
                clientPredictedMessage.deliveryTime    = _networkClock.CurrentTime;
                clientPredictedMessage.startTickNumber = _sendRedundantInputsToServer
                    ? _clientLastReceivedStateTickNumber
                    : _currentTickNumber;

                var inputList = new List <Inputs>();

                for (uint tick = clientPredictedMessage.startTickNumber; tick <= _currentTickNumber; tick++)
                {
                    inputList.Add(_clientInputBuffer[tick % _clientBufferSize]);
                }

                clientPredictedMessage.inputs = inputList.ToArray();

                //Send Input Message To Server
                connectionToServer.Send(_predictedMessageReceivedID, clientPredictedMessage);

                _clientPacketID++;

                _currentTickNumber++;
            }

            if (ClientHasStateMessage())
            {
                ServerStateMessage serverStateMessage = _clientServerStateMessageBuffer.Dequeue().Element;

                while (ClientHasStateMessage()
                       ) // make sure if there are any newer state messages available, we use those instead
                {
                    serverStateMessage = _clientServerStateMessageBuffer.Dequeue().Element;
                }

                _clientLastReceivedStateTickNumber = serverStateMessage.tickNumber;

                //Broadcast this server state for easy access for debugging purposes
                if (OnValidSercerStateReceived != null)
                {
                    OnValidSercerStateReceived(serverStateMessage.serverState);
                }
                //-----------------------------

                uint bufferSlot = serverStateMessage.tickNumber % _clientBufferSize;

                Vector3 positionError =
                    serverStateMessage.serverState.position - _clientStateBuffer[bufferSlot].position;

                float rotationError = 1.0f - Quaternion.Dot(serverStateMessage.serverState.rotation,
                                                            _clientStateBuffer[bufferSlot].rotation);

                //Validating position,rotation and extras rules defined in de State processor
                if (positionError.sqrMagnitude > 0.0000001f || rotationError > 0.00001f ||
                    !StateProcessorComponent.IsValidateState(ref serverStateMessage.serverState,
                                                             ref _clientStateBuffer[bufferSlot]))
                {
                    ApplyCorrectionsWithServerState(serverStateMessage, bufferSlot);
                }
            }

            SmoothTransformForModels();
        }