Photon Unity Joining a room with game in progress

I would like to join a room via a lobby scene and have a correct unique player index before transitioning into the next scene (which may or may not be in progress) such that objects may be instantiated in that scene correctly.

Is Photon capable of this? I've tried multiple methods such as Photon's included player indexing utility and trying to set player properties in the lobby before moving on, but all have run into timing problems.

Each client that connects to a Photon room gets an ActorNumber. This is instant, when joining the room, so that number is very reliable and won't repeat.
On top of this, PUN has a player indexing component which figures out a player number between 1 and MaxPlayers. Example: You have 4 players in a room already and the player with ActorNumber 1 leaves. The remaining players keep their ActorNumber each and their player index, too. A new client may join and gets a new, higher ActorNumber from the server, e.g. 5. The player index should be 1 in this case, as that number became available when the ActorNumber 1 left.

If this is not working for you, let us know how it's wrong. We can have a look.
In PUN 2, we cleaned this up some more and the component you should have in the scene for this is: PlayerNumbering. Have a look at it's doc in-code or in the .chm file.

As for lobby: Only when you are in a room, you can communicate with everyone else in that room. If you enter a room and others are in another scene, you will run into issues where a client gets updates from networked objects, which the local client didn't load yet. This causes issues, so it might be easier to load the correct scene but show a UI on top of that (or a different camera or whatever). Fake it :)

[quote=“tobiass”, post:2, topic: 716888]
Each client that connects to a Photon room gets an ActorNumber. This is instant, when joining the room, so that number is very reliable and won’t repeat.
[/quote]

Unfortunately, I don’t see anyway to convert this to an index.

[quote=“tobiass”, post:2, topic: 716888]
On top of this, PUN has a player indexing component which figures out a player number between 1 and MaxPlayers. Example: You have 4 players in a room already and the player with ActorNumber 1 leaves. The remaining players keep their ActorNumber each and their player index, too. A new client may join and gets a new, higher ActorNumber from the server, e.g. 5. The player index should be 1 in this case, as that number became available when the ActorNumber 1 left.
[/quote]

Yes. This component does NOT work reliably. The issue is detailed well here.

https://forum.photonengine.com/discussion/12553/strange-behavior-when-joining-different-scene-with-autosyncscene-true#latest

[quote=“tobiass”, post:2, topic: 716888]
If this is not working for you, let us know how it’s wrong. We can have a look.
[/quote]

I have, as detailed in the above post. I need a method by which players can have a unique ID BEFORE entering the scene. If AutoSyncScene is enabled, this does not occur. If AutoSync Scene is not enabled this problem exists…

[quote=“tobiass”, post:2, topic: 716888]
IAs for lobby: Only when you are in a room, you can communicate with everyone else in that room. If you enter a room and others are in another scene, you will run into issues where a client gets updates from networked objects, which the local client didn’t load yet. This causes issues, so it might be easier to load the correct scene but show a UI on top of that (or a different camera or whatever). Fake it :slight_smile:
[/quote]

[quote=“ThySpektre”, post:3, topic: 716888]
I need a method by which players can have a unique ID BEFORE entering the scene.
[/quote]
The PhotonPlayer.ID is a unique ID (in a room), given by the server when someone joins a room. In PUN 2, this is the Player.ActorNumber. It’s never reused and automatically used all messages.
The player numbering / indexing does not provide a unique ID: When player number 2 leaves (e.g.) someone else may become player 2, joining a moment later.
This is why you should use the player numbering in a purely cosmetic way (display, etc) and instead rely on the PhotonPlayer.ID for anything that identifies a client/actor in the room.
Player Numbering needs some negotiation, which is why it’s not always available on join.
We could make everyone wait until it’s done, of course but this wasn’t requested often, before.

So, if you want to build your logic based on non-unique numbers which are reused when players leave and others join, then you should simply do your own level loading and when the player numbering for new players is “done”, you load the new scene (leaving the “lobby scene”). Deactivate PUN’s “Automatically Sync Scene” feature, put the “map” info into a Custom Room Property and use that to load the play scene whenever you’re ready.

