protected void ProcessStateUpdateFromJitterBuffer( Context context, Context.ConnectionData connectionData, int fromClientIndex, int toClientIndex, bool applySmoothing = true ) { if ( connectionData.remoteFrameNumber < 0 ) return; JitterBufferEntry entry = connectionData.jitterBuffer.GetEntry( (uint) connectionData.remoteFrameNumber ); if ( entry == null ) return; if ( fromClientIndex == 0 ) { // server -> client // Ignore updates from before the last reset. if ( Network.Util.SequenceGreaterThan( context.GetResetSequence(), entry.packetHeader.resetSequence ) ) return; // Reset if the server reset sequence is more recent than ours. if ( Network.Util.SequenceGreaterThan( entry.packetHeader.resetSequence, context.GetResetSequence() ) ) { context.Reset(); context.SetResetSequence( entry.packetHeader.resetSequence ); } } else { // client -> server // Ignore any updates from the client with a different reset sequence # if ( context.GetResetSequence() != entry.packetHeader.resetSequence ) return; } // add the cube states to the receive delta buffer AddPacketToDeltaBuffer( ref connectionData.receiveDeltaBuffer, entry.packetHeader.sequence, context.GetResetSequence(), entry.numStateUpdates, ref entry.cubeIds, ref entry.cubeState ); // apply the state updates to cubes context.ApplyCubeStateUpdates( entry.numStateUpdates, ref entry.cubeIds, ref entry.cubeState, fromClientIndex, toClientIndex, applySmoothing ); // process the packet header (handles acks) connectionData.connection.ProcessPacketHeader( ref entry.packetHeader ); }
public bool AddStateUpdatePacket(byte[] packetData, DeltaBuffer receiveDeltaBuffer, ushort resetSequence, out long packetFrameNumber) { Network.PacketHeader packetHeader; ReadStateUpdatePacketHeader(packetData, out packetHeader); packetFrameNumber = packetHeader.frameNumber; int entryIndex = sequenceBuffer.Insert(packetHeader.frameNumber); if (entryIndex < 0) { return(false); } bool result = true; Profiler.BeginSample("ProcessStateUpdatePacket"); JitterBufferEntry entry = sequenceBuffer.Entries[entryIndex]; if (ReadStateUpdatePacket(packetData, out entry.packetHeader, out entry.numAvatarStates, ref entry.avatarStateQuantized, out entry.numStateUpdates, ref entry.cubeIds, ref entry.notChanged, ref entry.hasDelta, ref entry.perfectPrediction, ref entry.hasPredictionDelta, ref entry.baselineSequence, ref entry.cubeState, ref entry.cubeDelta, ref entry.predictionDelta)) { for (int i = 0; i < entry.numAvatarStates; ++i) { AvatarState.Unquantize(ref entry.avatarStateQuantized[i], out entry.avatarState[i]); } DecodePrediction(receiveDeltaBuffer, resetSequence, entry.packetHeader.sequence, entry.numStateUpdates, ref entry.cubeIds, ref entry.perfectPrediction, ref entry.hasPredictionDelta, ref entry.baselineSequence, ref entry.cubeState, ref entry.predictionDelta); DecodeNotChangedAndDeltas(receiveDeltaBuffer, resetSequence, entry.numStateUpdates, ref entry.cubeIds, ref entry.notChanged, ref entry.hasDelta, ref entry.baselineSequence, ref entry.cubeState, ref entry.cubeDelta); } else { sequenceBuffer.Remove(packetHeader.frameNumber); result = false; } Profiler.EndSample(); return(result); }
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); }