Search Unity

  1. Unity 2018.3 is now released.
    Dismiss Notice
  2. The Unity Pro & Visual Studio Professional Bundle gives you the tools you need to develop faster & collaborate more efficiently. Learn more.
    Dismiss Notice
  3. Want more efficiency in your development work? Sign up to receive weekly tech and creative know-how from Unity experts.
    Dismiss Notice
  4. Build games and experiences that can load instantly and without install. Explore the Project Tiny Preview today!
    Dismiss Notice
  5. Nominations have been announced for this years Unity Awards. Celebrate the wonderful projects made by your peers this year and get voting! Vote here!
    Dismiss Notice
  6. Want to provide direct feedback to the Unity team? Join the Unity Advisory Panel.
    Dismiss Notice
  7. Improve your Unity skills with a certified instructor in a private, interactive classroom. Watch the overview now.
    Dismiss Notice

Photon Unity Joining a room with game in progress

Discussion in 'Connected Games' started by ThySpektre, Oct 3, 2018.

  1. ThySpektre

    ThySpektre

    Joined:
    Mar 15, 2016
    Posts:
    38
    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.
     
  2. tobiass

    tobiass

    Joined:
    Apr 7, 2009
    Posts:
    2,068
    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 :)
     
  3. ThySpektre

    ThySpektre

    Joined:
    Mar 15, 2016
    Posts:
    38
    Unfortunately, I don't see anyway to convert this to an index.

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

    https://forum.photonengine.com/disc...ifferent-scene-with-autosyncscene-true#latest

    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...

     
    Last edited: Oct 10, 2018
  4. tobiass

    tobiass

    Joined:
    Apr 7, 2009
    Posts:
    2,068
    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...
     
  5. ThySpektre

    ThySpektre

    Joined:
    Mar 15, 2016
    Posts:
    38
    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.

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

    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.

    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.

    Are you saying each players' index should be stored as a custom room property as opposed to a custom player property?
     
    Last edited: Oct 11, 2018
  6. tobiass

    tobiass

    Joined:
    Apr 7, 2009
    Posts:
    2,068
    That's my bad wording, sorry. :)
    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).

    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.

    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.

    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.
     
  7. ThySpektre

    ThySpektre

    Joined:
    Mar 15, 2016
    Posts:
    38
    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.

    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.

    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)

    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()

    Code (CSharp):
    1.         //Setup Player Index
    2.         //Initialize Player Custom Property
    3.         Hashtable indexProps = new Hashtable() { { "in", -1 } };
    4.         //PhotonNetwork.player.SetCustomProperties(indexProps);
    5.  
    6.         //Iterate through all Players to get their index
    7.         bool[] taken = { false, false, false, false, false, false };
    8.  
    9.         foreach (PhotonPlayer photonPlayer in PhotonNetwork.otherPlayers)
    10.         {
    11.             int index = 0;
    12.             Nullable<int> nullIndex = photonPlayer.CustomProperties["in"] as Nullable<int>;
    13.             if (nullIndex != null)
    14.             {
    15.                 index = (int)nullIndex;
    16.                 taken[index] = true;
    17.                 print(index.ToString());
    18.                 if (index > -1)
    19.                 {
    20.                     taken[index] = true;
    21.                 }
    22.             }
    23.             else
    24.             {
    25.                 print("Null found.  Join time too close to another.  Duplicate Behavior will appear.");
    26.             }
    27.  
    28.         }
    29.  
    30.         //Step through indices until empty spot is found and assign it to player
    31.         int i2 = 0;
    32.         while (taken[i2] == true)
    33.         {
    34.             i2++;
    35.         }
    36.  
    37.         indexProps = new Hashtable() { { "in", i2 } };
    38.         PhotonNetwork.player.SetCustomProperties(indexProps);
    39.         PlayerNetwork.Instance.Index = i2;
    40.         print(i2.ToString());
    41.  
    42.         PhotonNetwork.automaticallySyncScene = true;
    43.     }
     
    Last edited: Oct 12, 2018
  8. tobiass

    tobiass

    Joined:
    Apr 7, 2009
    Posts:
    2,068
    It's weekend time here. I'm sorry but this delays a proper reply to Monday.
     
  9. ThySpektre

    ThySpektre

    Joined:
    Mar 15, 2016
    Posts:
    38
    You have weekends?!?!?!?

    Enjoy.
     
    tobiass likes this.
  10. tobiass

    tobiass

    Joined:
    Apr 7, 2009
    Posts:
    2,068
    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?
     
  11. GamesBX2018

    GamesBX2018

    Joined:
    Oct 12, 2018
    Posts:
    1
    Thank you
    I have completed my work thanks to your sharing
    GamesBX
     
  12. ThySpektre

    ThySpektre

    Joined:
    Mar 15, 2016
    Posts:
    38
    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.
     
  13. ThySpektre

    ThySpektre

    Joined:
    Mar 15, 2016
    Posts:
    38
    Which work? Were you able to complete what I am tyng to do? If so, how?
     
  14. ThySpektre

    ThySpektre

    Joined:
    Mar 15, 2016
    Posts:
    38
    Any updates?
     
  15. tobiass

    tobiass

    Joined:
    Apr 7, 2009
    Posts:
    2,068
    @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.
     
  16. tobiass

    tobiass

    Joined:
    Apr 7, 2009
    Posts:
    2,068
    @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.
     
  17. ThySpektre

    ThySpektre

    Joined:
    Mar 15, 2016
    Posts:
    38
    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.
     
    Last edited: Nov 14, 2018
  18. tobiass

    tobiass

    Joined:
    Apr 7, 2009
    Posts:
    2,068
    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.
     
  19. ThySpektre

    ThySpektre

    Joined:
    Mar 15, 2016
    Posts:
    38
    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.
     
    Last edited: Nov 19, 2018
  20. ThySpektre

    ThySpektre

    Joined:
    Mar 15, 2016
    Posts:
    38
    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.
     
  21. tobiass

    tobiass

    Joined:
    Apr 7, 2009
    Posts:
    2,068
    What if you get into the right scene but use an overlay / UI to show something else, until the setup is done?
    The client would update the objects in the background and would be up to date (in terms of updates) when the role is selected. Of course, you'd have to delay setting up any role-related objects and instantiate them delayed.
     
  22. ThySpektre

    ThySpektre

    Joined:
    Mar 15, 2016
    Posts:
    38
    I think I've mentioned before how this will not work for this project

    I am interested in the 2 solution you have suggested previously and how they would/can work..

    Namely:

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

    or alternately info about:

    "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."

    Thanks.
     
  23. tobiass

    tobiass

    Joined:
    Apr 7, 2009
    Posts:
    2,068
    The second is comparatively simple: Set AutomaticallySyncScene to false and manually load the scene when ready.
    To share which scene should be loaded, use a Custom Room Property. E.g. the Master Client could make sure there is some ID stored for that asap.
    Use LoadLevel(int levelNumber) to make sure the clients keep the connection while loading the scene or load the scene async (in the background).
     
  24. ThySpektre

    ThySpektre

    Joined:
    Mar 15, 2016
    Posts:
    38
    This bypasses the problem of receiving messages for objects not in your scene? The problem, as noted above, I have run into is that once you have joined a room, you receive messages for players that are already in the scene. Suppressing these messages by turning the message queue off, disables you from receiving the indexing information.
     
  25. tobiass

    tobiass

    Joined:
    Apr 7, 2009
    Posts:
    2,068
    As long as you're aware you don't know the objects yet (for good reason), you could simply ignore the messages (which primarily means removing the logging for it). The warning is there to help you notice this case. However, you're free to ignore it, of course. Part of why PUN is open source, is that you should modify it, where needed.
     
  26. ThySpektre

    ThySpektre

    Joined:
    Mar 15, 2016
    Posts:
    38
    Upon joining the scene, Photon will still properly network instantiate the objects? I had assumed (perhaps incorrectly) that these messages were giving network instantiate instructions.