In PUN 2, the Asteroids Demo is doing something like it: It has a screen where every player has to check “ready”, before we start the game. This is similar. You can do this in PUN Classic, too, of course.

Edit: PhotonViews do relate to the Player.ID, not the player number. Updates, RPCs and all that are related to the .ID and not to the number (which is, as said, reused). So it really makes sense to just sort your display based on the player number…

[quote=“tobiass”, post:4, topic: 716888]
The PhotonPlayer.ID is a unique ID (in a room), given by the server when someone joins a room. In PUN 2, this is the Player.ActorNumber. It’s never reused and automatically used all messages.
The player numbering / indexing does not provide a unique ID: When player number 2 leaves (e.g.) someone else may become player 2, joining a moment later.
[/quote]

Thanks Tobiass. That sentence was worded badly. An index is unique at any point in time. That is what I am looking for. Startup behaviors of the various players depend on the index of the player in game. There are a finite number of behaviors. These are mapped to the players’ indicies. As such, PhotonPlayer.ID is not suitable.

[quote=“tobiass”, post:4, topic: 716888]
This is why you should use the player numbering in a purely cosmetic way (display, etc) and instead rely on the PhotonPlayer.ID for anything that identifies a client/actor in the room.
Player Numbering needs some negotiation, which is why it’s not always available on join.
[/quote]

Unfortunately, this runs into the same timing issue detailed previously. Converting these ID’s into indicies requires communication with the room.

[quote=“tobiass”, post:4, topic: 716888]
We could make everyone wait until it’s done, of course but this wasn’t requested often, before.
[/quote]

I’m not sure I understand this. If you are joining a game in progress (as is the problem case here) the other players would continue playing until the joining player had an index and could properly join the scene.

[quote=“tobiass”, post:4, topic: 716888]
So, if you want to build your logic based on non-unique numbers which are reused when players leave and others join, then you should simply do your own level loading and when the player numbering for new players is “done”, you load the new scene (leaving the “lobby scene”).
[/quote]

How would one accomplish this? If one turns off the message queue these indicies never are communicated. If one turns on the message queue, one receives many messages for objects that do not yet exist.

[quote=“tobiass”, post:4, topic: 716888]
Deactivate PUN’s “Automatically Sync Scene” feature, put the “map” info into a Custom Room Property and use that to load the play scene whenever you’re ready.
[/quote]

Are you saying each players’ index should be stored as a custom room property as opposed to a custom player property?

[quote=“ThySpektre”, post:5, topic: 716888]
I’m not sure I understand this. If you are joining a game in progress (as is the problem case here) the other players would continue playing until the joining player had an index and could properly join the scene.
[/quote]

That’s my bad wording, sorry. :slight_smile:
I meant to say: We could delay the “joined” callback until the player number was “found”. This will make “everyone” wait in the sense that it delays the joined callback for each player (individually, not for the full room).

[quote=“ThySpektre”, post:5, topic: 716888]
Are you saying each players’ index should be stored as a custom room property as opposed to a custom player property?
[/quote]

Both is doable. If you place this in the room properties, you may have some “assignments”, which are outdated (when someone leaves). If a player has this in the player custom properties, then the entry gets cleared, when said player leaves.

[quote=“ThySpektre”, post:5, topic: 716888]
Startup behaviors of the various players depend on the index of the player in game. There are a finite number of behaviors.
[/quote]

I would love to understand this better. Can I imagine this as … assigning a role or something to players, depending on their placing in a team or … comparable? Mail us, if you’d like to keep this out of public.

[quote=“ThySpektre”, post:5, topic: 716888]
How would one accomplish this? If one turns off the message queue these indicies never are communicated. If one turns on the message queue, one receives many messages for objects that do not yet exist.
[/quote]

I would probably try to load the correct scene in addition to the current one, which you keep as an overlay until everything is setup. The benefit would be that you could already make use of updates coming in the background but you’d not see it. Then, an event “im done / ready” might tell the others when the new player is ready.

