Search Unity

Score doubles every time when default is set value? - help please

Discussion in 'Multiplayer' started by djgriff, Mar 21, 2018.

  1. djgriff

    djgriff

    Joined:
    May 29, 2014
    Posts:
    279
    Hello,

    I have setup a simple player score system where i keep track of the player who shots a bullet and the last player to hit the target is cached. If that player who shot kills the enemy i ive them 10 ppoints. How ever the strange thing is first kill it awards 10 points, then second kill it adds 20, then 30 for the 3rd kill.. like for some reason the server is adding the last kill value to the next value.!?
    It should be 10 each time..

    Does anyone know what might be going wrong here?

    I have a syncvar hook on the AddScore

    The enemy before getting destroyed calls a command to the player object which is cached.

    Not sure why it is doing this.

    Oh and this only seems to happen for clients connecting to player who is hosting the server

    Any advise would be great. Thanks
     
  2. Joe-Censored

    Joe-Censored

    Joined:
    Mar 26, 2013
    Posts:
    11,847
    I'm sure your issue is specific to how you're written your code, so please post the code.
     
  3. djgriff

    djgriff

    Joined:
    May 29, 2014
    Posts:
    279
    PlayerShoots and with pass the player gameobject the the instantiated bullet:

    Code (CSharp):
    1. [Command]
    2.         private void CmdShoot()
    3.         {
    4.             Bullet bullet = null;
    5.             bullet = _bulletPrefab.GetComponent<Bullet>();
    6.  
    7.             Rigidbody rbody = Instantiate(_bulletPrefab, _bulletSpawn.position, _bulletSpawn.rotation) as Rigidbody;
    8.             rbody.GetComponent<Bullet>()._playerWhoShot = this.gameObject;
    9.             _muzzleFlash.SetActive(true);
    10.             Invoke("DisableMuzzleFlash", .1f);
    11.             if (rbody != null)
    12.             {
    13.                 rbody.velocity = bullet._speed * _bulletSpawn.transform.forward;
    14.                 NetworkServer.Spawn(rbody.gameObject);
    15.             }
    16.         }
    Called on the instantiated bullet controller when it hits an enemy:

    Code (CSharp):
    1. [Command]
    2.     public void CmdDamageEnemy(int damage, GameObject enemy, GameObject whoShotThis)
    3.     {
    4.         enemy.GetComponent<EnemyStats>().RpcDamageEnemy(damage, whoShotThis);
    5.     }
    Then on the enemy we cache the last player to hit the enemy and if he is dead call the command to add score:
    Code (CSharp):
    1. [ClientRpc]
    2.     public void RpcDamageEnemy(int damage, GameObject playerWhoShot)
    3.     {
    4.  
    5.         if (_health > 0)
    6.         {
    7.             _health -= damage;
    8.             //Debug.Log("Dealing damageof: " + damage);
    9.             _lastPlayerToHit = playerWhoShot;
    10.         }
    11.     }
    12.  
    13.  
    14.     [Command]
    15.     public void CmdDestroyEnemy(GameObject obj, GameObject player, int score)
    16.     {
    17.         _isDead = true;
    18.         GameObject explode = Instantiate(_explosionEffect, transform.position, Quaternion.identity);
    19.         NetworkServer.Spawn(explode);
    20.         player.GetComponent<PlayerManager>().AddScore(score);
    21.         Destroy(explode, 3);
    22.         Destroy(obj);
    23.     }

    Add the score for killing the enemy:


    Code (CSharp):
    1.        
    2. [SyncVar(hook = ("AddScore"))]
    3.         public int _score = 0;
    4.  
    5.  public void AddScore(int score)
    6.         {
    7.             Debug.Log(score);
    8.             _score += score;
    9.             Debug.Log("ScoreAfter: " + _score.ToString());
    10.             _scoreText.text = "SCORE: " + _score.ToString();
    11.         }

    Hope this makes sense and think i am going about it the right way. Any pointers would be great.

    Thanks
     
  4. Joe-Censored

    Joe-Censored

    Joined:
    Mar 26, 2013
    Posts:
    11,847
    So here is what is happening:

    1) Client calls CmdDestroyEnemy and passes a score (lets say 10)
    2) CmdDestroyEnemy calls AddScore and passes in 10 on the server
    3) AddScore takes syncvar _score and adds its value to the 10, so lets say it was already 10 so is now 20
    4) _score syncvar change causes it to propagate to the client the value of 20 for _score
    5) On the client the syncvar hook AddScore is called and passes in the value of _score of 20
    6) AddScore on the client then adds the previous value of _score (10) to the current value of 20 on your line 8 of that function, to set it locally on the client to 30 - this results in the value of syncvar _score on the client to be out of sync with the server value.

    Id recommend in the SyncVar hook you use on the client to just set _score to the value instead of adding, as you already did the adding on the server before the updated value of the syncvar was sent to the client. You don't need to reuse the same function on the client as a syncvar hook that you use for adding to the value of the syncvar on the server.
     
  5. djgriff

    djgriff

    Joined:
    May 29, 2014
    Posts:
    279
    Thank you for your detailed explanation, most superb and helpful.

    not sure i fully understand you last sentence.

    From what i understand you would just do : _score = score; correct? - i tried this but it always stays at 10..

    So a little confused. I tried checking if its not server and returning..
    also if not player and returning..

    dont suppose you have example ..

    would you just remove the synvar?

    thanks for your time
     
  6. djgriff

    djgriff

    Joined:
    May 29, 2014
    Posts:
    279
    strange thing is if i change it to a sync var it works for the player hosting but not the connected player..?
     
  7. Joe-Censored

    Joe-Censored

    Joined:
    Mar 26, 2013
    Posts:
    11,847
    So when a syncvar is updated it sends the new value to the client. So you just need to avoiding adding to it twice like you're doing. Right now you are adding to _score on the server, and then adding again to it on the client. Don't do that, as the _score syncvar is already at the updated value when the client receives it. So on the client you just set it, you don't increment it again because the server already did that and sent the updated value to the client.

    Code (CSharp):
    1.    
    2. [SyncVar(hook = ("ScoreHook"))]
    3. public int _score = 0;
    4.  
    5. //Used on server to update the score
    6. public void AddScore(int score)
    7. {
    8.     Debug.Log(score);
    9.     _score += score;
    10.     Debug.Log("ScoreAfter: " + _score.ToString());
    11.     _scoreText.text = "SCORE: " + _score.ToString();
    12. }
    13.  
    14. //Used when client receives updated score from the server
    15. public void ScoreHook(int score)
    16. {
    17.     Debug.Log(score);
    18.     _score = score;
    19.     Debug.Log("ScoreAfter: " + _score.ToString());
    20.     _scoreText.text = "SCORE: " + _score.ToString();
    21. }
    22.  
     
  8. djgriff

    djgriff

    Joined:
    May 29, 2014
    Posts:
    279
    Aah damn i see the light!
    Thanks man.. i have been doing it so wrong to date.. arrghh i have to correct lots of code! thank you so much for taking the time to explain!

    Big thanks
     
  9. djgriff

    djgriff

    Joined:
    May 29, 2014
    Posts:
    279
    Works beautifully thank you
     
  10. Joe-Censored

    Joe-Censored

    Joined:
    Mar 26, 2013
    Posts:
    11,847
    Glad to hear :)