Search Unity

Spawn a new GameObject to clients from server at runtime

Discussion in 'Multiplayer' started by ElGuapo, Oct 27, 2016.

  1. ElGuapo

    ElGuapo

    Joined:
    Sep 27, 2016
    Posts:
    9
    Hi All,

    I have successfully used UNET to spawn prefabs that were added to the network spawnable prefabs in the unity editor for clients and servers. However, I need a way to spawn randomized GameObjects at runtime. Is it possible to have my server generate new GameObjects at runtime, and then spawn those onto the clients?

    So far in the code below I've been able to override the default spawning behavior by registering a client side spawn handler. Now when a server spawn command is issued, the remote client receives it's own spawn command. I've used this to spawn a cube on the host's client and a different cube (in green) on the remote clients in the code below.

    Instead of spawning a different cube in green on the remote client(s), I need someway to recreate the server's GameObject. Is it possible to use the assetID that is passed to reach back to the server and get the GameObject somehow? Or can I access the server's registered spawnable prefabs and recreate it on the client? Does anyone have any other ideas?


    Code (csharp):
    1.  
    2. public class TestEnemyManagerServer : NetworkBehaviour
    3. {
    4.     private bool isNextEnemySpawnEnabled = false;
    5.     private NetworkManager myNetMan;
    6.  
    7.     void Start ()
    8.     {
    9.         myNetMan= GameObject.Find ("Network Manager").GetComponent<NetworkManager>();
    10.         //Server will start checking for new enemy spawn requests every 2 seconds
    11.         if (isServer) {
    12.             InvokeRepeating ("SpawnEnemies", 2f, 2f);
    13.         }
    14.     }
    15.     public void SetNextEnemySpawnEnabled()
    16.     {
    17.         if (isServer) {
    18.             Debug.Log ("Server enabled next enemy spawn");
    19.             isNextEnemySpawnEnabled = true;
    20.         }
    21.     }
    22.  
    23.     void SpawnEnemies()
    24.     {
    25.         if (isServer) {
    26.             if (isNextEnemySpawnEnabled) {
    27.                 Debug.Log ("Server preparing to spawn new enemy at runtime");
    28.                 GameObject theCube = GameObject.CreatePrimitive(PrimitiveType.Cube);
    29.                 theCube.transform.position = new Vector3 (0, 2, 0);
    30.                 theCube.AddComponent<NetworkIdentity> ();
    31.  
    32.                 //Generate a new unique assetId here - not currently unique
    33.                 NetworkHash128 myAssetId = NetworkHash128.Parse("e2656f");
    34.  
    35.                 //Add to the registered spawnable prefabs for network spawning
    36.                 myNetMan.spawnPrefabs.Add(theCube);
    37.  
    38.                 //Call the client to register the spawn handler via RPC
    39.                 RpcLoadPrefab (myAssetId);
    40.  
    41.                 Debug.Log ("Server spawning object across clients");
    42.                 NetworkServer.Spawn(theCube,myAssetId);
    43.  
    44.                 //Set trigger bool back to false
    45.                 isNextEnemySpawnEnabled = false;
    46.             }
    47.         }
    48.     }
    49.  
    50.     [ClientRpc]
    51.     void RpcLoadPrefab(NetworkHash128 assetId)
    52.     {
    53.         Debug.Log ("Server called the Client RPC to register a client-specific handler");
    54.         ClientScene.RegisterSpawnHandler(assetId, SpawnEnemyHandler, UnSpawnEnemyHandler);
    55.     }
    56.  
    57.     //This is only runs on remote clients
    58.     public GameObject SpawnEnemyHandler(Vector3 position, NetworkHash128 assetId)
    59.     {
    60.         Debug.Log ("We have entered the client-specific spawn handler");    
    61.         //Here we create a cube (but make it green instead) to illustrate separate functionality
    62.         //Normally we would want to recreate the same game object that the server used
    63.         GameObject otherCube = GameObject.CreatePrimitive(PrimitiveType.Cube);
    64.         otherCube.transform.position = position;
    65.         otherCube.AddComponent<NetworkIdentity> ();
    66.         otherCube.GetComponent<MeshRenderer>().material.color = Color.green;
    67.         return otherCube;
    68.  
    69.         //HELP - How can I access the server's game object from here?
    70.         //Can I do something with assetId here?
    71.     }
    72.    //This is only runs on remote clients
    73.     public void UnSpawnEnemyHandler(GameObject spawned)
    74.     {
    75.         Destroy (spawned);
    76.     }
    77. }
    78.  
    I've looked for days and have found nothing but dead ends. I've seen this question asked all in multiple threads, but haven't found any legit answers yet. Please help!
     
    Last edited: Oct 27, 2016
  2. peterpi

    peterpi

    Joined:
    May 18, 2013
    Posts:
    20
    No.

    What you could do is have the server send a spawn command for a prefab that serves as a common start point, and then call a series of ClientRpc functions to modify that instance into the desired object. That's how I'd do something like user-customizable avatars. Obviously the more open-ended the objects you want to spawn, the more work you'll have to do.
     
  3. ElGuapo

    ElGuapo

    Joined:
    Sep 27, 2016
    Posts:
    9
    I hadn't thought of doing it this way, but it makes total sense. Thanks for the advice!

    I do have very complicated GameObjects, so this could get quite ugly. I'll try to see if I can serialize some of the more complicated parts to preserve my sanity.

    (I wish the documentation spelled this out. It talks about setting up the spawn handlers for spawning dynamic prefabs, but doesn't mention how you would actually go about doing that.)
     
  4. Oattjv

    Oattjv

    Joined:
    Jun 28, 2017
    Posts:
    2
    did you find out the solution?? I've got the same issue here..
     
  5. Joe-Censored

    Joe-Censored

    Joined:
    Mar 26, 2013
    Posts:
    11,847
    Did you try peterpi's idea? That is the way I would go with it. Spawn a known base prefab, and then send instructions to the clients using the various methods available to construct the custom object.
     
  6. ElGuapo

    ElGuapo

    Joined:
    Sep 27, 2016
    Posts:
    9
    Unfortunately I did not. If I remember correctly, it became too cumbersome due to the many problems with the underlying assets I had chosen.

    I am by no means an expert in unity, so don't take my experience to mean that it is not possible. I generally remember being disappointed with how Unity (and many of it's assets) seems to be more aimed at a GUI/Load Time configuration and how difficult it was to specify Dynamic/Run Time configuration. I hope you will fare better than I. Good luck!
     
  7. Oattjv

    Oattjv

    Joined:
    Jun 28, 2017
    Posts:
    2
    still stuck at it now :(