257 lines
8.2 KiB
C#

using System;
using UnityEngine;
[Serializable]
public class State : System.Object
{
public Vector3 p;
public Quaternion r;
public float t = 0.0f;
public float m = 0.0f;
public float n = 0.0f;
public State(Vector3 p, Quaternion r, float t, float m, float n)
{
this.p = p;
this.r = r;
this.t = t;
this.m = m;
this.n = n;
}
}
[Serializable]
public class VehicleNet : MonoBehaviour
{
public Vehicle vehicle;
public bool simulatePhysics = true;
public bool updatePosition = true;
public float physInterp = 0.1f;
public float ping;
public float jitter;
public float calcPing = 0.00f;
public float rpcPing = 0.00f;
public float lastPing = -1.00f;
public int pingCheck;
public bool wePinged = false;
public float autoInterp = 0.00f;
private int m;
private Vector3 p;
private Quaternion r;
public State[] states;
public VehicleNet()
{
pingCheck = UnityEngine.Random.Range(15, 20);
states = new State[15];
}
public void Start()
{
vehicle.networkView.observed = this;
}
public void Update()
{
if (vehicle.networkMode == 2 && Time.time > lastPing + (float)pingCheck)
{
if (lastPing < 0f)
{
lastPing = Time.time;
}
else
{
networkView.RPC("sT", RPCMode.All, 0f);
}
}
if (
!updatePosition ||
states[14] == null ||
states[14].t == 0f ||
!vehicle.myRigidbody ||
!Game.Player ||
!Game.Player.rigidbody)
{
return;
}
if (Game.Settings.networkPhysics == 0)
{
physInterp = 0.1f;
}
else if (Game.Settings.networkPhysics == 1)
{
physInterp = 0.2f;
}
if (Game.Settings.networkPhysics == 2)
{
simulatePhysics = false;
}
else
{
simulatePhysics = Vector3.Distance(
vehicle.myRigidbody.position,
Game.Player.rigidbody.position) < 40f;
}
vehicle.myRigidbody.isKinematic = !simulatePhysics;
vehicle.myRigidbody.interpolation = RigidbodyInterpolation.None;
//Interpolation
float interpolationTime;
if (Game.Settings.networkInterpolation > 0f)
{
interpolationTime = (float)(Network.time - (double)Game.Settings.networkInterpolation);
}
else
{
autoInterp = Mathf.Max(
0.1f,
Mathf.Lerp(
autoInterp,
ping * 1.5f + jitter * 8f,
Time.deltaTime * 0.15f));
interpolationTime = (float)(Network.time - (double)autoInterp);
}
if (states[0].t > interpolationTime) // Target playback time should be present in the buffer
{ // Go through buffer and find correct state to play back
for (int i = 1; i < states.Length - 1; i++)
{
if (
states[i] != null &&
states[i].t <= interpolationTime ||
i == states.Length - 3)
{
State rhs = states[i - 1]; // The state one slot newer than the best playback state
State lhs = states[i]; // The best playback state (closest to .1 seconds old)
float l = rhs.t - lhs.t; // Use the time between the two slots to determine if interpolation is necessary
float t = 0f; // As the time difference gets closer to 100 ms, t gets closer to 1 - in which case rhs is used
if (l > 0.0001f)
{
t = (interpolationTime - lhs.t) / l; // if t=0 => lhs is used directly
}
vehicle.velocity = Vector3.Lerp(
vehicle.velocity,
((rhs.p - states[i + 2].p) / (rhs.t - states[i + 2].t)),
Time.deltaTime * 0.3f);
if (simulatePhysics)
{
vehicle.myRigidbody.MovePosition(Vector3.Lerp(
vehicle.transform.position,
Vector3.Lerp(lhs.p, rhs.p, t),
physInterp));
vehicle.myRigidbody.MoveRotation(Quaternion.Slerp(
vehicle.transform.rotation,
Quaternion.Slerp(lhs.r, rhs.r, t),
physInterp));
vehicle.myRigidbody.velocity = vehicle.velocity;
}
else
{
vehicle.myRigidbody.position = Vector3.Lerp(lhs.p, rhs.p, t);
vehicle.myRigidbody.rotation = Quaternion.Slerp(lhs.r, rhs.r, t);
}
vehicle.isResponding = true;
vehicle.netCode = "";
return;
}
}
}
//Extrapolations
else
{
float extrapolationLength = (interpolationTime - states[0].t);
vehicle.velocity = Vector3.Lerp(
vehicle.velocity,
((states[0].p - states[2].p) / (states[0].t - states[2].t)),
Time.deltaTime * 0.3f);
if (extrapolationLength < 1f)
{
if (!simulatePhysics)
{
vehicle.myRigidbody.position = states[0].p +
(vehicle.velocity * extrapolationLength);
vehicle.myRigidbody.rotation = states[0].r;
}
vehicle.isResponding = true;
if (extrapolationLength < 0.3f) vehicle.netCode = ">";
else vehicle.netCode = " (Delayed)";
}
else
{
vehicle.netCode = " (Not Responding)";
vehicle.isResponding = false;
}
}
}
public void OnSerializeNetworkView(BitStream stream, NetworkMessageInfo info)
{
//We are the server, and have to keep track of relaying messages between connected clients
if (stream.isWriting)
{
if (networkView.stateSynchronization == NetworkStateSynchronization.Off)
{
Debug.Log("sNv NvS: " + gameObject.name);
return;
}
if (states[0] == null) return;
p = states[0].p;
r = states[0].r;
//m is the number of milliseconds that transpire between the packet's original send time and the time it is resent from the server to all the other clients
m = (int)((Network.time - (double)states[0].t) * 1000.0);
stream.Serialize(ref p);
stream.Serialize(ref r);
stream.Serialize(ref m);
}
//New packet recieved - add it to the states array for interpolation!
else
{
if (networkView.stateSynchronization == NetworkStateSynchronization.Off)
{
Debug.Log("sNv NvN: " + gameObject.name);
return;
}
stream.Serialize(ref p);
stream.Serialize(ref r);
stream.Serialize(ref m);
State state = new State(
p,
r,
(float)(info.timestamp - (double)((m <= 0) ?
0f :
((float)m / 1000f))),
m,
(float)(Network.time - info.timestamp));
if (states[0] != null && state.t == states[0].t)
{
state.t += 0.01f; //Bizarre - dragonhere
}
if (states[0] == null || state.t > states[0].t)
{
float png = (float)(Network.time - (double)state.t);
jitter = Mathf.Lerp(
jitter,
Mathf.Abs(ping - png),
1f / Network.sendRate);
ping = Mathf.Lerp(ping, png, 1f / Network.sendRate);
for (int k = states.Length - 1; k > 0; k--)
{
states[k] = states[k - 1];
}
states[0] = state;
}
}
}
}