Can't Reconnect when Disconnected via ServerTimeout

PUN 2.10, Photon Cloud, Region us

I'm trying to silently reconnect users when they are disconnected, whether in a lobby, or in a room.

In my current test, I have a Host device, and a Guest device.. The Host creates and joins the room. The guest joins the room.
I pause the guest's unity editor until the guest drops from the Host's room, then I unpause the unity editor.

No matter what I call from the guest machine, ConnectUsingSettings(), Reconnect, or RecconnectAndJoin(),, or RejoinRoom, nothing is working.

The sequence of events after I unpause is as follows:
OnDisconnect is fired with ServerTimeout (Disconnected GameServer)
OnLeaveRoom then fires (Disconnected GameServer)
Then my Network Objects are destroyed (2 players), one after the other

Generally, when I call something, it will immediately fire OnDisconnected with cause of None
Then I usually get the following error: Operation Authenticate (230) not called because client is not connected or not ready yet, client state: Disconnected

Is there a chart that can tell me what to call based on what state and disconnect cause?
Seems like this shouldn't be this difficult, or a reconnect recovery tool (small class should already be available for this, which is what I'm trying to write).

Thanks in advance.

Comments

  • JohnTube
    JohnTube ✭✭✭✭✭
    edited April 2019
    Hi @KirkGames,

    a reconnect recovery tool (small class should already be available for this, which is what I'm trying to write).
    I have provided a similar thing for PUN1 before on the forum, I just updated it for PUN2:

    Could you try this UtilityScript? (save as a file under "Assets\Photon\PhotonUnityNetworking\UtilityScripts\DisconnectsRecovery.cs")
  • Has ReconnectAndRejoin been tested for 2.10 with a ServerTimeout?
  • JohnTube
    JohnTube ✭✭✭✭✭
    edited May 2019
    Hi @KirkGames,

    Sorry for the late comment.
    Why are you asking? it's not working for you?
    What error do you see?
  • error: Operation Authenticate (230) not called because client is not connected or not ready yet, client state: Disconnected.

    My original post above has that information.
  • JohnTube
    JohnTube ✭✭✭✭✭
    Hi @KirkGames,

    OK I see.
    Could you try this updated utility script version? (if link is empty, script can be found here) If it still does not help let us know by sending an email to deverloper@photonengine.com.
  • JohnTube
    JohnTube ✭✭✭✭✭
    a better, updated version:
    using System;
    using System.Collections;
    using ExitGames.Client.Photon;
    using Photon.Realtime;
    using UnityEngine;
    
    namespace Photon.Pun.UtilityScripts
    {
        /// <summary>
        /// Unexpected disconnects recovery
        /// </summary>
        public class DisconnectsRecovery : MonoBehaviourPunCallbacks
        {
            [Tooltip("Whether or not attempt a rejoin without doing any checks.")]
            [SerializeField]
            private bool skipRejoinChecks;
            [Tooltip("Whether or not realtime webhooks are configured with persistence enabled")]
            [SerializeField]
            private bool persistenceEnabled;
    
            private bool rejoinCalled;
    
            private int minTimeRequiredToRejoin = 0; // TODO: set dynamically based on PhotonNetwork.NetworkingClient.LoadBalancingPeer.RoundTripTime
    
            private bool wasInRoom
            {
                get { return roomToRejoin != null; }
            }
    
            private bool reconnectCalled;
    
            private Room roomToRejoin;
    
            private Coroutine reconnectDelayCoroutine;
    
            public override void OnDisable()
            {
                base.OnDisable();
                if (reconnectDelayCoroutine != null)
                {
                    StopCoroutine(reconnectDelayCoroutine);
                    reconnectDelayCoroutine = null;
                }
            }
    
            public override void OnDisconnected(DisconnectCause cause)
            {
                Debug.LogFormat("OnDisconnected(cause={0}) ClientState={1} PeerState={2}",
                    cause, // TODO: filter obsolete enum values
                    PhotonNetwork.NetworkingClient.State,
                    PhotonNetwork.NetworkingClient.LoadBalancingPeer.PeerState);
                if (rejoinCalled)
                {
                    Debug.LogErrorFormat("Rejoin failed, client disconnected due to {0}", cause);
                    rejoinCalled = false;
                }
                else if (reconnectCalled)
                {
                    Debug.LogErrorFormat("Reconnect failed, client disconnected due to {0}", cause);
                    reconnectCalled = false;
                }
                else
                {
                    HandleDisconnect(cause);
                }
            }
    
            private void HandleDisconnect(DisconnectCause cause)
            {
                switch (cause)
                {
                    case DisconnectCause.ClientTimeout:
                    case DisconnectCause.Exception:
                    case DisconnectCause.ServerTimeout:
                    case DisconnectCause.DisconnectByServerLogic:
                    case DisconnectCause.AuthenticationTicketExpired:
                    case DisconnectCause.DisconnectByServerReasonUnknown:
                        reconnectDelayCoroutine = StartCoroutine(HandleDisconnectDelayed());
                        return;
                }
            }
    
            private IEnumerator HandleDisconnectDelayed()
            {
                WaitForEndOfFrame wait = new WaitForEndOfFrame();
                yield return wait;
                HandleDisconnect();
            }
    
            private void HandleDisconnect()
            {
                if (wasInRoom)
                {
                    CheckAndTryQuickRejoin();
                }
                else
                {
                    Debug.Log("PhotonNetwork.Reconnect called");
                    reconnectCalled = PhotonNetwork.Reconnect();
                }
            }
    
            public override void OnJoinRoomFailed(short returnCode, string message)
            {
                if (!rejoinCalled)
                {
                    return;
                }
                rejoinCalled = false;
                Debug.LogErrorFormat("Rejoin failed with error code: {0} & error message: {1}", returnCode, message);
            }
    
            public override void OnJoinedRoom()
            {
                if (rejoinCalled)
                {
                    Debug.Log("Rejoin successful");
                    rejoinCalled = false;
                }
                roomToRejoin = PhotonNetwork.CurrentRoom;
            }
    
            private void CheckAndTryQuickRejoin()
            {
                if (ShouldTryRejoin(roomToRejoin))
                {
                    rejoinCalled = PhotonNetwork.ReconnectAndRejoin();
                    if (rejoinCalled)
                    {
                        Debug.Log("PhotonNetwork.ReconnectAndRejoin called");
                        return;
                    }
                }
                Debug.LogWarning("PhotonNetwork.ReconnectAndRejoin not called, PhotonNetwork.Reconnect is called instead.");
                reconnectCalled = PhotonNetwork.Reconnect();
            }
    
            private bool ShouldTryRejoin(Room room)
            {
                if (room == null)
                {
                    Debug.LogError("Room is null");
                    return false;
                }
                if (skipRejoinChecks)
                {
                    return true;
                }
                bool wasLastActivePlayer = true;
                if (!persistenceEnabled)
                {
                    foreach (Player player in room.Players.Values)
                    {
                        if (!player.IsInactive && !player.IsLocal)
                        {
                            wasLastActivePlayer = false;
                            break;
                        }
                    }
                }
                if ((room.PlayerTtl < 0 || room.PlayerTtl > minTimeRequiredToRejoin) // PlayerTTL checks
                    && (!wasLastActivePlayer || room.EmptyRoomTtl > minTimeRequiredToRejoin || persistenceEnabled)) // EmptyRoomTTL checks
                {
                    return true;
                }
                return false;
            }
    
            public override void OnConnectedToMaster()
            {
                if (reconnectCalled)
                {
                    Debug.Log("Reconnect successful");
                    reconnectCalled = false;
                }
                if (wasInRoom && !rejoinCalled && ShouldTryRejoin(roomToRejoin)) // should not happen
                {
                    rejoinCalled = PhotonNetwork.RejoinRoom(roomToRejoin.Name);
                }
                roomToRejoin = null;
            }
        }
    }
  • Hello all,
    I'm using cocos2dx with photon, but I can't reconnect when client has timeout.
  • JohnTube
    JohnTube ✭✭✭✭✭
    Hey @trongdung85,

    Thank you for choosing Photon!

    Open a new discussion on the Native category and I'm sure my colleague @Kaiserludi will help you out.