Problems with spawned Player Objects

I recently made a change to my game that broke everything.

Before, the whole game would be in one scene, with a simple host and client button. Depending on if the Host pressed the button first, I would change the default player prefab through an approval check to fit the client character and then just run StartClient().

Today I updated it so that you first have to go through a main menu and character selection screen before you enter the game, so I changed the spawn mechanic to an empty gameobject in the gameplay scene that spawns the character as a player prefab using SpawnAsPlayerObject() in OnNetworkSpawn()

For some reason this completely broke my camera and movement script and I can’t access the Singleton that’s in the scene for some reason.

For example this code doesn’t instantiate the cameras anymore, neither locally nor on the network. I checked and the Client does have ownership:

public class AssignCamera : NetworkBehaviour
{
    [SerializeField] GameObject _camerasPrefab;
    public GameObject cameras;
    public override void OnNetworkSpawn()
    {
        if (!IsOwner) return;
        cameras = Instantiate(_camerasPrefab, Vector3.zero, Quaternion.identity);

        cameras.GetComponentInChildren<CinemachineVirtualCamera>().Follow = transform;
        cameras.GetComponentInChildren<CinemachineVirtualCamera>().LookAt = transform;
        cameras.transform.GetChild(2).GetComponent<CinemachineVirtualCamera>().Follow = transform;
        cameras.transform.GetChild(2).GetComponent<CinemachineVirtualCamera>().LookAt = transform;
      
        SpawnCamerasServerRpc();
    }


    [ServerRpc]
    private void SpawnCamerasServerRpc()
    {
        cameras.GetComponent<NetworkObject>().SpawnWithOwnership(OwnerClientId);
    }
}

My shoddy programming also requires the cameras to be accessible by other scripts in the player through a public variable.

Some help would be appreciated XOXO

For added context, here’s my spawn script:

public class CharacterSpawner : NetworkBehaviour
{
    [SerializeField] GameObject _overlordPrefab, _minionPrefab, _camerasPrefab;

    [SerializeField] Transform _overlordSpawn;
    [SerializeField] Transform[] _minionSpawns;

    public override void OnNetworkSpawn()
    {
        if (!IsServer) return;

        for (int i = 0; i < ServerManager.Instance.ConnectedIds.Count; i++)
        {
            if (i == 0)
            {
                GameObject overlord = Instantiate(_overlordPrefab, _overlordSpawn.position, _overlordSpawn.rotation);
                overlord.GetComponent<NetworkObject>().SpawnAsPlayerObject(ServerManager.Instance.ConnectedIds[i]);
            }
            else
            {
                GameObject minion = Instantiate(_minionPrefab, _minionSpawns[i].position, _minionSpawns[i].rotation);
                minion.GetComponent<NetworkObject>().SpawnAsPlayerObject(ServerManager.Instance.ConnectedIds[i]);
            }
        }
    }
}

I’m confused. I moved the function in CharacterSpawner to a button and now suddenly everything works…

Does anyone have a clue as to why spawning players breaks when done in OnNetworkSpawn but doesn’t when executed manually through a button?

EDIT: I’ve resorted to turning the function into a Coroutine and adding a .5 second delay. I’ll mark the thread as resolved.