Search Unity

Question Destroy objects (Ammos) when client disconnects

Discussion in 'Netcode for GameObjects' started by Erenquin, Jul 17, 2021.

  1. Erenquin

    Erenquin

    Joined:
    Apr 9, 2018
    Posts:
    164
    Hello,
    I'm new to multiplayer, I followed few tutorials.
    I have a setup which works quite well, but have an issue when client disconnects.

    So my game is very small:
    2 players facing each other and firing.
    When an ammo hits the other player score is increased.
    The ammos are generated from an object pooling and are Spawned with ownership.
    I test only in play mode, using Parrelsync to open a clone of my project.

    My issue is, when a client disconnects (when I stop the "Play" mode in the editor), the alive ammos still stay on the server, and they do not move.
    So I setup a callback, which is called, but at this time the ammos are not owned any more and so are not destroyed.
    If I understand well only the owner can call a server RPC.
    So what is the solution ?

    Thanks for the help :)

    Code (CSharp):
    1.    
    2.     void Start()
    3.     {
    4.         NetworkManager.Singleton.OnClientDisconnectCallback += DestroyOwnedAmmos;
    5.     }
    6.  
    7.     private void DestroyOwnedAmmos(ulong obj)
    8.     {
    9.         Debug.Log("disconnect callback " + IsOwner);
    10.         if (IsOwner) // Owner is false
    11.         {
    12.             DestroyServerRpc(transform.GetComponent<NetworkObject>().NetworkObjectId);
    13.         }
    14.     }
    15.  
    16.     [ServerRpc]
    17.     void DestroyServerRpc(ulong objectid)
    18.     {
    19.         ObjectPool.instance.ReturnToPool(gameObject);
    20.     }
    21.  
     
  2. Erenquin

    Erenquin

    Joined:
    Apr 9, 2018
    Posts:
    164
    One thing is in "ReturnToPool" I use Despawn(), which indeed destroys the object on client, but not on the server.
    That is how the ObjectPooling() tutorial shows to do.
    It works well, until a client disconnects.
     
  3. luke-unity

    luke-unity

    Joined:
    Sep 30, 2020
    Posts:
    306
    OnClientDisconnectCallback also gets called on the server. Try to check for `IsServer` and have the server return the ammo to the pool instead of sending an RPC. Also do you really want to destroy the ammo here on the server? You probably just want to disable the object while it's inside the pool and re-use it later.
     
  4. Erenquin

    Erenquin

    Joined:
    Apr 9, 2018
    Posts:
    164
    Hello, thanks a lot for the reply.
    For the record I followed this tutorial:

    If anyone is aware of a better one that combines object pooling and MLapi, including disconnection handling, do not hesitate.

    As per your advice I modified the callback like so.
    And I renamed it as I indeed do not want to destroy. I made some trials to destroy to see if it can get any better, but no.

    Code (CSharp):
    1.     // OnClientDisconnectCallback - When client disconnect destroys its ammos
    2.     private void DespawnAmmo(ulong obj)
    3.     {
    4.         if (IsOwner)
    5.         {
    6.             DespawnServerRpc(transform.GetComponent<NetworkObject>().NetworkObjectId);
    7.         }
    8.         else if (IsServer)
    9.         {
    10.             ObjectPool.instance.ReturnToPool(gameObject, false);
    11.         }
    12.     }
    Here is the implementation of return to pool:
    Code (CSharp):
    1.     public void ReturnToPool(GameObject go, bool despawn = true)
    2.     {
    3.  
    4.         Debug.Log("Putting back in pool ");
    5.         PoolAmmo(go);
    6.         if (despawn) go.GetComponent<NetworkObject>().Despawn();
    7.     }
    This helps, now when the client disconnects the ammo are disabled on the host.
    But if the client re-connects I have 2 issues:
    1) the ammo are reactivated, with no velocity. So they are only visible.
    2) when I fire with the host, I get a message saying the ammo is already spawned. This happens even if the client did not reconnect.

    This means that the ammo is not despawned on server side.
    This could be expected as the despawn boolean is false, but, if I set it to true, at that moment I have a message:
    SpawnStateException: Object is not spawned
     
  5. luke-unity

    luke-unity

    Joined:
    Sep 30, 2020
    Posts:
    306
    Sorry it is really hard to tell what you are doing wrong without the code of `OnClientDisconnectCallback` and `DespawnServerRpc`. Could you post that code please?
     
  6. Erenquin

    Erenquin

    Joined:
    Apr 9, 2018
    Posts:
    164
    I think I found a solution by checking if the ammo is active, so in Despawn ammo I modified the test like so:
    Code (CSharp):
    1. else if (IsServer && gameObject.activeSelf)
     
  7. Erenquin

    Erenquin

    Joined:
    Apr 9, 2018
    Posts:
    164
    Hello,
    here are the methods you requested:
    Code (CSharp):
    1.     void Start()
    2.     {
    3.         NetworkManager.Singleton.OnClientDisconnectCallback += DespawnAmmo;
    4.     }
    5.  
    6.     // OnClientDisconnectCallback - When client disconnect destroys its ammos
    7.     private void DespawnAmmo(ulong obj)
    8.     {
    9.         if (IsOwner)
    10.         {
    11.             DespawnServerRpc(transform.GetComponent<NetworkObject>().NetworkObjectId);
    12.         }
    13.         else if (IsServer && gameObject.activeSelf)
    14.         {
    15.             ObjectPool.instance.ReturnToPool(gameObject, true);
    16.         }
    17.     }
    18.  
    19.     [ServerRpc]
    20.     void DespawnServerRpc(ulong objectid)
    21.     {
    22.         ObjectPool.instance.ReturnToPool(gameObject);      
    23.     }
     
  8. luke-unity

    luke-unity

    Joined:
    Sep 30, 2020
    Posts:
    306
    So the RPC you have here does nothing. You can remove it. It will never arrive on the server because the client is already disconnected a this point. I see that you changed the ReturnToPool to `true` in this latest iteration which was `false` before. I think it should be true because you want to despawn the object here.
     
  9. Erenquin

    Erenquin

    Joined:
    Apr 9, 2018
    Posts:
    164
    Yes it is working fine.
    And the boolean is not necessary any more it is always true now so I removed it.

    The last issue I have, but I will keep as it is for now, is that this implementation also despawns/deactivates the ammos fired by the host.
    With 2 players it is no big deal but I plan to have up to 4 players at once.

    Anyway I want to do other stuff and will hopefully learn stuff and be able to do things better.

    Thanks a lot for the help.