Leaving room in Photon

Hi everyone, I create a simple multiplayer game using PUN2 where one player can create a room with a specific name and another player can join this room by clicking its name in a simple list. After that I add an "exit button" that allow the player to leave the room before the start of the game using
PhotonNetwork.LeaveRoom();
because I thounght that this code make the room re-joinable but the room is no more joinable after the leave of the player, indipendently if the player is the masterclient or not. So my question is: is there any method to make a room re-joinable after one player leaves it? Or in case that's not possible, is there any method that I can use to force to leave every player and close the room when someone click "exit button"? Thanks in advance and sorry for my bad English :)

Comments

  • The room should be "joinable", provided it's not closed or full.
    But an empty room will be cleaned up (no active players -> room gets cleaned up and can't be re joined).
  • Steven123
    Steven123
    edited June 23

    What about when you have the following situation:

    • Player X creates a room.
    • After the level loads up, he immediately exits (PhotonNetwork.LoadLevel("Lobby")).
    • And tries to create a room with the same properties, same name etc.

    I tried to implement this and it gives me an error: "MissingReferenceException: THe object of type 'GameObject' has been destroyed but you are still trying to access it. Your script should either check if it is null or you should not destroy the object.".

    Why does that happen? Does that have anything to do with the fact that when the player exits the room, only PhotonNetwork.LoadLevel() is called instead of LeaveRoom()?

  • Tobias
    Tobias admin

    First off: LoadLevel does not leave the room. You can not join new rooms unless the LBC is connected to the Master Server...

    Why this happens? Because "The object of type 'GameObject' has been destroyed but you are still trying to access it. Your script should either check if it is null or you should not destroy the object."

    You need to figure out which object is missing, then why it is missing. Usually, Unity destroys the old scene, when you load a new one, so that may be a hint.

    It's not something I can dive deeper into but maybe the community can help.

  • Steven, I don't know PUN well but I learn a lot by trying to solve issues. They key here is confirm what your code does when you write "immediately exits" and "create a room", etc.

    Are you calling PhotonNetwork.LeaveRoom() to leave? That's the start of the pattern. It will call OnLeftRoom which gives you a change to process more after having left.

  • So here is what I tried to implement. Sorry for the late reply.

    This is how I create the room:

     RoomOptions options = new RoomOptions()
            {
    
    
                IsOpen = true,
                MaxPlayers = (byte)nrPlayers_HostGame,
                CustomRoomProperties = new ExitGames.Client.Photon.Hashtable()
                {
                    { "C0", "yes" },
                    { "C1", HG_NameGame.text }
                },
                CustomRoomPropertiesForLobby = new string[]
                {
                    "C0",
                    "C1",
                    "key"
                }
                //CleanupCacheOnLeave = false
            };
    
    
            if (!Public_Toggle.isOn)
            {
                options.CustomRoomProperties.Add("key", PasswordEncryptor.Encrypt(HG_PasswordGame.text));
                options.IsVisible = false;
            }
            else
            {
                options.CustomRoomProperties.Add("public", true);
                options.IsVisible = true;
            }
    
    
    
    
            PhotonNetwork.LocalPlayer.SetCustomProperties(new ExitGames.Client.Photon.Hashtable()
            {
                { "knowsPassword", true }
            });
            PhotonNetwork.CreateRoom(HG_NameGame.text, options, customLobby);
    


    I don't actually use the "C0" or "C1" things because I don't understand how the OnRoomListUpdated works since it is never called in any instance.

    Anyhow, leaving that aside, this is how I exit a room. Nothing too crazy, just a simple button in the player's UI:

    public void ExitButton_OnClick()
        {
            if (PhotonNetwork.InRoom)
            {
                if (PhotonNetwork.IsMasterClient && PhotonNetwork.CurrentRoom.PlayerCount > 1) MigrateMaster();
                else
                {
                    PhotonNetwork.DestroyPlayerObjects(PhotonNetwork.LocalPlayer);
                    PhotonNetwork.LeaveRoom();
                }
            }
        }
    
    private void MigrateMaster()
        {
            var dict = PhotonNetwork.CurrentRoom.Players;
            if (PhotonNetwork.SetMasterClient(dict[dict.Count - 1]))
                PhotonNetwork.LeaveRoom();
        }
    
    
        public override void OnLeftRoom()
        {
            Debug.LogError("Left room");
            PhotonNetwork.LoadLevel("Launcher");
            Debug.LogError("Left room");
        }
    

    Now, the biggest problem is that the button is pressed correctly and the "event" is detected. However, the Debug.LogError("Left room") in OnLeftRoom() method is NEVER called. And instead of loading the Launcher scene, it just stays in the Game scene with the player's instance being destroyed which is very suspicious to me.

  • Steven123
    Steven123
    edited June 30

    I just further tested this scenario and it makes me believe only one thing:

    The player is destroyed way too early and the OnLeftRoom() method which is in the same script will never get called.

    I tried to make call DontDestroyOnLoad() for the instance off the player, but that doesn't solve it.


    Any suggestions at this point?

  • Steven123
    Steven123
    edited June 30

    I actually solved this issue by using OnPlayerLeftRoom(Player otherPlayer).

    The best solution I found, and it works whether you are a master client or not in a room, is to let a Manager script (usually the one that spawns the players in the room) handle the Destroy methods instead of the player who leaves the room at that instance.

    It's best to leave the room option CleanupCacheOnLeave to false so that the Manager script can destroy the inactive players manually. I guess this way you have more control and you know each time when each player was destroyed or not.

    And so the player can just have PhotonNetwork.LeaveRoom() and the OnLeftRoom() callback in the player script and the manager script will PhotonNetwork.Destroy(otherPlayer) in the OnPlayerLeftRoom(Player otherPlayer).


    P.S.: The method PhotonNetwork.DestroyPlayerObjects(otherPlayer) also destroys the objects that the player instantiated, so be careful.

  • Hi @Steven123 I can't say exactly understand your intent but it looks like you are handing off the "Master" role. I do not know (someone can comment) if this is needed (maybe so) but the process (if needed) is surely templated somewhere.

    You have a bit of spaghetti creeping in (from what I can see) which may make your logic slightly less than obvious. Assuming the "key" and "public" properties are always set one way or the other? It seems that Public_Toggle.isOn could be passed as a parameter to the constructor thereby getting back a fully-baked RoomOptions object.

    Similarly I don't see the need for two branches in the Exit OnClick handler. When someone clicks the exit button they go to a single handler which determines how best to handle it. Then for instance you don't sometimes exit from the OnClick handler and sometimes from MigrateMaster.

    And from a VR course I took we call PhotonNetwork.Disconnect from OnLeftRoom and then in OnDisconnected return them to a "home room". It apparently can help clean things up but I can't attest to it (just read it somewhere).

    Bottom line is if things are seeming acting "weird" it may indicate something in your logic. The library has been used for a long time and if there were lots of "gotchas" I have to assume there would be list available.