MLAPI Character Selection

Hey, I have 2 classes for characters for my game, when people select a class I wish for that character to spawn in and be controllable by the local player and not the other players that are playing.

But when I do this and try and get the clientId it just doesn’t want to work and I am confused to as why.

I’ve looked at the documentation and it doesn’t give any answers to my issue

Here is my code:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using MLAPI;

public class ChooseCharacter : NetworkBehaviour
{
    public GameObject scoutPrefab;
    public GameObject assaultPrefab;
    GameObject scout;
    GameObject assault;
    public void Scout()
    {
        scout = Instantiate(scoutPrefab, Vector3.zero, Quaternion.identity);
        scout.GetComponent<NetworkObject>().Spawn();
        scout.GetComponent<NetworkObject>().ChangeOwnership(NetworkManager.Singleton.LocalClientId);
        Cursor.lockState = CursorLockMode.Locked;
    }

    public void Assault()
    {
        assault = Instantiate(assaultPrefab, Vector3.zero, Quaternion.identity);
        assault.GetComponent<NetworkObject>().Spawn();
        assault.GetComponent<NetworkObject>().ChangeOwnership(NetworkManager.Singleton.LocalClientId);
        Cursor.lockState = CursorLockMode.Locked;
    }
}

I hope I can get help with this question as it is giving me a headache working out the issue

Hey! Just stumbled upon this thread while searching for the solution, then after banging my head a bit I stumbled upon a solution too! It’s actually in the MLAPI documentation but it’s kind of hidden, you can find it here: https://mp-docs.dl.it.unity3d.com/docs/getting-started/connection-approval

Here’s a quick explanation too if the above link stops working in the future. You probably have a menu/scene/whatever where you select if you want to be a Host/Client/Server. You have to add a ConnectionApprovalCallback function right before calling StartHost, this callback will be called when a Client connects and can be used to approve or deny that Client. But it’s also used for choosing which prefab to select as the player for that Client. Here’s some half-done code:

using MLAPI;
using MLAPI.Spawning;

...

private string playerClass;

private void ScoutPress() {
    playerClass = "Scout";
}

private void AssaultPress() {
    playerClass = "Assault";
}

private void HostPress() {
    NetworkManager.Singleton.ConnectionApprovalCallback += ApprovalCheck;
    ulong prefabHash = NetworkSpawnManager.GetPrefabHashFromGenerator(playerClass);
    NetworkManager.Singleton.StartHost(Vector3.zero, Quaternion.identity, true, prefabHash, null);
}

private void ClientPress() {
        NetworkManager.Singleton.NetworkConfig.ConnectionData = 
            System.Text.Encoding.ASCII.GetBytes(playerClass);
        NetworkManager.Singleton.StartClient();
}

private void ApprovalCheck(byte[] connectionData, ulong clientId,
                           MLAPI.NetworkManager.ConnectionApprovedDelegate callback) {
    playerClass = System.Text.Encoding.ASCII.GetString(connectionData);
    ulong prefabHash = NetworkSpawnManager.GetPrefabHashFromGenerator(playerClass);
    callback(true, prefabHash, true, Vector3.zero, Quaternion.identity);
}

To make this work you need to have all your player prefabs in the NetworkPrefabs list of you NetworkManager object/component. The playerClass string should then match the “Prefab Hash Generator” string on the NetworkObject component on each player prefab.

Keep in mind that the callback is NOT used for the Host. That’s why we have to call StartHost() with special parameters to set up the correct class. Then in the ClientPress we send some ConnectionData which is read in the callback (which only runs on the Server) so the correct class is spawned.