Search Unity

Command object references

Discussion in 'Multiplayer' started by any_user, Jun 19, 2015.

  1. any_user

    any_user

    Joined:
    Oct 19, 2008
    Posts:
    374
    Reading the documentation, it's not clear to me which object references I should be able to pass around in commands. Can I pass any part (the gameobject itself, component) of a spawned object in a command? Do the have to be NetworkBehaviours?

    Code (CSharp):
    1. [Command]
    2. void CmdDoSomething(GameObject obj)
    3. {
    4.     // do something
    5. }
    6. [Command]
    7. void CmdDoSomething2(MyScriptAttachedToASpawnedObject obj)
    8. {
    9.     // do something
    10. }
    11.  
    I'm experiencing some problems with it and I don't understand if I'm just doing something that is not supported or if there's another problem. For example I was able to pass a NetworkIdentity reference of a runtime-spawned object but the same thing doesn't seem to work for a scene object (null reference exception on server)


    Code (CSharp):
    1.  
    2. // this works for a runtime-spawned object but not if obj is the identity of a scene object
    3. [Command]
    4. void CmdDoSomething(NetworkIdentity obj)
    5. {
    6.     // do something
    7. }
    8.  
    9.  
     
  2. seanr

    seanr

    Unity Technologies

    Joined:
    Sep 22, 2014
    Posts:
    669
    You cannot pass a component of a GameObject. You can pass a GameObject with a NetworkIdentity, a NetworkIdentity itself or a NetworkInstanceId.

    It shouldn't make a difference if the object is in the scene or spawned, both can be looked up on the server by NetworkInstanceId using NetworkServer.FindLocalObject.
     
    Ishidres likes this.
  3. any_user

    any_user

    Joined:
    Oct 19, 2008
    Posts:
    374
    It doesn't work in commands for me, sending a reference to a (dedicated) server. The same thing works when connected to a server that is a host.

    By looking into ReadGameObject function of NetworkReader, it looks like it always tries to find the object in the ClientScene, not NetworkServer.

    Code (CSharp):
    1.  
    2. public GameObject ReadGameObject ()
    3. {
    4.     NetworkInstanceId networkInstanceId = this.ReadNetworkId ();
    5.     if (networkInstanceId.IsEmpty ()) {
    6.         return null;
    7.     }
    8.     GameObject gameObject = ClientScene.FindLocalObject (networkInstanceId);
    9.     if (gameObject == null && LogFilter.logDebug) {
    10.         Debug.Log (string.Concat (new object[] {
    11.             "ReadGameObject netId:",
    12.             networkInstanceId,
    13.             "go:",
    14.             gameObject
    15.         }));
    16.     }
    17.     return gameObject;
    18. }
    This bug was already in the issue tracker and is marked as fixed there:
    http://issuetracker.unity3d.com/issues/networkreader-dot-readnetworkidentity-assumes-it-is-on-client

    Is this fix not yet in 5.1.1 ?
     
  4. any_user

    any_user

    Joined:
    Oct 19, 2008
    Posts:
    374
    For those who have the same issue, here's a workaround that works for commands in 5.1.1. Just pass the NetworkInstanceId instead of the object itself.

    Code (CSharp):
    1.  
    2.  
    3.     //instead of  
    4.    CmdDoSomething(someObject);
    5.  
    6.     CmdDoSomething
    7.     [Command]
    8.     public void CmdDoSomething(GameObject obj)
    9.     {
    10.         //do something with obj
    11.     }
    12.  
    13.     // send only the id
    14.     CmdDoSomethingWorkaround(someObject.GetComponent<NetworkIdentity>().netId);
    15.  
    16.     [Command]
    17.     public void CmdDoSomethingWorkaround(NetworkInstanceId objId)
    18.     {
    19.         GameObject obj;
    20.         if (Game.networkManager.isClient)
    21.             obj = ClientScene.FindLocalObject (objId);
    22.         else
    23.             obj = NetworkServer.FindLocalObject (objId);  
    24.         //do something with obj
    25.     }
    26.  
     
    Roiw likes this.
  5. shoo

    shoo

    Joined:
    Nov 19, 2012
    Posts:
    67
    Hello! Anyone know is it optimized to pass GameObject as parametr to Commad/Rpc? I mean, I can pass like int id or string name and then find object by this value. Does it need significantly more bandwidth to pass GameObject or it uses kinda same algorithm (pass ID and then find it on other side)?
     
  6. srylain

    srylain

    Joined:
    Sep 5, 2013
    Posts:
    159
    Assuming I'm right, if you were to send a GameObject as a parameter all they would do is send a reference/pointer to the object. And due to the way RAM works, I'd think a pointer on computer could point to completely different memory because you can have one person with 8GBs and another with 32GBs.

    Send the netID. And then find it on the server or other clients by using NetworkServer.FindLocalObject().
     
  7. Oshroth

    Oshroth

    Joined:
    Apr 28, 2014
    Posts:
    99
    As they said above, if you pass a gameobject with a NetworkIdentity to a Cmd or Rpc, it will send its netid and the server/clients on the other side will use FindLocalObject() to get the gameobject. Netid is guaranteed to be unique to an object and matches all network versions of that object.
    A pointer is completely useless outside of the computer that it is associated with, even if the computers had the same amount of ram, the program is running in a completely different address space.