///////////////////////////////////////////////////////////////////////////// /// Function: OnSerializeNetworkView ///////////////////////////////////////////////////////////////////////////// protected void OnSerializeNetworkView(BitStream stream, NetworkMessageInfo info) { Vector3 v3Position = m_trObservedTransform.position; Quaternion qRotation = m_trObservedTransform.rotation; if (stream.isWriting) // Executed by owner of the network view { if (Network.isServer) { stream.Serialize(ref v3Position); stream.Serialize(ref qRotation); } } else // Executed by everyone else receiving the data { stream.Serialize(ref v3Position); stream.Serialize(ref qRotation); // Shift buffer for (int i = m_rgBuffer.Length - 1; i >= 1; i--) { m_rgBuffer[i] = m_rgBuffer[i - 1]; } // Insert latest data at the front of buffer m_rgBuffer[0] = new CAIPayload() { Position = v3Position, Rotation = qRotation, Timestamp = (float)info.timestamp }; } }
///////////////////////////////////////////////////////////////////////////// /// Function: UpdateClients ///////////////////////////////////////////////////////////////////////////// protected void UpdateClients() { if (Network.isClient) { clientPing = (Network.GetAveragePing(Network.connections[0]) / 100) + pingMargin; // on client the only connection [0] is the server float interpolationTime = (float)Network.time - clientPing; // make sure there is at least one entry in the buffer if (m_rgBuffer[0] == null) { m_rgBuffer[0] = new CAIPayload() { Position = m_trObservedTransform.position, Rotation = m_trObservedTransform.rotation, Timestamp = 0 }; } // Interpolation if (m_rgBuffer[0].Timestamp > interpolationTime) { for (int i = 0; i < m_rgBuffer.Length; i++) { if (m_rgBuffer[i] == null) { continue; } // Find best fitting state or use the last one available if (m_rgBuffer[i].Timestamp <= interpolationTime || i == m_rgBuffer.Length - 1) { CAIPayload bestTarget = m_rgBuffer[Mathf.Max(i - 1, 0)]; CAIPayload bestStart = m_rgBuffer[i]; float timeDiff = bestTarget.Timestamp - bestStart.Timestamp; float lerpTime = 0f; if (timeDiff > 0.0001) { lerpTime = ((interpolationTime - bestStart.Timestamp) / timeDiff); } m_trObservedTransform.position = Vector3.Lerp(bestStart.Position, bestTarget.Position, lerpTime); m_trObservedTransform.rotation = Quaternion.Slerp(bestStart.Rotation, bestTarget.Rotation, lerpTime); return; } } } else { //Extrapolation float extrapolationTime = (interpolationTime - m_rgBuffer[0].Timestamp); if (m_rgBuffer[0] != null && m_rgBuffer[1] != null) { CAIPayload lastSample = m_rgBuffer[0]; CAIPayload prevSample = m_rgBuffer[1]; float timeDiff = lastSample.Timestamp - prevSample.Timestamp; float lerpTime = 0f; if (timeDiff > 0.0001) { lerpTime = ((extrapolationTime - lastSample.Timestamp) / timeDiff); } Vector3 predictedPosition = lastSample.Position + prevSample.Position; m_trObservedTransform.position = Vector3.Lerp(lastSample.Position, predictedPosition, lerpTime); m_trObservedTransform.rotation = lastSample.Rotation; } } } }