Search Unity

Spawn objects from clients UNET

Discussion in 'UNet' started by hugettini, Jun 12, 2015.

  1. hugettini

    hugettini

    Joined:
    Apr 1, 2013
    Posts:
    19
    Hello, I'm testing the UNET system trying to switch my game from the old one to the new one, but I'm having some troubles.

    I already setup the server and the client with the network manager.

    I've spawned the player prefab (this object will control other players prefabs)
    There's a point which I need to spawn an object from the player prefab (this object has a NetworkIdentity and the player will control that object).

    If I spawn the object from the Client using

    Code (CSharp):
    1. GameObject go= (GameObject)Instantiate(prefab, transform.position, transform.rotation);
    2. NetworkServer.Spawn (go);
    The object is only spawned on the client.

    If I use a [Command] function to send it to the server, then it works ok and it's spawned everywhere.
    The problem is if the object is created on the server the client does not have the authority so I cannot call Command functions.
    Another problem is the instantiated gameobject is not destroyed when the player disconnects.

    What would be a good solution for that?

    Thank you!
     
    Last edited: Jun 12, 2015
    JoRouss, paluch.tiago and Miricks like this.
  2. Vapid-Linus

    Vapid-Linus

    Joined:
    Aug 6, 2013
    Posts:
    64
    Did you find an answer to this? I am in the same situation.
     
  3. seanr

    seanr

    Unity Technologies

    Joined:
    Sep 22, 2014
    Posts:
    669
    only the server can spawn objects.
     
  4. hugettini

    hugettini

    Joined:
    Apr 1, 2013
    Posts:
    19
    As #searn says, only server can spawn objects.

    My work arround was to use the instantiated player prefab as a bridge to control the server instantiated gameObject.

    But now I'm facing a lag problem with that object, I didn't had time to solve that.

    I'll post if I can fix that secondary issue.
     
  5. Vapid-Linus

    Vapid-Linus

    Joined:
    Aug 6, 2013
    Posts:
    64
    So, there's no way to spawn another object that is controller by the player..?
     
  6. Stardog

    Stardog

    Joined:
    Jun 28, 2010
    Posts:
    1,913
    Anyone got an answer to this? If a server spawns an object, how can the client call a function on one of its scripts?

    I have a building that is placed by CmdSpawnBuilding(). Any client/host can place a building that everyone sees, but they can't run any of its functions afterwards, even commands.

    Edit: You have to send the NetworkInstanceId of the object to the server. Get it from the object's NetworkIdentity component. Then the server can call whatever function you wanted on the gameobject.
     
    Last edited: Jul 27, 2015
    JoRouss likes this.
  7. EndUser

    EndUser

    Joined:
    Aug 12, 2013
    Posts:
    51
    Inaetaru likes this.
  8. EndUser

    EndUser

    Joined:
    Aug 12, 2013
    Posts:
    51
    It looks like you can choose from two routes:
    1) Your avatar sends message to his avatar (on your computer), and his avatar forwards message to server. Server's reaction is returned to his avatar on both of your computers.
    2) Your avatar sends message about his avatar to server, and server processes this message. The server returns new state of his avatar to both of your computers.
    Either way the authoritative server can verify messages from your computer.
    But I guess, the second way is more correct (although, first way is simpler). Yet, I have not reached this stage of my project yet.
     
  9. Inaetaru

    Inaetaru

    Joined:
    Aug 9, 2015
    Posts:
    16
    I'm having same problem, but after a few hours, I found the solution. It's not so easy.

    First, a few notes:
    • Networking uses something called "player controller id". It's a number (type: short) which is used to identify what you want to spawn. It's something like "spawned object type identificator". Value 0 (zero) is default, but all other values are free to use.
      • Note: it doesn't mean you can use only one prefab per single player controller id. You can select the prefab, send info about selected prefab to server through command (identify it with number, string or anything else which can be sent by command) and then use a player controller id (for example "1") to ask server to spawn the selected prefab.
    • In my system, I need to use something I call "default local player". It's instance of a prefab which was configured in NetworkManager class in field "Player Prefab" spawned by this very NetworkManager. From all players instances, the "local" one is the one representing (and controlled by) local player.
    My how-to:
    1. Define an ID for prefab type you want to spawn. This ID is player controller id I talked about above. In my example, I use number one.
    2. Derive a class from NetworkManager and override OnServerAddPlayer method. (Deriving from NetworkManager is purely because of the Add Player message - if you want to, you can use
      NetworkServer.RegisterHandler, but I found my way easier).
      Code (CSharp):
      1. public override void OnServerAddPlayer(NetworkConnection conn,
      2.     short playerControllerId)
      3. {
      4.     if(playerControllerId == 0)
      5.     {
      6.         // For default type use default implementation
      7.         // (spawnes prefab configured in inspector)
      8.         base.OnServerAddPlayer(conn, playerControllerId);
      9.     }
      10.     else if(playerControllerId == 1) // (Used 1 as id of my prefab type)
      11.     {
      12.         NetworkServer.AddPlayerForConnection(conn,
      13.             Instantiate(MyOtherPrefab), playerControllerId);
      14.     }
      15. }
      MyOtherPrefab is the prefab I want to spawn. This method spawnes the prefab on client request.
    3. Clients request spawning with ClientScene.AddPlayer() method. This method requires an instance of NetworkConnection. I'm really not sure where to take it "correctly", so I use default local player instance.
      Code (CSharp):
      1. ClientScene.AddPlayer(defaultLocalPlayer.connectionToClient, 1);
    4. However this won't work for client who is also a host. But for this special case, you can call NetworkServer.AddPlayerForConnection or NetworkManager.OnServerAddPlayer directly;
      Code (CSharp):
      1. if(defaultLocalPlayer.isServer)
      2. {
      3.     myNetworkManagerInstance.OnServerAddPlayer(
      4.        defaultLocalPlayer.connectionToClient, 1);
      5. }
      6. else
      7. {
      8.     ClientScene.AddPlayer(defaultLocalPlayer.connectionToClient, 1);
      9. }

    I hope my guide is helpful to someone...
     
  10. seanr

    seanr

    Unity Technologies

    Joined:
    Sep 22, 2014
    Posts:
    669
    5.2 adds support for client authority of non-player objects:

    https://unity3d.com/unity/beta/unity5.2.0b1

    Networking: Added support for client-side authority for non-player objects.
    • The new function NetworkServer.SpawnWithClientAuthority(GameObject obj, NetworkConnection conn) allows authority to be assigned to a client by its connection when an object is created. This would typically be used in a command handler for a client asking to spawn an object, then the client's connection would be passed in. For example:
    Code (CSharp):
    1. [Command]
    2. void CmdSpawn()
    3. {
    4.     var go = (GameObject)Instantiate(otherPrefab, transform.position + new Vector3(0,1,0), Quaternion.identity);
    5.     NetworkServer.SpawnWithClientAuthority(go, base.connectionToClient);
    6. }
    • For setting the authority on objects after they are created, there are the new functions AssignClientAuthority(NetworkConnection conn) and RemoveClientAuthority(NetworkConnection conn) on the NetworkIdentity class. Note that only one client can be the authority for an object at a time. On the client that has authority, the function OnStartAuthority() is called, and the property hasAuthority will be true.

    • The set of objects that is owned by a client is available in the new property NetworkConnection.clientOwnedObjects which is a set of NetworkInstanceIds. This set can be used on the server when a message is received to ensure that the client that sent the message actually owns the object.
      When a client disconnects, the function DestroyPlayersForConnection now destroys all the objects owned by that connection, not just the player object. Objects which have their authority set to a client must have LocalPlayerAuthority set in their NetworkIdentity.
    • Networking: Added support for network [Command] calls from non-player objects with authority on a client. Since in 5.2 clients can have authority over non-player objects using NetworkServer.SpawnWithClientAuthority() or NetworkIdentity.AssignClientAuthority(), network Commands were extended from being allowed from just the player object to any object that is controlled by a client
     
  11. vanshika1012

    vanshika1012

    Joined:
    Sep 18, 2014
    Posts:
    48
    I just want my client to spawn a object but it is not spawning on Server. I have Unity pro and I am spawning it with NetworkServer.SpawnWithClientAuthority(), but no success. @seanr
     
  12. Morgenstern_1

    Morgenstern_1

    Joined:
    Jul 1, 2013
    Posts:
    34
    Clients cannot spawn objects, only the server can spawn networked objects.
     
  13. ElnuDev

    ElnuDev

    Joined:
    Sep 24, 2017
    Posts:
    298
    Then how would one spawn an object from a client trigger?
     
  14. asperatology

    asperatology

    Joined:
    Mar 10, 2015
    Posts:
    981
    1. On the client, trigger an event.
    2. The event indicates the client must send a message with instructions to the server.
    3. Client sends the message to the server.
    4. Server receives the message.
    5. Server begins processing the message.
    6. Server sees that the message indicated the client wants a new object to be spawned.
    7. Server sends to the client, as well as all other clients that are listening to this message, a new message with new instructions.
    8. Each listening client receives the server's message.
    9. Each listening client processes the server's message.
    10. Each listening client sees the server wanted to spawn a new object for a particular client.
    11. Each listening client instantiates a new object.
    12. Each listening client assigns the ownership of the new instantiated object to that particular client.
    13. Each listening client now understands whom the new instantiated object belongs to.
    14. Each listening client handles the newly instantiated object accordingly.
    TLDR; Client A sends a message to Server, telling the Server to send back a message to all clients A through Z that a new object is about to spawn, and that object belongs to Client A.
     
  15. GibTreaty

    GibTreaty

    Joined:
    Aug 25, 2010
    Posts:
    792
    Only the server can assign authority so really, the client just needs to send a request to the server to spawn the thing. Then the server can spawn the thing in question and use that client's NetworkConnection as the one to assign authority to.
     
  16. Di_o

    Di_o

    Joined:
    May 10, 2016
    Posts:
    62

    PLEEEEASE GIVE US A CODE EXAMPLE
     
  17. Joe-Censored

    Joe-Censored

    Joined:
    Mar 26, 2013
    Posts:
    11,847
    Unet was deprecated a year ago, you should really be moving on instead of churning up old threads about stuff that is removed from the current scripting reference. But since no one seems to listen, put the below on the Player GameObject.

    Code (csharp):
    1. public GameObject SomeNetworkObjectPrefab;
    2.  
    3. [Command]
    4. void CmdSpawnSomeNetworkObjectWithClientAuthority()
    5. {
    6.     GameObject someNetworkObject = Instantiate(SomeNetworkObjectPrefab);
    7.     NetworkServer.SpawnWithClientAuthority(someNetworkObject, connectionToClient);
    8. }
     
  18. Di_o

    Di_o

    Joined:
    May 10, 2016
    Posts:
    62
    I wish I could. I really do...

    The big problem is that there is nothing out there to safely implement all the other stuff, that I'm using in my project. I would like to just go on vacation until everything is finally ready to use. This is not gonna happen, though...
     
    Last edited: May 15, 2019
    ElnuDev likes this.
  19. ElnuDev

    ElnuDev

    Joined:
    Sep 24, 2017
    Posts:
    298
    I feel the same way. I don't want to use UNET because of its deprecation, however, the new multiplayer system isn't ready yet. So I'm probably going to stick with singleplayer and local multiplayer games for now, at least until the new multiplayer system is ready.
     
    GibTreaty likes this.
  20. Joe-Censored

    Joe-Censored

    Joined:
    Mar 26, 2013
    Posts:
    11,847
    Unity now is on their 3rd networking implementation. Both previous times they were released half baked with little follow up. Unity has said or done nothing to indicate that this round will be handled differently, and past behavior says you shouldn't be waiting breathlessly for what Unity releases for networking. Especially when networking isn't a feature that even needs an implementation from Unity directly.

    They've been working a year on a system which looks like something someone knowledgeable in writing networking code could have built in a few weeks. Most of the blog posts on the topic focus on their monetized server hosting rather than the networking API. The networking API appears to me to not be a priority at Unity or it would have been fully featured and released months ago. Just go with a solution not from Unity.
     
    Last edited: May 15, 2019
  21. Di_o

    Di_o

    Joined:
    May 10, 2016
    Posts:
    62

    You should talk to my boss ;)
     
  22. asperatology

    asperatology

    Joined:
    Mar 10, 2015
    Posts:
    981
    Sure:

    https://forum.unity.com/threads/fee...d-with-unity-multiplayer.368900/#post-2390703

    Just going to copy/paste it here for brevity and without having to jump back/forth between hyperlinks:


    Code (CSharp):
    1. using UnityEngine.Networking;
    2.  
    3. public class CustomScript : NetworkBehaviour {
    4.     [ServerCallback]
    5.     public void ServerStuff(GameObject newObject, Vector3 newObjectPosition){
    6.         //Do server-side stuff. Initializing all game stuffs can be used here. Syncing objects can also be used here.
    7.  
    8.         //Let's pretend "newObject" has NetworkTransform attached.
    9.         newObject.transform.position = newObjectPosition;
    10.  
    11.         //Now newObject's NetworkTransform will sync the new position across all connected clients. The values are updated on the server
    12.         //side, all clients will have their old positions marked as Dirty() and will update to the server's values.
    13.     }
    14.  
    15.     [ClientCallback]
    16.     public void ClientStuff(){
    17.         //Do client-side stuff.
    18.  
    19.         //Client may have this registered prefab from the Network Manager, but usually it's better to have it available in the Hierarchy before continuing. Usually, it's assigned directly through the Inspector, but let's go with this.
    20.         GameObject prefabObject = GameObject.FindGameObjectWithTag("SamplePrefab");
    21.         if (prefabObject != null){
    22.             //Always check for null. In UNET, there may be times where the object is not spawned through NetworkServer, thus the object will be missing.
    23.             CmdDoAction(prefabObject);
    24.         }
    25.     }
    26.  
    27.     [Command]
    28.     public void CmdDoAction(GameObject objectToUse){
    29.         //This is where you would do stuffs that the client wants the server to do.
    30.         GameObject obj = Instantiate<GameObject>(objectToUse);
    31.         NetworkServer.SpawnWithClientAuthority(obj, this.connectionToClient);
    32.  
    33.         //Or just have the server do something for the client.
    34.         obj = Instantiate<GameObject>(objectToUse);
    35.         NetworkServer.Spawn(obj);
    36.         ServerStuff(obj, new Vector3(0f, 10f, 0f));
    37.  
    38.         //Once the server has done whatever it needs to do, you can choose if you want to have all clients do other actions.
    39.         RpcDoAction();
    40.     }
    41.  
    42.     [ClientRpc]
    43.     public void RpcDoAction(){
    44.         //Do broadcasting stuffs. Stuffs where all clients (local clients = LAN host, and remote clients = LAN clients) will do.
    45.  
    46.         //Because there exists a game object with client authority (meaning the game object's NetworkIdentity has "Local Player Authority" property
    47.         //enabled), it means it's better to check for NetworkBehaviour.hasAuthority, rather than NetworkBehaviour.isLocalPlayer.
    48.         if (!this.hasAuthority){
    49.             //Clients with no authority do stuffs here.
    50.  
    51.             //Or if you want, you can do something that all other clients without authority of this game object can do.
    52.             Ping(new Vector3(0f, 10f, 0f), Color.red);
    53.         }
    54.         else {
    55.             //Do something in which the client itself has control over the game object of local authority.
    56.  
    57.             //Then do whatever you need to do that tells the player the unit has spawned, and all other enemies have taken notice of it.
    58.             Ping(new Vector3(0f, 10f, 0f), Color.green);
    59.         }
    60.         return;
    61.     }
    62.  
    63.     public void Ping(Vector3 position, Color color){
    64.         //Pretend this is a function which pings a colored ! symbol on a minimap.
    65.     }
    66.  
    67.     public void Update(){
    68.         //Because this is a custom NetworkBehaviour script, this is attached to a game object that the client may use.
    69.         if (Input.GetMouseButtonUp(0)){
    70.             //When something occurred...
    71.             ClientStuff();
    72.         }
    73.     }
    74. }
     
    Di_o likes this.
  23. URGr8

    URGr8

    Joined:
    Sep 10, 2012
    Posts:
    24
    I still use UNET, and what I know is that the same commands can be used in Mirror, but have not upgraded yet, still on Unity 5.6

    Here is an example of how I spawn game objects and how this works on clients and servers. with commands and RPCs

    The csharp file is on my player object that is spawned from the server, but remember that it is running code on the server and the client at the same time.


    Code (CSharp):
    1.  
    2.       GameObject myBandStageGO; // this is the game object that will be on the server, the local one will be null unless you get a reference to it. (you can find it or get it from an Rpc, see below)
    3.       public bool stageActive = false; //server and client bool (each has their own variable, they are not connected in any way. i.e. they don't know about each other, if you want that then use a SyncVar
    4.  
    5. //call this from your code, it will be called locally
    6.       public void LoadMusicStage()
    7.       {
    8.           //Load the stage  - tell the server to load it
    9.           if (!stageActive)
    10.           {
    11.               stageActive = true; // local client variable
    12.               CmdLoadMyBandStage(); // tell the server to load the stage
    13.           }
    14.           else
    15.           {
    16.               CmdUnLoadMyBandStage(); // tell the server to unload the stage (i.e. destroy it)
    17.               stageActive = false;
    18.           }
    19.       }
    20.  
    21.       //this is used to have a Local Player do something on the server. (Tell the server to do something)
    22.       [Command]//Send from the Local Client (Called on the Local Client) executed (received) on the Server.
    23.       void CmdLoadMyBandStage()
    24.       {
    25.           //This is called by the local player, but all this code here is executed on the server, so the local player will not have reference to this.
    26.  
    27.           stageActive = true; // code on the server side, i.e. server side bool
    28.  
    29.          // find the NetworkManger and get the prefab this has been added to the list - the same list your player prefab is on, (You can also register one and load it, but won't do that here.)
    30.           GameObject myBandStagePrefab = GameObject.Find("NetworkManager").GetComponent<NetworkManager>().spawnPrefabs[3]; //BandStage
    31.  
    32.          //We are going to instantiate the GameObject on the server here right now
    33.           myBandStageGO = (GameObject)Instantiate(myBandStagePrefab, new Vector3(0, 0, 0), Quaternion.identity);
    34.        
    35.         // this will spawn it on the network so all clients will get it
    36.         //You can just spawn the object, like a bullet if you want, or you can give it client authority like below.
    37.   //    NetworkServer.Spawn(myBandStageGO );
    38.           NetworkServer.SpawnWithClientAuthority(myBandStageGO, connectionToClient); // this will spawn an object with the local player authority on the server and clients that are ready. (If the client isn't ready, when a new person joins, it will spawn automatically
    39.  
    40.           //You can do stuff on this game object, remember this is on the server, not the client.
    41.           myBandStageGO.GetComponent<BandStageManager>().SetPlayerManageNetworkComponent(gameObject);
    42.  
    43.          //that is all, the object will appear on your client, but you will need to find it or send the GameObject to your clients thru an RPC command if you need to gain access to it locally
    44.       }
    45.  
    46.      //To destroy the object call this
    47.       [Command]//Send from the Local Client (Called on the Local Client) executed (received) on the Server.
    48.       void CmdUnLoadMyBandStage()
    49.       {
    50.           stageActive = false; // server side bool
    51.           NetworkServer.Destroy(myBandStageGO);  //destroys object on server and clients.
    52.  
    53.           //if you need to just remove it from the clients do this
    54.           //     NetworkServer.UnSpawn(myBandStageGO); //removes an object on the server, but doesn't destroy it.
    55.       }
    56.  
    You can use Command and RPC commands to call functions on the spawned game object, send in the GameObject from the server to the RPC, here is an example.

    Code (CSharp):
    1.  
    2.  
    3. // call this on your local client, it will tell the server to run a command (an rpc) that will tell all clients to do something
    4.      public void PlayBandStageSFX(int sfxNum, int sfxType, bool isOn)
    5.       {
    6.           //run this on the server, tell all the clients to do this action.
    7.           if (stageActive) // local bool
    8.           {
    9.            //this will send a command so it plays the effect on all stages.
    10.               CmdPlayBandStageSFX(sfxNum, sfxType, isOn);
    11.           }
    12.          
    13.       }
    14.      //remember all code in Commands is run on the server, the GameObject we are going to send to the clients was created on the server - the code above - but it will have the server and local reference
    15.       [Command]//Send from the Local Client (Called on the Local Client) executed (received) on the Server.
    16.       void CmdPlayBandStageSFX(int val, int sfxType, bool isOn)
    17.       {
    18.           //run this on the server, tell all the clients to do this action.
    19.           if (stageActive) // server side bool
    20.           {
    21.               //send a rpc to the clients to do this. Send in the GameObject that is the one we created above, only the server knows about it, the GameObject we send in, on the client, will have a reference to it, part of the Unet system
    22.               RpcPlayBandStageSFX(val, sfxType, isOn, myBandStageGO);
    23.           }
    24.       }
    25.  
    26.     //This is Run on the server, but the code in there is run locally on the clients
    27.     //Send from the Server (Called on the Server) executed (received) on the Clients - Can also use the TargetRPC goes to a specific Net Connection (i.e. one player) this ClientRpc goes to all players
    28.       [ClientRpc]
    29.       void RpcPlayBandStageSFX(int val, int sfxType, bool isOn, GameObject stage)
    30.       {
    31.         //the GameObject here is the server/local one so the reference is ok.
    32.         //The BandStageManager is my code on the prefab
    33.           if (sfxType == 1)
    34.             stage.GetComponent<BandStageManager>().TriggerSFX(val);
    35.           if (sfxType == 2)
    36.               stage.GetComponent<BandStageManager>().PlaySFX(val, isOn);
    37.       }
    38.  
    That is all you need to do stuff with game objects, if you have authority over them. Make sure you have the Network Identity and Network Transform on your prefabs.
    The Csharp code here is <YourClass> : NetworkBehaviour