Search Unity

Spawn objects instantly on the client

Discussion in 'Multiplayer' started by Michael_Waltham, Aug 26, 2015.

  1. Michael_Waltham

    Michael_Waltham

    Joined:
    Aug 20, 2014
    Posts:
    31
    I am aware that in order to spawn objects over the network, one must call NetworkServer.Spawn() on the Server. However, say for example the client fires a projectile on mouse click. On the client side, we don't want to wait for the server to receive the command to spawn the projectile but rather spawn the projectile instantly on the client and then notify the server.

    How can I go about doing this? (NetworkServer.Spawn() does not work on the client side)
     
  2. Michael_Waltham

    Michael_Waltham

    Joined:
    Aug 20, 2014
    Posts:
    31
  3. Samuel411

    Samuel411

    Joined:
    Dec 20, 2012
    Posts:
    646
    If you are doing,
    Code (CSharp):
    1. void SpawnProjectile(GameObject projectile)
    2. {
    3.       GameObject spawnedProjectile= Instantiate(projectile, position, rotation) as GameObject;
    4.       // Spawn On Server
    5.       CmdSpawnProjectileOnServer(spawnedProjectile);
    6. }
    7.  
    8. [Command]
    9. void CmdSpawnProjectileOnServer(GameObject projectile)
    10. {
    11.       NetworkServer.Spawn(projectile);
    12. }
    13.  
    Then it will instantiate the bullet on the local player, but it won't be spawned for everyone else until the Command is called.
     
  4. Michael_Waltham

    Michael_Waltham

    Joined:
    Aug 20, 2014
    Posts:
    31
    I have tried your code before and it doesn't work. When the client attempts to spawn a projectile, the server throws an error (not set to an instance of an object). It seems that Unet doesn't like having Gameobjects as arguments to RPC's? I am using Unity 5.1.3
     
  5. Samuel411

    Samuel411

    Joined:
    Dec 20, 2012
    Posts:
    646
    That means something isn't being set in your code. It should work fine, make sure your inputting the correct parameters.
     
  6. Michael_Waltham

    Michael_Waltham

    Joined:
    Aug 20, 2014
    Posts:
    31
    hmmm not sure what it could be. When the server spawns it works fine and appears on the client which means that all variables are set,=.
     
  7. mlukeyb

    mlukeyb

    Joined:
    Nov 8, 2014
    Posts:
    3
    Not sure if either of you found a solution to this problem. I am trying to do the same thing and also get the "Object reference not set to an instance of an object" error. Everything works when creating the object on the host client, but not on any other. Here is my code:

    Code (CSharp):
    1.  
    2. void Update() {
    3.     if (isLocalPlayer) {
    4.         if (Input.GetKeyDown (KeyCode.E)) {
    5.             GameObject tempProjectile = Instantiate(fireballPrefab, fireballStartObject.transform.position, Quaternion.identity) as GameObject;
    6.             CmdShoot (tempProjectile);
    7.        }
    8.     }
    9. }
    10.  
    11. [Command]
    12. void CmdShoot(GameObject projectile){
    13.     NetworkServer.Spawn(projectile);
    14. }
    Any idea what could be going wrong here? The fireballPrefab exists in the Registered Spawnable Prefabs of the network manager.

    NullReferenceException: Object reference not set to an instance of an object
    UnityEngine.Networking.NetworkServer.GetNetworkIdentity (UnityEngine.GameObject go, UnityEngine.Networking.NetworkIdentity& view) (at C:/buildslave/unity/build/Extensions/Networking/Runtime/NetworkServer.cs:1096)
    UnityEngine.Networking.NetworkServer.SpawnObject (UnityEngine.GameObject obj) (at C:/buildslave/unity/build/Extensions/Networking/Runtime/NetworkServer.cs:1302)
    UnityEngine.Networking.NetworkServer.Spawn (UnityEngine.GameObject obj) (at C:/buildslave/unity/build/Extensions/Networking/Runtime/NetworkServer.cs:1531)
    Player.CmdShoot (UnityEngine.GameObject projectile) (at Assets/Scripts/Player.cs:133)
    Player.InvokeCmdCmdShoot (UnityEngine.Networking.NetworkBehaviour obj, UnityEngine.Networking.NetworkReader reader)
    UnityEngine.Networking.NetworkBehaviour.InvokeCommandDelegate (Int32 cmdHash, UnityEngine.Networking.NetworkReader reader) (at C:/buildslave/unity/build/Extensions/Networking/Runtime/NetworkBehaviour.cs:303)
    UnityEngine.Networking.NetworkBehaviour.InvokeCommand (Int32 cmdHash, UnityEngine.Networking.NetworkReader reader) (at C:/buildslave/unity/build/Extensions/Networking/Runtime/NetworkBehaviour.cs:81)
    UnityEngine.Networking.NetworkIdentity.HandleCommand (Int32 cmdHash, UnityEngine.Networking.NetworkReader reader) (at C:/buildslave/unity/build/Extensions/Networking/Runtime/NetworkIdentity.cs:492)
    UnityEngine.Networking.NetworkServer.OnCommandMessage (UnityEngine.Networking.NetworkMessage netMsg) (at C:/buildslave/unity/build/Extensions/Networking/Runtime/NetworkServer.cs:1290)
    UnityEngine.Networking.NetworkConnection.HandleReader (UnityEngine.Networking.NetworkReader reader, Int32 receivedSize, Int32 channelId) (at C:/buildslave/unity/build/Extensions/Networking/Runtime/NetworkConnection.cs:416)
    UnityEngine.Networking.NetworkConnection.HandleBytes (System.Byte[] buffer, Int32 receivedSize, Int32 channelId) (at C:/buildslave/unity/build/Extensions/Networking/Runtime/NetworkConnection.cs:372)
    UnityEngine.Networking.NetworkConnection.TransportRecieve (System.Byte[] bytes, Int32 numBytes, Int32 channelId) (at C:/buildslave/unity/build/Extensions/Networking/Runtime/NetworkConnection.cs:522)
    UnityEngine.Networking.NetworkServer.InternalUpdate () (at C:/buildslave/unity/build/Extensions/Networking/Runtime/NetworkServer.cs:684)
    UnityEngine.Networking.NetworkServer.Update () (at C:/buildslave/unity/build/Extensions/Networking/Runtime/NetworkServer.cs:546)
    UnityEngine.Networking.NetworkIdentity.UNetStaticUpdate () (at C:/buildslave/unity/build/Extensions/Networking/Runtime/NetworkIdentity.cs:887)
     
  8. darthbator

    darthbator

    Joined:
    Jan 21, 2012
    Posts:
    169
    You cannot send reference types to the server in commands. Anything you send in a command needs to be serialized and then sent to the server. Doing that with something like a gameObject is apparently not supported in the HLAPI. The only way I have been able to track object between clients is using networkIDs (which are functionally strings).

    UNET Command parameters appear to be limted to int, float, enum, string, Vect2, Vect3, Vect4 and user defined structs.
     
  9. vanshika1012

    vanshika1012

    Joined:
    Sep 18, 2014
    Posts:
    48
  10. Freakyuno

    Freakyuno

    Joined:
    Jul 22, 2013
    Posts:
    138
    Are you getting the object null error on Line 6 or line 13 in the above reference? There's a cast happening on line 6 that could possibly come out null.

    All variables passed around in C# are byvalue, by default. Reference objects are only passed as reference types if you explicitly state ref or out.

    But...it still should be serializable if you pas it by value. Try something like this

    Code (CSharp):
    1. public void Update()
    2. {
    3.    
    4.     if (isLocalPlayer){
    5.         if (Input.GetKeyDown(KeyCode.E))
    6.         {
    7.              
    8.                 GameObject tempProjectile = (GameObject)Instantiate(fireballPrefab, fireballStartObject.transform.position, Quaternion.identity);
    9.                   CmdShoot (tempProjectile);
    10.  
    11.         }
    12.     }
    13. }
    14.  
    15. public void CmdShoot(GameObject projectile){
    16.     if (projectile == null)
    17.     {
    18.         Debug.Log("No game object was received from the client to the server method");
    19.         return;        
    20.     }
    21.     NetworkServer.Spawn(projectile);
    22. }
    Two things happen here. 1, we use a non-nullable cast into tempProjectile, if it fails there, it should throw an exception. Secondly, we make sure we're getting something in the server command.
     
  11. vanshika1012

    vanshika1012

    Joined:
    Sep 18, 2014
    Posts:
    48
    @Freakyuno I have tried everything. If I am calling command function from both server and client but on client it is not working.

    In my game GameObject is colliding with some element let say food. When it collide with food, it instantiate something. code is working fine on server side, but not on Client. Following is my code :-

    private void CmdCheckForFood(Vector3 snakePartPosToBeInitialize,Vector3 headPos)
    {
    if(_food != null)
    {
    if (_food.transform.position == headPos)
    {

    UiControllerCS.UI.showScore();
    CmdCreatePartSnake();
    }
    }
    }

    [Command]
    public void CmdCreatePartSnake()
    {
    Vector3 lastPos = new Vector3(0,0,0);
    Vector3 parentPos = HeadTransform.position;
    Debug.Log("tailcount"+tail.Count);
    for (int i = 0; i < tail.Count; i++)
    {
    Vector3 currPos = tail.transform.position;
    if (i == tail.Count - 1)
    {
    lastPos = currPos;
    }
    tail.transform.position = parentPos;
    parentPos = currPos;
    }
    GameObject obj = Instantiate(snakePart,lastPos , Quaternion.identity) as GameObject;
    currPartOfSnake += 1;
    obj.name = "" + currPartOfSnake;
    obj.transform.parent = gameObject.transform;
    tail.Add(obj);
    if(isLocalPlayer)
    NetworkServer.SpawnWithClientAuthority(obj , connectionToClient);

    }