Search Unity

Parenting over a network?

Discussion in 'Multiplayer' started by Vertnacular, Jan 18, 2018.

  1. Vertnacular

    Vertnacular

    Joined:
    Oct 15, 2017
    Posts:
    12
    So I'm creating a multiplayer VR game and I have a good setup for the player prefab. A player can spawn in and their controllers and headset are tracked and sent over the network using the network transform child component. I can see their transforms update on both a host and client.

    To handle the VR side of things, I'm using VRTK. Basically VRTK will allow me to control picking up and dropping items, and really anything the player interacts with on their instance of the scene.

    Now an item the player can pick up has a network identity and network transform on it so that the other players can see it move when the player is not interacting with it. To save some bandwidth, I was hoping to take the instance of the item on every client and just parent to the controller instance under the player prefab for each client and then turn off the network transform for the item. I figured that it would be redundant to track the player's controller and the item they are holding. And when they drop the item, just turn it back on so the transform would be updated again.

    The problem is, I'm having a hard time getting each client to update the parent of the item to that player's hand. Using VRTK, it's no problem having the local player pick up the item. I wrote a script to say "hey, I was just picked up and this is my new parent (the controller), take that info and send a command to the server and RPC the clients this new parent and set it" But it doesn't seem to work. I've tried sending the game object via the Cmd and Rpc, but figured that each client would have a different memory path to their version of the game objects in their scene. So I tried putting a Network Identity on the controllers (despite Unity not liking the player prefab having more than one net id) and using clientscene.findlocalobject to get the shared id of the controllers and set it that way. But once again, nada.

    Am I not approaching this problem correctly? Or maybe I am but my execution is not right? I'm throwing random things into the code at this point, hoping to make it stick.

    I've tried finding an answer searching various forums and either came up with an answer that uses the outdated networkview or their solution doesn't seem to work. I should mention I'm using ver 2017.3.0f3, If you need anymore info let me know. If anyone has any ideas, it would be much appreciated.

    Thanks!
     
  2. Vertnacular

    Vertnacular

    Joined:
    Oct 15, 2017
    Posts:
    12
    I've tried many different ways so far. I've used syncvar's and hooks or sending different info through RPC's. But they all seem to have the same result. This is one way I tried:

    Code (CSharp):
    1. [Command]
    2.     public void CmdSetParent()
    3.     {
    4.         NetworkInstanceId parentId = transform.root.GetComponent<NetworkIdentity>().netId;
    5.         string controllerName = transform.parent.name;
    6.         string location = ClientScene.FindLocalObject(parentId).name + "/Character/" + controllerName;
    7.         //A bit redundant to set parent again
    8.         transform.SetParent(GameObject.Find(location).transform);
    9.         RpcSetParent(location);
    10.     }
    11.  
    12.     [ClientRpc]
    13.     public void RpcSetParent(string goLocation)
    14.     {
    15.         transform.SetParent(GameObject.Find(goLocation).transform);
    16.     }
    If a client tries to pick up the object, It does nothing. But When the host picks up the object, it parents correctly on both the host and client. So this leaves me to believe that I'm not fully doing it wrong.

    After reading the doc's for the 20th time, I'm starting to believe it might have something to do with authority??? The non player object's network info on the host is as followed:

    Is Client: Yes
    Is Server: Yes
    Has Authority: No
    Is Local Player: No

    But as a client, Is Client: Yes, is the only yes.

    Makes sense. But now I'm thinking that the since the host is the server, they can dictate the parenting. But I figured that a Command would do the job since it's from the client to the server, then the server RPC's back to the clients (and host client).

    But maybe a client can't tell the server what to do? I'm really not sure, still pretty confused with the whole networking thing. Once you think you understand it, it throws you a house-sized curve ball.
     
  3. Vertnacular

    Vertnacular

    Joined:
    Oct 15, 2017
    Posts:
    12
    I think I'm heading in the right direction but I'm not really sure. So I've noticed that when the client tries to pick up the object and I want to send the command to tell the server to do the same. I get a warning message "Trying to send command for object without authority." So I'm thinking that I can just use:

    Code (CSharp):
    1. GetComponent<NetworkIdentity>().RemoveClientAuthority(GetComponent<NetworkIdentity>().connectionToClient);
    2.         GetComponent<NetworkIdentity>().AssignClientAuthority(transform.root.GetComponent<NetworkIdentity>().connectionToClient);
    to clear any client authority and then set the authority to the parent player object that is holding the item. But now I get an error message "AssignClientAuthority can only be call on the server for spawned objects." So I'm thinking that I'll need to set it in the Command, because the the client needs to tell the server to do something... But that's a bit of a catch 22. Can't send a command without authority and can't set authority without sending a command. So I read up on [Server] and [ServerCallback] thinking that I might be able to use the server to do the assigning of authority. But once again it doesn't seem to work.

    I feel like I'm half on track, but the doc's don't really do a great explanation in layman's term. And that's when there's any explanation at all...
     
  4. Vertnacular

    Vertnacular

    Joined:
    Oct 15, 2017
    Posts:
    12
    Just had the "Oh that makes sense" moment...

    So for future reference to anyone googling like crazy on how to parent an object over the network. You don't want the object to send the command that it is changing it's parent. You have to have the player object issue the command. So what I did was to create a script that is on the item and when it is picked up and locally parented under the controller, go to the root of the player prefab and call a second script. This second script will have the [Command] and [ClientRpc]. It takes in the item's netID and controller(sub parent item) and does it's magic, then calls the ClientRpc. Here's a really sloppy way I put it together. I'll clean it up and try it without using a string to locate the item.

    Code (CSharp):
    1. public void CallCommand(string controllerName, NetworkInstanceId idNum)
    2.     {
    3.         CmdSetParent(controllerName, idNum);
    4.     }
    5.  
    6.     [Command]
    7.     public void CmdSetParent(string controllerName, NetworkInstanceId idNum)
    8.     {
    9.         //Where the item is locally
    10.         string location = ClientScene.FindLocalObject(netId).name + "/Character/" + controllerName;
    11.         //Find the item based on the netid
    12.         GameObject item = ClientScene.FindLocalObject(idNum);
    13.         //Parent object
    14.         item.transform.SetParent(GameObject.Find(location).transform);
    15.         item.transform.localPosition = Vector3.zero;
    16.         item.transform.localRotation = Quaternion.identity;
    17.         //Call Rpc
    18.         RpcSetParent(location, idNum);
    19.     }
    20.  
    21.     [ClientRpc]
    22.     public void RpcSetParent(string goLocation, NetworkInstanceId idNum)
    23.     {
    24.         //Tell clients to parent the item correctly
    25.         GameObject item = ClientScene.FindLocalObject(idNum);
    26.         item.transform.SetParent(GameObject.Find(goLocation).transform);
    27.         item.transform.localPosition = Vector3.zero;
    28.         item.transform.localRotation = Quaternion.identity;
    29.     }
    I was confused because the doc's talk about "Starting with Unity release 5.2, it is possible to have client authority over non-player objects". So you start thinking about how the player needs to assign authority and what not. A lot of the networking terms are confusing but such is networking I guess.
     
  5. unity_Cn_9LZVSq85wBA

    unity_Cn_9LZVSq85wBA

    Joined:
    Apr 30, 2019
    Posts:
    5
    Hi @Vertnacular ,
    I'm working on a VR multiplayer project and have a problem when combine VRTK and Networking.

    To test, I create a scene with a cube which has network identity and network transform, vrtk_interactable object and vrtk_interact grab.
    All I want to do is run the scene in 2 machines and have 2 players who can grab the cube and throw.
    But in my case, only the host player can interact with the cube, the client player can't do this. However, the client can see the cube's position change.
    The player prefab structure and the cube configuration is in the attached image.
    Can you help me to figure it out ? Thank you very much.
     

    Attached Files:

  6. Joe-Censored

    Joe-Censored

    Joined:
    Mar 26, 2013
    Posts:
    11,847
    Note that Unet doesn't actually support GameObjects with a NetworkIdentity component as children of another object. Objects with a NetworkIdentity component are supposed to be at the root of the scene, or you will get unexpected behavior. Also Unet was deprecated a year ago and hasn't received significant updates or bugfixes in several years. Unless your game is all but complete by now, you should switch to another API.
     
    vlogesh2001 likes this.
  7. unity_Cn_9LZVSq85wBA

    unity_Cn_9LZVSq85wBA

    Joined:
    Apr 30, 2019
    Posts:
    5
  8. mrrevsalt

    mrrevsalt

    Joined:
    Aug 3, 2019
    Posts:
    1
    i had a feeling this was way too complex for my games so i had to find a way around it !! i kept searching for about a week now and an idea jumped to my head i could use animators yet its an insignificant way of using my animations but it worked and i was able to parent stuff using animation functions !!! i even had different animators and had scripts reach out to the main script with the net identity!! it was way easier !!!
     
  9. Giantbean

    Giantbean

    Joined:
    Dec 13, 2012
    Posts:
    144
    So if RPC was removed as part of the legacy networking in 2018.2 how is this done with NetworkIdntity using mirror? Maybe the network transform child script? In Steam VR the object picked up by one client disappears from view on other clients until the object is dropped again (similar to THIS). RPC seemed like a solution but I'm not having any luck. @mrrevsalt how did you do this with animators?