Last active
February 1, 2020 00:14
-
-
Save hellos3b/b0d5284a16c3f7ff1a350843063c78be to your computer and use it in GitHub Desktop.
Custom network smoothing using uNet in Unity3D
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System.Collections; | |
using System.Collections.Generic; | |
using UnityEngine; | |
using UnityEngine.Networking; | |
using ThirdPersonCamera; | |
/// <summary> | |
/// Sync and Smooth out player's movement | |
/// </summary> | |
public class PlayerSyncTransform : NetworkBehaviour { | |
[HideInInspector] | |
public NetworkInstanceId connection_id; | |
[Header("Network Information")] | |
public float updateInterval = 0.025f; | |
public float lerpRate = 0.15f; | |
private float updateTimer = 0; | |
private PlayerBody body; | |
private Vector3 ServerPositionLast = new Vector3(0,0,0); // The previous position got from the server | |
private Vector3 ServerPosition = new Vector3(0,0,0); // The latest position from the server | |
private Quaternion ServerRotation = new Quaternion(); // The latest rotation from the server | |
private PlayerMovementController movementController; | |
void Awake() { | |
body = GetComponent<PlayerBody>(); | |
movementController = GetComponent<PlayerMovementController>(); | |
} | |
void Start() { | |
ServerPosition = transform.position; | |
} | |
void FixedUpdate() { | |
if (isLocalPlayer) { | |
// Just a timer to send sync at an interval | |
if (updateTimer <= 0) { | |
SendSync (); | |
updateTimer = updateInterval; | |
} else { | |
updateTimer -= Time.deltaTime; | |
} | |
} else { | |
SyncSmooth (); | |
} | |
} | |
void SendSync() { | |
CmdSync (transform.position, movementController.movement, movementController.vSpeed.get(), Timestamp ()); | |
} | |
[Command] | |
void CmdSync(Vector3 position, Vector3 vel, float vspeed, int timestamp) { | |
// "Simulating" here takes some physics variables, and calculates where it would be in (t) seconds | |
// where (t) is the time it took from server sending the message to client recieving | |
// Basically, if I'm at (0,0) and am moving right at 1 unit a second, and the server sent the message half a second ago, | |
// The simulated position is now (0.5,0) | |
// GetClientDelay() and GetServerDelay() calculates the difference in timestamps to figure out how long the message took | |
position = movementController.SimulatePosition(GetServerDelay(timestamp), position, vel, vspeed); | |
vspeed = movementController.SimulateGravity(GetServerDelay(timestamp), vspeed); | |
RpcSync (position, vel, vspeed, Timestamp ()); | |
} | |
[ClientRpc] | |
void RpcSync(Vector3 position, Vector3 vel, float vspeed, int timestamp) { | |
if (!isLocalPlayer && enabled) { | |
position = movementController.SimulatePosition(GetClientDelay(timestamp), position, vel, vspeed); | |
vspeed = movementController.SimulateGravity(GetClientDelay(timestamp), vspeed); | |
// I update the controller's physics so they continue emulating client-side, to fill in the gap between server messages | |
movementController.movement = vel; | |
movementController.vSpeed.Set(vspeed); | |
ServerPositionLast = ServerPosition; | |
ServerPosition = position; | |
} | |
} | |
private void SyncSmooth() { | |
transform.position = Vector3.Lerp (transform.position, ServerPosition, lerpRate); | |
transform.rotation = Quaternion.Slerp (transform.rotation, ServerRotation, lerpRate); | |
} | |
# region Network Delay Utils | |
private int Timestamp() { | |
return NetworkTransport.GetNetworkTimestamp (); | |
} | |
private float GetClientDelay(int timestamp) { | |
if (!isLocalPlayer || isServer) { | |
return 0; | |
} | |
byte error; | |
int delayMS = NetworkTransport.GetRemoteDelayTimeMS ( | |
connectionToServer.hostId, | |
connectionToServer.connectionId, | |
timestamp, | |
out error); | |
return (float)delayMS / 1000; | |
} | |
private float GetServerDelay(int timestamp) { | |
if (isServer && isLocalPlayer) { | |
return 0; | |
} | |
byte error; | |
int delayMS = NetworkTransport.GetRemoteDelayTimeMS ( | |
connectionToClient.hostId, | |
connectionToClient.connectionId, | |
timestamp, | |
out error); | |
return (float)delayMS / 1000; | |
} | |
#endregion | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment