- Home /
Unet NetworkServer.Spawn() not working
Hello, I'm try to spawn objects over the network and to make it simple I told it to spawn a cube. The cube has the two networking components Network Identity and Network Transform. I have this code to make the cube.
using UnityEngine;
using System.Collections;
using UnityEngine.Networking;
public class Network_BuilderGUI : NetworkBehaviour
{
public GameObject TestPart;
// Use this for initialization
void Start () {
}
// Update is called once per frame
void Update ()
{
if(Input.GetMouseButtonDown(0))
{
print ("Create");
CreatePart();
}
}
//[Command]
void CreatePart()
{
GameObject Te = (GameObject)Instantiate(TestPart,transform.position,transform.rotation);
NetworkServer.Spawn(TestPart);
}
}
Now it seems to be that the cube gets created by the client that started it, but then I get error on the other clients "Failed to spawn server object" am I missing something because seems the manual states to do it this way?
Ok I found that you have to register a object for it to work. Is there a way though to create objects for everyone to see without the use of registering prefabs?
When your in Network$$anonymous$$anager component open up Spawn Info. Then there should be an area called Registered Spawnable Prefabs. Click the + icon and add it in then it should work. I've tried using the code version to add which is ClientScene.RegisteredPrefab() but doesn't seem to work.
Ah that makes sense. But now when i shoot on the client they don't appear on the server. But they do when i shoot on the server. Any idea why this is? Sorry btw for not answering your questions but asking questions ins$$anonymous$$d :p
That's fine. I don't have any idea for the shooting. Sorry. Unet is brand new so I'm still learning it. Hopefully there is a way to create objects over the server like the old networking "Network.Instantiate" Because I have to many objects for registering.
Answer by csisy · Jun 23, 2015 at 08:53 PM
A host is a special thing here. Mainly it's a server but it's a local client as well.
The registering is required for the clients to be able to find the spawnable prefabs.
I'm trying to provide you a simple "shooting" example, step by step
PART 1
Create a new scene and save it
Create a new game object, name it NetworkManager
Add two components to it: NetworkManager and NetworkManagerHUD
Create a new game object called Player. This will be our player to be spawned when connected to the server.
Add a NetworkIdentity component to this object. Check "Local Player Authority".
Add a NetworkTransform component as well. This will handle the transform syncing automatically.
Add a child cube or something to be able to see where the player is.
Create a new (c#) script and call it Player as well. Here is the commented code:
using UnityEngine; using UnityEngine.Networking; public class Player : NetworkBehaviour { public float _moveSpeed = 3.0f; private Vector3 _velocity; public override void OnStartLocalPlayer() { base.OnStartLocalPlayer(); // you can use this function to do things like create camera, audio listeners, etc. // so things which has to be done only for our player } private void Update() { // isLocalPlayer is true for the client who "owns" the player object // we only want input handling for our player if (!base.isLocalPlayer) return; // handle input here... _velocity = Vector3.zero; if (Input.GetKey(KeyCode.W)) ++_velocity.z; if (Input.GetKey(KeyCode.S)) --_velocity.z; if (Input.GetKey(KeyCode.A)) --_velocity.x; if (Input.GetKey(KeyCode.D)) ++_velocity.x; _velocity.Normalize(); } private void FixedUpdate() { // because Local Player Authority is true, the client has to move the player // only the resulting transform will be sent to the server and to the other clients if (!base.isLocalPlayer) return; // if that flag is not true, we should check that the code runs only on server // it could be done by checking base.isServer // transforming and other authoritive stuff here... transform.position += _velocity * Time.deltaTime * _moveSpeed; } }
After adding the newly created Player component to the Player object, create a prefab from this object (drag & drop from the Hiearchy to the Assets tab)
Select the NetworkManager, expand "Spawn Info" section, and assign the previously created prefab to the Player Prefab.
If it was successful (no error messages, etc), delete the Player object from the scene.
Now, if you build the game, and start the standalone, a basic movement is working. One of the game has to be the host, the other is a client (ofc, create the host first)
PART 2
Create a new game object, call it Bullet
Add a NetworkIdentity and a NetworkTransform components to it - note the Local Player Authority is not checked this time!
Add a child sphere to be able to see the bullet
Create a new (c#) script, call it Bullet. Here is the code:
using UnityEngine; using UnityEngine.Networking; public class Bullet : NetworkBehaviour { public float moveSpeed = 10.0f; public Vector3 velocity; private void FixedUpdate() { // we want the bullet to be updated only on the server if (!base.isServer) return; // transform bullet on the server transform.position += velocity * Time.deltaTime * moveSpeed; } }
Add the newly created Bullet script to the Bullet object.
Create a prefab from this object
Select the NetworkManager object and in the Spawn Info section under the Registered Spawnable Prefabs, press the + icon and assign the bullet prefab to the empty space. Now, you can remove the Bullet object from the scene
This registering means that your clients will be able to spawn this object. This is a must-have step.
The client cannot spawn networked object itself, it can just ask the server to spawn a new one. To have shooting, we have to modify our Player class
// Command means when the client call this function, it's "forwarded" to the server // and the code will actually run on server side // NOTE: the function name has to start with "Cmd" [Command] public void Cmd_Shoot() { // create server-side instance GameObject obj = (GameObject)Instantiate(bulletPrefab, transform.position, Quaternion.identity); // setup bullet component Bullet bullet = obj.GetComponent<Bullet>(); bullet.velocity = transform.forward; // destroy after 2 secs Destroy(obj, 2.0f); // spawn on the clients NetworkServer.Spawn(obj); } private void Update() { // ... same as before // when pressing the space button, ask the server to spawn a bullet if (Input.GetKeyDown(KeyCode.Space)) Cmd_Shoot(); }
Select the Player prefab, and assign the Bullet prefab to the corresponding place.
Build and test it. You can now move and shoot bullets. :)
Here is the completed project. The source code looks better than here. :) And Here is a "tutorial" from the Unite 2014.
Awesome, Thank you very much for helping me with this.
So far I got it to create a cube on the clients and host at the position of the players. The only problem I'm running into is that when you join the match the objects don't get created for the new clients. The tutorial video I believe stated that the objects should automatically get created and updated with new clients. But I get errors saying that it won't spawn the object. How would I go at controlling this?
Does the object have NetworkIdentity component? Have you added the NetworkTransform component to it?
Anyway, have you tried the attached sample project?
Edit: Oh, and you can try to build the standalone, run the server/host on it, but the client in the editor. In this case, you can see client-side error messages appear on the console and the hiearchy (the spawned objects) as well.
Yes, Yes, I just tried your program and if there are bullets still current in scene when client joins the client gets the error Failed to spawn server object, UnityEngine.Networking.NetworkIdentity
Sorry, my bad... It seems like I forgot to attach the meta files. :) Now I tried to create a new project, extract the assets, build, and run it twice, and it works for me. I created a host, then in the other window, I join as a client.
Here is the fixed version of the completed project. :)
NOTE: the metafiles are hidden files, take care!
If it's not working then... I don't know. Which version of Unity are you using?
Answer by brunopava · Jun 18, 2015 at 01:42 PM
//[Command]
void CreatePart()
{
GameObject Te = (GameObject)Instantiate(TestPart,transform.position,transform.rotation);
// You had "TestPart" here. You need to put "Te" because its actualy the object you are instantiating
NetworkServer.Spawn(Te);
}
Woops I believe I was trying multiple different lines of code. Will I still have to register the game object to get it to create over server. I have too many prefabs to register them all.
Answer by Guardian2300 · Jun 22, 2015 at 08:52 PM
I can't comment anymore so I have to make a new answer. I try doing the unet tutorials on youtube and doesn't want to create the object of the client the same way I am having issues with the current NetworkServer.Spawn(). This only works on the host but even then I can't tell the clients to tell server to create Object.
I've tried using OnStartServer() where the function CreatePart() is supposed to create the object for the server.
void CreatePart()
{
GameObject Te = (GameObject)Instantiate(TestPart,transform.position,transform.rotation);
ClientScene.RegisterPrefab(Te);
NetworkServer.Spawn(Te);
}
Gives me an error saying on the client side can't spawn object. I've tried [Server] and [Command] Attributes but doesn't work either. I don't understand what I'm missing because either I get errors or the object doesn't get spawned.
I think you don't get the concept of the UNET. You're calling this function when the server is started, so it's a server-side code. Why are you trying to register the prefab in the ClientScene? It has to be done only on client-side.
// The assigned prefab has to have a NetworkIdentity component!
// client side
public class Client : Network$$anonymous$$anager
{
public GameObject testPrefab;
void Start()
{
ClientScene.RegisterPrefab(testPrefab);
}
void OnGUI()
{
if (GUILayout.Button("Connect"))
{
base.StartClient(); // connecting to base.networkAddress base.networkPort
}
}
}
// server side
public class Server : Network$$anonymous$$anager
{
public GameObject testPrefab; // has to be the same prefab
// called when a new client is connected: spawn a test object when a client is connected
public override void OnServerConnect(Networking.NetworkConnection conn)
{
SpawnObject(testPrefab);
}
// or you can spawn it only once, when the server is started
public override void OnStartServer()
{
SpawnObject(testPrefab);
}
private void SpawnObject(GameObject prefab)
{
GameObject obj = GameObject.Instantiate(prefab);
NetworkServer.Spawn(obj);
}
}
So to be clear the host is the client as well? So when I register the prefab it creates the object? For example if I make a shooter to where everyone fires a capsule if I tell the client to fire from there position do I have to have a syncvar of the position and rotation of where its fired as well as telling the server as in your example to spawn the capsule? So the obj doesn't get register, its the main GameObject which would be testprefab. So the client talks to the server using the server side code? Thanks for putting in time to helping. I always had trouble comprehending the networking. Even in the older networking took me awhile to understand RPC's.
Answer by Ibzy · Jun 24, 2015 at 03:16 PM
Is this not a simple "you haven't added the prefab to the spawnable objects list in Network Manager" error?
Its a different case to where I have too many prefabs to add them in the network manager. I have to do it through code.
Answer by Mako04 · Jul 06, 2016 at 02:25 PM
//[Command]
void CreatePart()
{
GameObject Te = (GameObject)Instantiate(TestPart,transform.position,transform.rotation);
// You had "TestPart" here. You need to put "Te" because its actualy the object you are instantiating
NetworkServer.Spawn(Te);
}