示例#1
0
    private void Correct(IClock fixedClock)
    {
        if (_serverHistory.Count < 1)
        {
            Debug.Log("no server history available");
            return;
        }

        /* Extrapolate last received server state to catch up to client time */

        /* Todo: Save massive amounts of calculation by only simulating 1 correction tick per actual physics frame, you dummy
         * New server state? Do offline sim for however many steps it requires to catch up to local client time instantly.
         * THEN, then you only have to simulate one tick for each real-time physics tick in order to keep up. Until the new server state arrives.
         *
         * So in this method we only tick once
         * In the receive state handler we tick multiple times to catch up to local client time
         */

        var latency = _lastReceivedStateRTT / 2d;
        var timeSinceLastReceivedState = fixedClock.CurrentTime - _lastReceivedStateTimestamp;
        var timeSinceServerState       = latency + timeSinceLastReceivedState;
        var startTime = _lastReceivedStateTimestamp - latency;

        Debug.Assert(timeSinceServerState > 0.0, "timeSinceServerState > 0: " + timeSinceServerState);

        _eulerBody.State = _lastServerState;
        PlayerSimulation.SimulateOffline(_simulation.Config, _eulerBody, t => _inputHistory.Lerp(t), startTime, timeSinceServerState, fixedClock.DeltaTime);
        _correctedState = _eulerBody.State;

        /* Calculate error between corrected server state and current client state */

        var currentClientState = _simulation.UnityBody.State;

        const float maxPosError = 2f;
        const float maxRotError = 45f;

        _posError = Vector3.Distance(currentClientState.Position, _correctedState.Position) / maxPosError;
        _rotError = Quaternion.Angle(currentClientState.Rotation, _correctedState.Rotation) / maxRotError;

        /* Apply corrected state over time, with use of error metrics */

        _posErrorSmooth = Mathf.Lerp(_posErrorSmooth, 0.5f + _posError, 1f / _errorSmoothing * fixedClock.DeltaTime);
        _rotErrorSmooth = Mathf.Lerp(_rotErrorSmooth, 0.5f + _rotError, 1f / _errorSmoothing * fixedClock.DeltaTime);

        var interpolatedState = RigidbodyExtensions.Lerp(
            currentClientState, _correctedState,
            _posErrorSmooth * fixedClock.DeltaTime * _errorCorrectionSpeed,
            _rotErrorSmooth * fixedClock.DeltaTime * _errorCorrectionSpeed);

        if (_applyCorrection)
        {
            interpolatedState.ApplyTo(_simulation.UnityBody.Rigidbody);
        }
    }