Technically, it should also be possible for everyone to calculate the correct player numbering with the values available on join: The player-list is known, their custom properties and their IDs. Even if more than one spot is vacant it’s clear how new players pick spots (lowest first). So in theory, we don’t need to wait until someone else made a choice and stored it. The results are clear. We just wait to double check.
If the scene loading in the background doesn’t work, we should take a look at this.

1 Like

[quote=“tobiass”, post:6, topic: 716888]
That’s my bad wording, sorry. :slight_smile:
I meant to say: We could delay the “joined” callback until the player number was “found”. This will make “everyone” wait in the sense that it delays the joined callback for each player (individually, not for the full room).
[/quote]

Understood. This delay would certainly be helpful in my case. If I envision this timing correctly then, I could initialize AutoSyncScene and isMessageQueueRunning to false, wait for OnJoinedRoom() to fire and then enable these, knowing that when it sends me to the game scene, I’d have a valid player index.

[quote=“tobiass”, post:6, topic: 716888]
Both is doable. If you place this in the room properties, you may have some “assignments”, which are outdated (when someone leaves). If a player has this in the player custom properties, then the entry gets cleared, when said player leaves.
[/quote]

Understood, which is why I am currently implementing this via Player Properties. I had hoped that perhaps some Room Properties could be read before entering a room and thus avoid the timing issue.

[quote=“tobiass”, post:6, topic: 716888]
I would love to understand this better. Can I imagine this as … assigning a role or something to players, depending on their placing in a team or … comparable? Mail us, if you’d like to keep this out of public.
[/quote]

Yes, you understand it exactly right. Different team members have different behaviors that occur upon entering the scene. No amount of “hand waving” will alter their need to be correctly indexed prior to entering the game scene. (Including camera positioning, scene overlays, etc.) They must be properly indexed BEFORE entering the scene. (Thus the lobby scene)

[quote=“tobiass”, post:6, topic: 716888]
Technically, it should also be possible for everyone to calculate the correct player numbering with the values available on join: The player-list is known, their custom properties and their IDs. Even if more than one spot is vacant it’s clear how new players pick spots (lowest first). So in theory, we don’t need to wait until someone else made a choice and stored it. The results are clear. We just wait to double check.
[/quote]

This is what I am doing currently. In the lobby scene, OnJoinedRoom() attempts to assign a player index. This works well most of the time, but falls if 2 or more players join in close proximity to one another. Here is the snippet from OnJoinedRoom()

        //Setup Player Index
        //Initialize Player Custom Property
        Hashtable indexProps = new Hashtable() { { "in", -1 } };
        //PhotonNetwork.player.SetCustomProperties(indexProps);

        //Iterate through all Players to get their index
        bool[] taken = { false, false, false, false, false, false };

        foreach (PhotonPlayer photonPlayer in PhotonNetwork.otherPlayers)
        {
            int index = 0;
            Nullable<int> nullIndex = photonPlayer.CustomProperties["in"] as Nullable<int>;
            if (nullIndex != null)
            {
                index = (int)nullIndex;
                taken[index] = true;
                print(index.ToString());
                if (index > -1)
                {
                    taken[index] = true;
                }
            }
            else
            {
                print("Null found.  Join time too close to another.  Duplicate Behavior will appear.");
            }

        }

        //Step through indices until empty spot is found and assign it to player
        int i2 = 0;
        while (taken[i2] == true)
        {
            i2++;
        }

        indexProps = new Hashtable() { { "in", i2 } };
        PhotonNetwork.player.SetCustomProperties(indexProps);
        PlayerNetwork.Instance.Index = i2;
        print(i2.ToString());

        PhotonNetwork.automaticallySyncScene = true;
    }

It's weekend time here. I'm sorry but this delays a proper reply to Monday.

[quote=“tobiass”, post:8, topic: 716888]
It’s weekend time here. I’m sorry but this delays a proper reply to Monday.
[/quote]

You have weekends?!?!?!?

