UNET: Spawning different player prefabs (SOLVED)

This is getting ridiculous, I’ve been searching nearly all day for something that shouldn’t be this hard.

I just want to have different player meshes join the same game, you know like most games…

All prefabs work individually, but no matter what I do, the prefab that the host choses is the one that all the clients get when they join.

Both prefabs have been added to the registered network prefabs in the networkmanager. I have a class selector screen so the player prefab in the networkmanager gets set according to those prefabs like so.

if(ChosenClass==CharacterClasses.Ronin){
NetworkManager.singleton.playerPrefab =NetworkManager.singleton.spawnPrefabs[0];
}

I’ve tried OnServerAddPlayer

publicoverridevoidOnServerAddPlayer(NetworkConnection conn,short playerControllerId){
var player =(GameObject)Instantiate(playerPrefab,ActManager.singleton.SpawnObject.transform.position,Quaternion.identity);
NetworkServer.AddPlayerForConnection(conn, player, playerControllerId);
}

This simply doesn’t work.

Is this normally the way to do it, or is there more that should happen or something?

Thx

1 Like

Are your prefabs inside your “Resources” folder? if not it wont work…

Well I have not tried that, but to be fair, it’s not like that’s documented somewhere.
At least not from what could find.
I’ll get back to you.

True :slight_smile: hope that does it :wink:

This is completely incorrect based on the way he’s writing his code.

Now to address the original OP. You’ve been searching all day…but have you been searching your own work? What I mean by this, is look at WHAT you’re trying to accomplish. Look at HOW you’re trying to accomplish it. Then go through your code step by step to make sure every piece is working the way it’s intended. First of all, why are you bothering to change the player prefab? Why not just put your IF statement inside of your override for the OnServerAddPlayer() method?

public override void OnServerAddPlayer(NetworkConnection conn, short playerControllerId)
{
     if(/*PLAYER CHOOSES CLASS A*/)
          //SPAWN THAT PREFAB
   
     if(/*PLAYER CHOOSES CLASS B*/)
          //SPAWN THAT PREFAB
}

