Search Unity

[Solved] Need help on destroying objects when either the server or the client disconnects

Discussion in 'Multiplayer' started by asperatology, May 30, 2015.

  1. asperatology

    asperatology

    Joined:
    Mar 10, 2015
    Posts:
    976


    I made a small Unity project with the aim to fix this scenario where the player, client or server, disconnects from the game. I need to make the game destroy all units (the 2 balls) on the screen in order to free up unwanted resources, otherwise there will be memory leaks and inconsistent states causing desyncs.

    I used a UnitManager singleton instance on both the client and the server, so there's only 1 instance of UnitManager for each player.

    Code (CSharp):
    1. public class UnitManager : MonoBehaviour {
    2.     public static UnitManager instance;
    3.  
    4.     public static readonly int PG_Player = 1;
    5.     public static readonly int PG_Enemy = 2;
    6.  
    7.     public List<GameObject> PlayerUnits = new List<GameObject>();
    8.  
    9.     public void Awake() {
    10.         UnitManager.instance = this;
    11.     }
    12. }
    When the client connects to the server, it initializes the game board by using Network.Instantiate() to instantiate 1 unit (the ball) to each player. So, there are two units in the game, but there's only 1 unit in the UnitManager in the perspective of the client's/server's application. That 1 unit was added to to UnitManager when it was instantiated.

    Code (CSharp):
    1. [RPC]
    2.     public void RPC_Instantiate() {
    3.         if (this.playerSpawns != null && this.playerSpawns.Length > 0 && this.playerSpawns.Length > this.playerNumber-1) {
    4.             GameObject gameObject = (GameObject) Network.Instantiate(Resources.Load("Prefabs/Unit"), this.playerSpawns[this.playerNumber-1].transform.position, Quaternion.identity, 0);
    5.             if (gameObject != null) {
    6.                 gameObject.name = gameObject + " " + this.playerNumber;
    7.                 UnitManager.instance.PlayerUnits.Add(gameObject);
    8.             }
    9.         }
    10.     }
    The main trouble I am having is to destroy these network-instantiated units by using Network.Destroy(). Since there's only 1 unit in the UnitManager, when calling on Network.Destroy(), it only destroys 1 unit, which is the unit that the client/server is owning. The other unit is left in the game with no other methods of destroying it. It also left the client in an infinite loop of not being able to locate the associated network (since the network is already disconnected).



    What methods can I do to destroy game objects for both the client and the server when any one of them disconnects?

    Thanks in advance.
     
  2. asperatology

    asperatology

    Joined:
    Mar 10, 2015
    Posts:
    976
    Okay, I solved it. Thanks to this thread for pointing me in the right direction.

    I need a script that is to be placed in the scene. This script's purpose is to be triggered by a disconnection from either the server or the client. Once triggered, it will run, just as if the game is a single player mode.

    Code (CSharp):
    1. public void OnDisconnectedFromServer(NetworkDisconnection info) {
    2.     Debug.LogWarning("Unit Manager: On disconnected from server.");
    3.     foreach (GameObject g in this.PlayerUnits) {
    4.         Object.Destroy(g);
    5.     }
    6.     if (this.PlayerUnits.Count > 0) {
    7.         this.PlayerUnits.Clear();
    8.     }
    9. }
    10.  
    11. public void OnPlayerDisconnected(NetworkPlayer player) {
    12.     Debug.LogError("Simple Network Manager: Disconnected by player.");
    13.     foreach (GameObject g in this.PlayerUnits) {
    14.         Object.Destroy(g);
    15.     }
    16.     if (this.PlayerUnits.Count > 0) {
    17.         this.PlayerUnits.Clear();
    18.     }
    19. }
    And then I need another script that is added to the prefab that I am going to Network.Instantiate() when both the server and the client are ready to start the game. This script will automatically keep track of each instantiated unit on both the server and the client side, thereby not missing one of the instantiated units and causing memory leaks.

    Code (CSharp):
    1. public class AddToUnitManager : MonoBehaviour {
    2.     public void Awake() {
    3.         UnitManager.instance.PlayerUnits.Add(this.gameObject);
    4.     }
    5. }
    So, here's how it works:
    1. Server and client both connects to each other.
    2. Everyone is ready to begin the game.
    3. I used Network.Instantiate().
    4. Upon instantiation, the spawned unit is added into the unit manager.
    5. Game does whatever it needs to do.
    6. When either the server or the client disconnects, that end user triggers the On...() methods.
    7. Each of the methods will act according to the type of end user it is (server or client), and will destroy unwanted resources.
    8. Cleaned! No more memory leaks.
    I solely wrote my posts like this, so that I won't forget when I need to look it up again in the future.
     
unityunity