public bool GetInterpolatedAvatarState()

in Networked Physics/Assets/Scripts/JitterBuffer.cs [136:251]


    public bool GetInterpolatedAvatarState( ref AvatarState[] output, out int numOutputAvatarStates, out ushort resetSequence )
    {
        numOutputAvatarStates = 0;
        resetSequence = 0;

        // if interpolation frame is negative, it's too early to display anything

        double interpolation_frame = initial_frame + time * Constants.PhysicsFrameRate;

        if ( interpolation_frame < 0.0 )
            return false;

        // if we are interpolating but the interpolation start frame is too old,
        // go back to the not interpolating state, so we can find a new start point.

        const int n = 16;

        if ( interpolating )
        {
            long frame = (long) Math.Floor( interpolation_frame );

            if ( frame - interpolation_start_frame > n )
                interpolating = false;
        }
        
        // if not interpolating, attempt to find an interpolation start point. 
        // if start point exists, go into interpolating mode and set end point to start point
        // so we can reuse code below to find a suitable end point on first time through.
        // if no interpolation start point is found, return.

        if ( !interpolating )
        {
            long current_frame = (uint) Math.Floor( interpolation_frame );

            for ( long frame = current_frame + 1; ( frame > current_frame - n ) && ( frame >= 0 ); frame-- )
            {
                JitterBufferEntry entry = GetEntry( (uint) frame );

                if ( entry != null )
                {
                    double avatar_sample_time = ( frame - initial_frame ) * ( 1.0 / Constants.PhysicsFrameRate ) + entry.packetHeader.avatarSampleTimeOffset;
                    
                    if ( time >= avatar_sample_time && time <= avatar_sample_time + ( 1.0f / Constants.PhysicsFrameRate ) )
                    {
                        interpolation_start_frame = frame;
                        interpolation_end_frame = frame;

                        interpolation_start_time = avatar_sample_time;
                        interpolation_end_time = avatar_sample_time;

                        interpolating = true;
                    }
                }
            }
        }

        if ( !interpolating )
            return false;

        Assert.IsTrue( time >= interpolation_start_time );

        // if current time is >= end time, we need to start a new interpolation
        // from the previous end time to the next sample that exists up to n samples ahead.

        if ( time >= interpolation_end_time )
        {
            interpolation_start_frame = interpolation_end_frame;
            interpolation_start_time = interpolation_end_time;

            for ( int i = 0; i < n; ++i )
            {
                JitterBufferEntry entry = GetEntry( (uint) ( interpolation_start_frame + 1 + i ) );

                if ( entry != null )
                {
                    double avatar_sample_time = ( interpolation_start_frame + 1 + i - initial_frame ) * ( 1.0 / Constants.PhysicsFrameRate ) + entry.packetHeader.avatarSampleTimeOffset;

                    if ( avatar_sample_time >= time )
                    {
                        interpolation_end_frame = interpolation_start_frame + 1 + i;
                        interpolation_end_time = avatar_sample_time + ( 1.0 / Constants.PhysicsFrameRate );
                        break;
                    }
                }
            }
        }

        // if current time is still > end time, we couldn't start a new interpolation so return.

        if ( time > interpolation_end_time )
            return false;

        // we are in a valid interpolation, calculate t by looking at current time 
        // relative to interpolation start/end times and perform the interpolation.

        float t = (float) Clamp( ( time - interpolation_start_time ) / ( interpolation_end_time - interpolation_start_time ), 0.0, 1.0 );

        JitterBufferEntry a = GetEntry( (uint) ( interpolation_start_frame ) );
        JitterBufferEntry b = GetEntry( (uint) ( interpolation_end_frame ) );

        for ( int i = 0; i < a.numAvatarStates; ++i )
        {
            for ( int j = 0; j < b.numAvatarStates; ++j )
            {
                if ( a.avatarState[i].client_index == b.avatarState[j].client_index )
                {
                    AvatarState.Interpolate( ref a.avatarState[i], ref b.avatarState[j], out output[numOutputAvatarStates], t );  
                    numOutputAvatarStates++;
                }
            }
        }

        resetSequence = a.packetHeader.resetSequence;

        return true;
    }