// We interpolate only on other clients, not on the server, and not on the local client)
    void Update()
    {
        //Loop all states
        for (int i = 0; i < bufferedStatesCount; i++)
        {
            //State time is local time - state counter * interval between states
            float stateTime = lastBufferedStateTime - i * updateRate;
            //Find the first state that match now - interpTime (or take the last buffer entry)
            if (stateTime <= Time.time - interpolationBackTime || i == bufferedStatesCount - 1)
            {
                //Get one step after and one before the time
                CharacterNetworkSync.CharacterState afterState = bufferedStates[Mathf.Max(i - 1, 0)];
                float afterStateTime = lastBufferedStateTime - (i - 1) * updateRate;
                CharacterNetworkSync.CharacterState beforeState = bufferedStates[i];
                float beforeStateTime = lastBufferedStateTime - i * updateRate;;

                // Use the time between the two slots to determine if interpolation is necessary
                double length = afterStateTime - beforeStateTime;
                float  t      = 0.0F;
                // As the time difference gets closer to 100 ms t gets closer to 1 in
                // which case rhs is only used
                if (length > 0.0001)
                {
                    t = (float)((Time.time - interpolationBackTime - beforeStateTime) / length);
                }

                //Do the actual interpolation
                transform.position = Vector3.Lerp(beforeState.position, afterState.position, t);
                transform.rotation = Quaternion.Slerp(beforeState.rotation, afterState.rotation, t);
                break;
            }
        }
    }
    /// <summary>
    /// Called when a state is received from server
    /// </summary>
    /// <param name="newState"></param>
    public void ReceiveState(CharacterNetworkSync.CharacterState newState)
    {
        //Other Clients: Shift buffer and store at first position
        for (int i = bufferedStates.Length - 1; i >= 1; i--)
        {
            bufferedStates[i] = bufferedStates[i - 1];
        }
        bufferedStates[0]   = newState;
        bufferedStatesCount = Mathf.Min(bufferedStatesCount + 1, bufferedStates.Length);

        //Other Clients: Check that states are in good order
        for (int i = 0; i < bufferedStatesCount - 1; i++)
        {
            if (bufferedStates[i].state < bufferedStates[i + 1].state)
            {
                Debug.LogWarning("Warning, State are in wrong order");
            }
        }

        lastBufferedStateTime = Time.time;
    }
コード例 #3
0
    /// <summary>
    /// Receive a good state from the server
    /// Discard input older than this good state
    /// Replay missing inputs on top of it
    /// </summary>
    /// <param name="serverRecvState"></param>
    /// <param name="serverRecvPosition"></param>
    /// <param name="serverRecvRotation"></param>
    void ServerState(CharacterNetworkSync.CharacterState characterState)
    {
        int        serverRecvState    = characterState.state;
        Vector3    serverRecvPosition = characterState.position;
        Quaternion serverRecvRotation = characterState.rotation;

        //Client: Check that we received a new state from server (not some delayed packet)
        if (clientAckState < serverRecvState)
        {
            //Client: Set the last server ack state
            clientAckState = serverRecvState;

            //Client: Discard all input states where state are before the ack state
            bool loop = true;
            while (loop && inputStates.Count > 0)
            {
                CharacterInput.InputState state = inputStates.Peek();
                if (state.inputState <= clientAckState)
                {
                    inputStates.Dequeue();
                }
                else
                {
                    loop = false;
                }
            }

            //Client: store actual Character position, rotation and velocity along with current input
            CharacterInput.InputState oldState = characterInput.currentInput;
            Vector3    oldPos = transform.position;
            Quaternion oldRot = transform.rotation;

            //Client: move back the player to the received server position
            serverLastRecvPosition = serverRecvPosition;
            serverLastRecvRotation = serverRecvRotation;
            transform.position     = serverLastRecvPosition;
            transform.rotation     = serverLastRecvRotation;

            //Client: replay all input based on new correct position
            foreach (CharacterInput.InputState state in inputStates)
            {
                //Set the input
                characterInput.currentInput = state;
                //Run the simulation
                characterMovement.RunUpdate(Time.fixedDeltaTime);
                characterRotation.RunUpdate(Time.fixedDeltaTime);
            }
            //Client: save the new predicted character position
            serverLastPredPosition = transform.position;
            serverLastPredRotation = transform.rotation;

            //Client: restore initial position, rotation and velocity
            characterInput.currentInput = oldState;
            transform.position          = oldPos;
            transform.rotation          = oldRot;

            //Client: Check if a prediction error occured in the past
            //Debug.Log("States in queue: " + inputStates.Count + " Predicted distance: " + Vector3.Distance(transform.position, serverLastPredPosition));
            if (Vector3.Distance(transform.position, serverLastPredPosition) > MAX_SERVER_DISTANCE_SNAP)
            {
                //Client: Snap to correct position
                Debug.LogWarning("Prediction error!");
                transform.position = Vector3.Lerp(transform.position, serverLastPredPosition, Time.fixedDeltaTime * 10);
                transform.rotation = Quaternion.Lerp(transform.rotation, serverLastPredRotation, Time.fixedDeltaTime * 10);
            }
        }
    }