Enjoy.

2 Likes

[quote=“ThySpektre”, post:7, topic: 716888]
I had hoped that perhaps some Room Properties could be read before entering a room and thus avoid the timing issue.
[/quote]
It would be impossible to get this safe. Before you’re in the room, you are on the Master Server, which would need to get the info from the Game Server and it may change anytime. Then the client is in transition until being in the room.

[quote=“ThySpektre”, post:7, topic: 716888]
They must be properly indexed BEFORE entering the scene.
[/quote]
Ok. It would have been easier to solve, if the setup of a role is not needed when you’re loading a scene but that’s how things are now.

[quote=“ThySpektre”, post:7, topic: 716888]
This works well most of the time, but falls if 2 or more players join in close proximity to one another.
[/quote]
I got it on my list to check this but couldn’t find the time yet, as we’re preparing PUN v2.3 with a few quite critical fixes.
In general, I think it should be possible to cover all cases.

How far are you atm?

Thank you
I have completed my work thanks to your sharing
GamesBX

[quote=“tobiass”, post:10, topic: 716888]
It would be impossible to get this safe. Before you’re in the room, you are on the Master Server, which would need to get the info from the Game Server and it may change anytime. Then the client is in transition until being in the room.

Ok. It would have been easier to solve, if the setup of a role is not needed when you’re loading a scene but that’s how things are now.

I got it on my list to check this but couldn’t find the time yet, as we’re preparing PUN v2.3 with a few quite critical fixes.
In general, I think it should be possible to cover all cases.

How far are you atm?
[/quote]

Various components to the project are in different spots. We were hoping to stay with PUN v1.x for this game before moving to v2.x for the next, but we aren’t to alpha testing yet.

[quote=“GamesBX2018”, post:11, topic: 716888]
Thank you
I have completed my work thanks to your sharing
GamesBX
[/quote]

Which work? Were you able to complete what I am tyng to do? If so, how?

[quote=“tobiass”, post:10, topic: 716888]
It would be impossible to get this safe. Before you’re in the room, you are on the Master Server, which would need to get the info from the Game Server and it may change anytime. Then the client is in transition until being in the room.

Ok. It would have been easier to solve, if the setup of a role is not needed when you’re loading a scene but that’s how things are now.

I got it on my list to check this but couldn’t find the time yet, as we’re preparing PUN v2.3 with a few quite critical fixes.
In general, I think it should be possible to cover all cases.

How far are you atm?
[/quote]

Any updates?

@ThySpektre : It's still on my list but unfortunately, I had to prioritize the release of v2.4 with fixes to the socket code for the 4.x runtime. That was affecting a growing number of users.
As before I can't promise a timing but plan to look into this next week.
I didn't plan to implement this for PUN v1.x, however. It should be possible to port it back from 2.x.

@ThySpektre : Sorry for the very very late reply. Lots to do.

I think it's impossible to select a number without waiting. Think about this case:
Let's use A, B, C and D for four actors joining a game (corresponding 1, 2, 3 and 4). They should select 0, 1, 2 and 3 as player number.
A and B are in a game. Player C joins, Player B leaves and Player D joins almost at the same time.
Now we run into issues: C would select 2, as B was still using 1. D joins and knows that B left (but not when, in relation to C joining). If C didn't announce it's number to player D yet, then D can only guess that C is using the free slot that B left: 1. It would select 2 due to that but that clashes with C's selection.

With that in mind, I guess joining players have to wait, until everyone else announced their number slot.

This means: The logic has to wait, until the player numbering is finished. So instead of doing something on join, entering the game scene can only be done once numbering is defined.

[quote=“tobiass”, post:16, topic: 716888]
@ThySpektre : Sorry for the very very late reply. Lots to do.

