Guest User

Client Side Prediction/Reconsiliation?

a guest
Jan 29th, 2016
346
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C# 5.70 KB | None | 0 0
  1. using UnityEngine;
  2. using System.Collections.Generic;
  3. using UnityEngine.Networking;
  4. //using UnityEngine.UI;
  5.  
  6. public class playerControllerPrediction : NetworkBehaviour
  7. {
  8.     //How often to send inputs to server
  9.     public int sendRate = 10;
  10.  
  11.     public playerInput playerInput;
  12.     public Rigidbody2D playerRigidbody;
  13.  
  14.     //Speeds of character movement
  15.     public int walkSpeed = 2;
  16.     public int runSpeed = 4;
  17.     public int curSpeed;
  18.  
  19.     //Vector 2 pulled from input script
  20.     [SyncVar]
  21.     public Vector2 inputVector;
  22.     public Vector2 playerVelocity;
  23.     private Vector2 lastPos;
  24.  
  25.     //pos of character on server
  26.     [SyncVar (hook = "GetServerPosition")]
  27.     public Vector2 serverPos;
  28.  
  29.    
  30.     //Dictionaries containing timestamps and positions
  31.     private Dictionary<float, Vector2> serverPosDict = new Dictionary<float, Vector2>();
  32.     private Dictionary<float, Vector2> clientPosDict = new Dictionary<float, Vector2>();
  33.     public float serverTick;
  34.     public float clientTick;
  35.  
  36.     private float locationTolerance = 0.1f;
  37.  
  38.     //Testing Latency addition
  39.     //getting it in another script, in milliseconds
  40.     private playerNetworkSetup setupScript;
  41.     public float latency;
  42.  
  43.  
  44.     public override void OnStartLocalPlayer()
  45.     {
  46.         setupScript = GetComponent<playerNetworkSetup>();
  47.         playerRigidbody = GetComponent<Rigidbody2D>();
  48.         playerInput = GetComponentInChildren<playerInput>();
  49.  
  50.         float sendRateInSeconds = (1 / (float)sendRate);
  51.         InvokeRepeating("NetworkSend", sendRateInSeconds, sendRateInSeconds);
  52.     }
  53.  
  54.     //Client doesn't need to get the rigidbody or the server would set the client's velocity
  55.     public override void OnStartServer()
  56.     {
  57.         playerRigidbody = GetComponent<Rigidbody2D>();
  58.     }
  59.  
  60.     //just to only send to server when moving
  61.     void Update ()
  62.     {
  63.         Vector2 curPos = transform.position;
  64.         playerVelocity = (curPos - lastPos) / Time.deltaTime;
  65.         lastPos = transform.position;
  66.     }
  67.  
  68.     void FixedUpdate()
  69.     {      
  70.         if (isLocalPlayer)
  71.         {          
  72.             inputVector = playerInput.inputVector.normalized; //Normalized before sending
  73.  
  74.             if (playerInput.shift)
  75.             {
  76.                 curSpeed = runSpeed;
  77.             }
  78.             else
  79.             {
  80.                 curSpeed = walkSpeed;
  81.             }
  82.         }
  83.     }
  84.  
  85.  
  86.     //SYNCVARS ONLY SYNC TO THE CLIENTS NOT THE SERVER
  87.     //This code is now working because we are setting the SyncVar's
  88.     //in the command, and propogating these changes to the client.
  89.  
  90.  
  91.     void NetworkSend ()
  92.     {
  93.        
  94.         if (isLocalPlayer)
  95.         {
  96.             if (inputVector == Vector2.zero && playerVelocity == Vector2.zero)
  97.             {
  98.                 return;
  99.             }
  100.             else
  101.             {
  102.                 SendServerPlayerInputs();              
  103.                 ClientPrediction();              
  104.             }
  105.         }
  106.     }
  107.  
  108.  
  109.     [Command]
  110.     void CmdCalculatePlayerMovement(Vector2 clientInputs, int speed)
  111.     {
  112.         inputVector = clientInputs;
  113.         playerRigidbody.velocity = inputVector * speed;
  114.  
  115.         serverPos = new Vector2(transform.position.x, transform.position.y);
  116.     }
  117.  
  118.     [ClientCallback]
  119.     void SendServerPlayerInputs()
  120.     {
  121.         CmdCalculatePlayerMovement(inputVector, curSpeed);
  122.     }
  123.  
  124.     [ClientCallback]
  125.     void ClientPrediction ()
  126.     {
  127.         if (!isServer)
  128.         {
  129.  
  130.  
  131.             latency = (setupScript.latency / 100f);
  132.  
  133.             playerRigidbody.velocity = inputVector * curSpeed;
  134.  
  135.            
  136.             clientTick = (Mathf.Round(Time.time * 100) / 100);
  137.             if (!clientPosDict.ContainsKey(clientTick))
  138.             {
  139.                 clientPosDict.Add(clientTick, transform.position);
  140.             }
  141.      
  142.  
  143.             //Clamp count to 20 / 200ms
  144.             if (clientPosDict.ContainsKey(clientTick - 20))
  145.             {
  146.                 clientPosDict.Remove(clientTick - 20);
  147.             }
  148.  
  149.             if (serverPosDict.ContainsKey(serverTick - 20))
  150.             {
  151.                 serverPosDict.Remove(serverTick - 20);
  152.             }
  153.  
  154.             //Check server dictionary
  155.             if (serverPosDict.Count == 0)
  156.             {      
  157.                 return;
  158.             }
  159.             else
  160.             {
  161.                 //If server dictionary contains the client's tick, check for error.
  162.                 if (clientPosDict.ContainsKey(serverTick + latency))
  163.                 {
  164.                     Debug.Log("Fired");
  165.                     float errorX = serverPosDict[serverTick].x - clientPosDict[serverTick + latency].x;
  166.                     float errorY = serverPosDict[serverTick].y - clientPosDict[serverTick + latency].y;
  167.  
  168.                     if (Mathf.Abs(errorX) > locationTolerance)
  169.                     {
  170.                         Debug.Log("Error in X: " + errorX);
  171.                         //Correct error in x                    
  172.                     }
  173.  
  174.                     if (Mathf.Abs(errorY) > locationTolerance)
  175.                     {
  176.                         Debug.Log("Error in Y: " + errorY);
  177.                         //correct error in y
  178.                     }
  179.                 }
  180.             }          
  181.         }
  182.     }
  183.  
  184.     //hook function for getting the server position
  185.     //timestamp relative to localplayer?
  186.     [ClientCallback]
  187.     void GetServerPosition (Vector2 pos)
  188.     {
  189.         if (isLocalPlayer)
  190.         {
  191.             serverTick = Mathf.Round(Time.time * 100) / 100;
  192.  
  193.             if (!serverPosDict.ContainsKey(serverTick))
  194.             {
  195.                 serverPosDict.Add(serverTick, new Vector2(pos.x, pos.y));
  196.             }          
  197.         }  
  198.     }
  199. }
Advertisement
Add Comment
Please, Sign In to add comment