Network transform prediction

Hi… here’s a translated version of the Network Tutorials “NetworkInterpolatedTransform.cs” into JavaScript. It helps with the network transform predictions. I couldn’t get the C# version of the script to work with my CharacterControllers, and perhaps someone else might need this script.

var interpolationBackTime = 0.1;

private var m_BufferedState : Array = new State[20]; // where we store the State of our controller
private var m_TimestampCount : int; // keeps track of what slots are used


// Holds information about the controllers movements and last sent information from the network
class State
{
	var timeStamp : float;
	var pos : Vector3;
	var rot : Quaternion;
}

function OnSerializeNetworkView(stream : BitStream, info : NetworkMessageInfo)
{
	if (stream.isWriting)
	{
		var pos = transform.position;
		var rot = transform.rotation;
		
		stream.Serialize(pos);
		stream.Serialize(rot);
	}
	else
	{
		pos = Vector3.zero;
		rot = Quaternion.identity;
		stream.Serialize(pos);
		stream.Serialize(rot);
		
		
		for (var i = m_BufferedState.length - 1; i >= 1; i --)
		{
			m_BufferedState[i] = m_BufferedState[i-1];
		}
		
		var state = new State();
		state.timeStamp = info.timestamp;
		state.pos = pos;
		state.rot = rot;
		m_BufferedState[0] = state;
		
		m_TimestampCount = Mathf.Min(m_TimestampCount + 1, m_BufferedState.length);
		
		for (i = 0; i < m_TimestampCount-1; i++)
		{
			if (m_BufferedState[i].timeStamp < m_BufferedState[i+1].timeStamp)
			{
				Debug.Log("State inconsistent");
			}
		}
	}
}

function Update () 
{
	if (!networkView.isMine)
	{		
		var currentTime = Network.time;
		var interpolationTime = currentTime - interpolationBackTime;
	
		if (m_BufferedState[0] != null  m_BufferedState[0].timeStamp > interpolationTime)
		{
			for (var i = 0; i < m_TimestampCount; i++)
			{
				if (m_BufferedState[i].timeStamp <= interpolationTime || i == m_TimestampCount - 1)
				{
					// The state one slot newer (<100ms) than the best playback state
					var rhs : State = m_BufferedState[Mathf.Max(i-1, 0)];
					// The best playback state (closest to 100 ms old (default time))
					var lhs : State = m_BufferedState[i];
					
					// Use the time between the two slots to determine if interpolation is necessary
					var length = rhs.timeStamp - lhs.timeStamp;
					var t : float = 0.0;
					
					if (length > 0.0001)
					{
						t = ((interpolationTime - lhs.timeStamp) / length);
					}
					
					// if t=0 => lhs is used directly
					transform.position = Vector3.Lerp(lhs.pos, rhs.pos, t);
					transform.rotation = Quaternion.Slerp(lhs.rot, rhs.rot, t);
					return;
					
				}
			}
		}
		else
		{
			if (m_BufferedState[0] != null)
			{
				var latest = m_BufferedState[0];
				transform.position = latest.pos;
				transform.rotation = latest.rot;
			}
		}
	}
}

To use it, just drop the script onto your CharacterController, attach a NetworkView, and set the NetworkView to observe the script. Good luck…

I owe you a thank you. Since I am using this.

Thanks for sharing.