Next. I don’t know if you messed it up just here, or in your own code too (although I would assume you would have seen an error thrown, but your syntax is screwed up…

…should be…

public override void OnServerAddPlayer(NetworkConnection conn,short playerControllerId)

Finally, you’re not being clear on exactly WHAT results (if any) you’re getting. Are you saying that you get no errors, but the GameObject also isn’t spawned at all? Make sure to check you hierarchy to see if the prefab was spawned at all.

1 Like

I tried it that way too DRRosen3, calling the prefabs in OnServerAddPlayer, the syntax is also correctly typed, it’s just the forum code that messed up.

As to what happens, it’s in bold on top.
The host chooses model A and creates a game, all clients that connect also get model A regardless of what model they chose. The models do get changed when I look at the networkmanager’s playerprefab variable in the inspector. They just won’t instantiate the correct one when the scene loads. Everything works, even the gear that they have in their inventory.

It’s almost as if the playerprefab variable is shared amongst the network and can’t be changed.
Putting it in resources didn’t work either.

2 Likes

Also //SPAWN THAT PREFAB is kind of the code I need.
I’ve just been following this manual http://docs.unity3d.com/Manual/UNetPlayers.html

You said you tried it… “Putting it in resources…” What exactly did you do and did you change you code at all after putting it in resources? I have multiple player objects as well and that’s exactly how I spawn mine…via Resource Loading.

I still use the spawnprefabs[0], cause those are the prefabs in the networkmanager.
I just dragged the reference to resources, cause maybe they just need to be in the resources folder for what ever reason.

But I have not tried resources.load specifically, which I’ll do now.

First, make sure your prefabs are in a folder named Resources. They can be in a subfolder, as long as the main folder is named Resources and is in the Assets folder.

public override void OnServerAddPlayer(NetworkConnection conn, short playerControllerId)
{
     GameObject player;

     if(chosenClass == CharacterClasses.Ronin)
          player = Instantiate(Resources.Load("Ronin Prefab"), transform.position, Quaternion.identity) as GameObject;

     if(chosenClass == CharacterClasses.Samurai)
          player = Instantiate(Resources.Load("Samurai Prefab"), transform.position, Quaternion.identity) as GameObject;

     NetworkServer.AddPlayerForConnection(conn, player, playerControllerId);
}

Nop simply doesn’t work, I just made an new scene with 2 different dummies to prevent other scrips from messing with it.
The host still choses the model.

public override void OnServerAddPlayer(NetworkConnection conn, short playerControllerId) {
        //base.OnServerAddPlayer(conn, playerControllerId);
        if (chosenCharacter) {
            GameObject player = Instantiate(Resources.Load("Characters/A", typeof(GameObject))) as GameObject;
            NetworkServer.AddPlayerForConnection(conn, player, playerControllerId);
        }
        else {
            GameObject player = Instantiate(Resources.Load("Characters/B", typeof(GameObject))) as GameObject;
            NetworkServer.AddPlayerForConnection(conn, player, playerControllerId);
        }
    }

I have a feeling that the clientscene needs to do something too.

That code does work for you without any other scripting tho?

Yes my code works. Keep in mind OnServerAddPlayer() is called on the server. If you’re choosing your “chosenCharacter” on the client, the server needs some way to know which character the client has chosen.

Well that’s most likely the problem, cause I am doing it client side and I didn’t know OnServerAddPlayer was server side.
So how would I go about this?
Is it possible to have an offline scene send which character you selected, or does the class selection need to be online as well?

Offline or online doesn’t matter. The problem is changing the playerPrefab on the client won’t change it on the server. The NetworkManager is the same for both the server and the client when you build the game. So let’s say Ninja is in the playerPrefab slot when you build it. If you log onto the game as a client, and change the playerPrefab to Samurai by pressing a button, it only changes the playerPrefab for the client. The server still thinks the playerPrefab is the Ninja. That’s why you have to use something like Resources.Load. However, the only way to make this work is to let the server know which prefab the player wants to load from the Resources folder. You’re going to have to look into the second OnServerAddPlayer() method which takes 3 arguments. This is where my help is going to fall short, as I haven’t played around with this much yet. However, these two code snippets are taken from the base NetworkManager.cs.

internal void OnServerAddPlayerMessageInternal(NetworkMessage netMsg)
{
     if (LogFilter.logDebug) { Debug.Log("NetworkManager:OnServerAddPlayerMessageInternal"); }

            netMsg.ReadMessage(s_AddPlayerMessage);

            if (s_AddPlayerMessage.msgSize != 0)
            {
                var reader = new NetworkReader(s_AddPlayerMessage.msgData);
                OnServerAddPlayer(netMsg.conn, s_AddPlayerMessage.playerControllerId, reader);
            }
            else
            {
                OnServerAddPlayer(netMsg.conn, s_AddPlayerMessage.playerControllerId);
            }
        }
        public virtual void OnServerAddPlayer(NetworkConnection conn, short playerControllerId, NetworkReader extraMessageReader)
        {
            OnServerAddPlayerInternal(conn, playerControllerId);
        }

The entire script can be viewed HERE.

1 Like

Ye I was already looking in to the networkmessage, but surprise surprise the documentation is severely lacking :stuck_out_tongue:

On a side not tho, wouldn’t that mean my prefab should still be correct on the client side, and wrong on the server side, cause right now it’s wrong on both sides.

Anyway, thanks alot for your help mate, you helped me in the right direction :slight_smile:

2 Likes

Really? how are you able to instantiate prefabs outside the Resource folder? I want to know this …
And why is using Resource folder totally wrong? :eyes:

To instantiate prefabs outside of Resource folders, just get a game object with the target prefab set in that game object’s Inspector properties, then in the script component attached to the target prefab, call on MonoBehaviour.Instantiate(yourPrefab);

I’m not sure about the Resource folder. All I know is Resource folder is the same as Assets folder, except the Resource folder have a helper class that supports doing stuffs with the resources.

To be a but more clear on what @asperatology is saying. You can Instantiate a prefab by declaring it as a variable in a script. By making the variable public…once you attach the script to a GameObject, you can then drag your prefab into the variable’s slot in the inspector.

As for why using Resource was wrong… It wasn’t wrong in of itself. You told him it wouldn’t work unless he put the prefab in a Resource folder. THAT was wrong. The only time a prefab needs to be in a Resource folder, is if you’re using Resources.Load. Otherwise, you’ll have to use the method that @asperatology and I described above.

 GameObject player = Instantiate(Resources.Load("Characters/B",

Ehh wrong , that will not work unless you use normal instantiate … Resources.Load is target path to the Resource folder else it will return null. Using Resources.Load is a better practice if you experiencing issue with prefabs, because you have better control. Hence my tip in the first place…

Read the documents …

Oh, OP is referring to loading a prefab from Resources folder? I guess I misread the entire thread.