SpawnManagerBase won't work if other players load before Master Player

Idodi

New member
Hi,

SpawnManagerBase depends on the Master player loading the "arena" scene before the other players join the room since it relies on OnPlayerEnteredRoom.

In case there's a lobby scene and the Master player waits for all players to connect, and then loads the proper scene, the players may not spawn if the master player did not load the scene first.

This is a fairly popular use case (more popular than waiting in the action scene for other players).

I'll probably resolve this by inheriting from SpawnManagerBase and creating my own SpawnManager, but this should probably be part of the base class..
 
Last edited:
I'll probably resolve this by inheriting from SpawnManagerBase and creating my own SpawnManager, but this should probably be part of the base class..
That is the correct route to go. Having a lobby is a bit outside the scope of the add-on as it's mostly focused on character synchronization.
 
@Idodi

I also encountered the same problem. I would be grateful if you could help me out.

I solved it by editing the SpawnManagerBase script.
In the SpawnPlayer I have commented the following line at the start of the method
C#:
public void SpawnPlayer(Player newPlayer)
        {
            // Only the master client can spawn new players.
            /*if (!PhotonNetwork.IsMasterClient) {
                return;
            }*/

            var determineSpawnLocation = true;
            var spawnPosition = Vector3.zero;
            var spawnRotation = Quaternion.identity;

            InactivePlayer inactivePlayer;
            if (m_InactivePlayers != null && m_InactivePlayers.TryGetValue(newPlayer, out inactivePlayer)) {
                // The player has rejoined the game. The character does not need to go through the full spawn procedure.
                Scheduler.Cancel(inactivePlayer.RemoveEvent);
                m_InactivePlayers.Remove(newPlayer);

                // The spawn location is determined by the last disconnected location.
                spawnPosition = inactivePlayer.Position;
                spawnRotation = inactivePlayer.Rotation;
                determineSpawnLocation = false;
            }

I hope it will be useful to someone.
 
I solved it by editing the SpawnManagerBase script.
In the SpawnPlayer I have commented the following line at the start of the method
C#:
public void SpawnPlayer(Player newPlayer)
        {
            // Only the master client can spawn new players.
            /*if (!PhotonNetwork.IsMasterClient) {
                return;
            }*/

            var determineSpawnLocation = true;
            var spawnPosition = Vector3.zero;
            var spawnRotation = Quaternion.identity;

            InactivePlayer inactivePlayer;
            if (m_InactivePlayers != null && m_InactivePlayers.TryGetValue(newPlayer, out inactivePlayer)) {
                // The player has rejoined the game. The character does not need to go through the full spawn procedure.
                Scheduler.Cancel(inactivePlayer.RemoveEvent);
                m_InactivePlayers.Remove(newPlayer);

                // The spawn location is determined by the last disconnected location.
                spawnPosition = inactivePlayer.Position;
                spawnRotation = inactivePlayer.Rotation;
                determineSpawnLocation = false;
            }

I hope it will be useful to someone.
Thank you so much! My rooms are working perfectly now. I was scratching my head for days with this, I cant believe i overlooked that. Thanks again!
 
I just realized there were a lot of unanswered questions that I missed in this thread. Sorry guys I hadn't noticed!

I went a different route in my solution. As I mentioned in my op I inherited from SpawnManagerBase and on Start (which is basically when the scene was loaded) I sent out a buffered RPC with the local player as payload. In the RPC method the code spawns the player by checking if it's the master player first.

Here's the snippet:

C#:
protected override void Start()
{
    base.Start();
    photonView.RPC(nameof(LoadedBattleSceneRPC), RpcTarget.OthersBuffered, PhotonNetwork.LocalPlayer);
}

[PunRPC]
private void LoadedBattleSceneRPC(Player loadedPlayer)
{
    if (PhotonNetwork.IsMasterClient)
    {
        SpawnPlayer(loadedPlayer);
    }
}
 
I sent out a buffered RPC with the local player as payload. In the RPC method the code spawns the player by checking if it's the master player first.
I understand zero of this mate (Not a coder - visual scripter - can modify code to a small degree)

How is your solution different/better/more suited to something than Nikot93's solution above?

Is there something in particular you yourself specifically need to do differently to him?

I just foresaw this issue if a Non-Master Client loads in before the Master and found this thread wondering what the solution might be....
 
My thinking is I can't see a problem with a Non-Master player loading in and spawning before the Master Client - providing that doesn't break any of my game's logic or flow......
 
My thinking is I can't see a problem with a Non-Master player loading in and spawning before the Master Client - providing that doesn't break any of my game's logic or flow......
The problem is that the master player only spawn players when the SpawnManagerBase script receives an OnPlayerEnteredRoom event. This can lead to a situation where the 2nd (none-master) player loaded the scene first and executed its OnPlayerEnteredRoom event. The master player loads the scene after that and never receives the OnPlayerEnteredRoom event fired by the 2nd player, and thus will never spawn the 2nd player.

The code snippet I sent in my previous message takes care of this situation by sending a buffered RPC call to all other players announcing that the player has finished loading the scene. It's called a buffered RPC call because it stores this network call in a buffer and all players that load the scene will run it. Now it doesn't matter if the Master player loads the scene after the 2nd player because the call to spawn the player is buffered and the 2nd player will therefore be spawned.

I hope that makes sense. It's a little hard to get into this with no coding background, but if you do a lot of visual scripting then this should make some sense.

You can read more about RPCs and buffering in the Photon PUN documentation - https://doc.photonengine.com/en-us/pun/v2/gameplay/rpcsandraiseevent
 
Thanks a lot @Idodi .

Mainly I'd like to know could I paste your snippet as is or is it customised for your purpose only?

Secondly, is the other solution of allowing any client who loads in before the master to spawn themself a problem or is it ok?
 
C#:
public class BufferedPlayerSpawnManager : SpawnManagerBase
{
    [Tooltip(
        "A reference to the character that PUN should spawn. This character must be setup using the PUN Multiplayer Manager.")]
    [SerializeField]
    protected GameObject m_Character;

    public GameObject Character
    {
        get { return m_Character; }
        set { m_Character = value; }
    }

    /// <summary>
    /// Abstract method that allows for a character to be spawned based on the game logic.
    /// </summary>
    /// <param name="newPlayer">The player that entered the room.</param>
    /// <returns>The character prefab that should spawn.</returns>
    protected override GameObject GetCharacterPrefab(Player newPlayer)
    {
        // Return the same character for all instances.
        return m_Character;
    }

    protected override void Start()
    {
        base.Start();
        photonView.RPC(nameof(LoadedBattleSceneRPC), RpcTarget.OthersBuffered, PhotonNetwork.LocalPlayer);
    }

    [PunRPC]
    private void LoadedBattleSceneRPC(Player loadedPlayer)
    {
        if (PhotonNetwork.IsMasterClient)
        {
            SpawnPlayer(loadedPlayer);
        }
    }
}

This is the class that handles spawning players in my game. It inherits from SpawnManagerBase (so it replaces it in your scene too). There's no reason why you shouldn't be able to use it as is there is nothing customized here for my needs.

Regarding the other solution I haven't tried it and I'm not sure what its side effects are.
 
Top