I think it’s impossible to select a number without waiting. Think about this case:
Let’s use A, B, C and D for four actors joining a game (corresponding 1, 2, 3 and 4). They should select 0, 1, 2 and 3 as player number.
A and B are in a game. Player C joins, Player B leaves and Player D joins almost at the same time.
Now we run into issues: C would select 2, as B was still using 1. D joins and knows that B left (but not when, in relation to C joining). If C didn’t announce it’s number to player D yet, then D can only guess that C is using the free slot that B left: 1. It would select 2 due to that but that clashes with C’s selection.

With that in mind, I guess joining players have to wait, until everyone else announced their number slot.

This means: The logic has to wait, until the player numbering is finished. So instead of doing something on join, entering the game scene can only be done once numbering is defined.
[/quote]

Thanks for getting back but this scenario does not follow.

As per the previous conversation, you were looking at:

"I meant to say: We could delay the “joined” callback until the player number was “found”.

  1. C would select 2. Correct.
  2. D joins and Photon internally retrieves a player list and an index set. Two scenarios then could occur based on timing:
    a. C has already resolved an index, and thus save for the joining player, the index is complete and thus player D’s index is resolved and player D is sent an OnJoinedRoom() callback.
    b. C has not resolved an index, and so D does not receive the OnJoinedRoom() callback immediately. Once Photon has resolved these indicies, an OnJoinedRoom() call back is sent.

If what you mean to say is, “there is no workaround that can happen on the client”, I agree with you as I have tried many iterations over the past months.

What we had been discussing is delaying the OnJoinedRoom() callback until the index has been found.

Is this possible? If not, we need to scrap this game idea and move on.

Thanks.

[quote=“ThySpektre”, post:17, topic: 716888]
What we had been discussing is delaying the OnJoinedRoom() callback until the index has been found.
[/quote]
Everything is possible. It’s just code.
However, this change needs to be done on the client side and it could be quite some work.

Right now, I’m thinking it may be simpler to work on the client logic to trigger loading the game scene later on, when the player numbering is done (there’s a callback for that). The result would be the same: You load the scene when numbering is done. It’s just not on “Join” but on “Numbering done”, imho.

Or: Load the scene, enter it, maybe put an overlay over the scene and allow any client to select the role while in-room. Again, when the numbering is done. It’s a matter of arranging the timing of the instantiation of your own character, I guess.

Both options will mean you can use stock PUN, which is a good thing, as updates will be simpler.

[quote=“tobiass”, post:18, topic: 716888]
Everything is possible. It’s just code.
However, this change needs to be done on the client side and it could be quite some work.

Right now, I’m thinking it may be simpler to work on the client logic to trigger loading the game scene later on, when the player numbering is done (there’s a callback for that). The result would be the same: You load the scene when numbering is done. It’s just not on “Join” but on “Numbering done”, imho.

Or: Load the scene, enter it, maybe put an overlay over the scene and allow any client to select the role while in-room. Again, when the numbering is done. It’s a matter of arranging the timing of the instantiation of your own character, I guess.

Both options will mean you can use stock PUN, which is a good thing, as updates will be simpler.
[/quote]

I have attempted such a thing already. If looking at the code above when I see that a null value is returned (index not yet set), I set a flag and then check this on each Update for that client until they have a valid index.

Unfortunately in the interim, since Photon believes I am now in the room, it outputs many errors for not being in the “right scene” for its messages.

I can turn off the messaging queue, but then the various other clients have messages that go unreceived (they should never have been sent) as I should not have “joined” the room until the index has been set.

[quote=“tobiass”, post:18, topic: 716888]
Everything is possible. It’s just code.
However, this change needs to be done on the client side and it could be quite some work.

Right now, I’m thinking it may be simpler to work on the client logic to trigger loading the game scene later on, when the player numbering is done (there’s a callback for that). The result would be the same: You load the scene when numbering is done. It’s just not on “Join” but on “Numbering done”, imho.
[/quote]

How would this work as not entering the scene until a “Numbering done” callback is run would be what I am looking for.

The Catch-22 I have run into with this method is.

  1. If I leave the Messaging queue on, I inevitably receive errors from message for object that I do not yet have (I’m not in that scene)

  2. If I turn the Messaging queue off, I do not get the callback.