Skip to content

fix: disconnect issue with wifi turned off #562

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 11 additions & 3 deletions Assets/BossRoom/Prefabs/NetworkingManager.prefab
Original file line number Diff line number Diff line change
Expand Up @@ -50,11 +50,15 @@ MonoBehaviour:
m_HeartbeatTimeoutMS: 500
m_ConnectTimeoutMS: 1000
m_MaxConnectAttempts: 60
m_DisconnectTimeoutMS: 10000
m_DisconnectTimeoutMS: 5000
ConnectionData:
Address: 127.0.0.1
Port: 7777
ServerListenAddress:
DebugSimulator:
PacketDelayMS: 0
PacketJitterMS: 0
PacketDropRate: 0
--- !u!1 &503411707
GameObject:
m_ObjectHideFlags: 0
Expand Down Expand Up @@ -105,11 +109,15 @@ MonoBehaviour:
m_HeartbeatTimeoutMS: 500
m_ConnectTimeoutMS: 1000
m_MaxConnectAttempts: 60
m_DisconnectTimeoutMS: 10000
m_DisconnectTimeoutMS: 5000
ConnectionData:
Address: 127.0.0.1
Port: 7777
ServerListenAddress:
DebugSimulator:
PacketDelayMS: 0
PacketJitterMS: 0
PacketDropRate: 0
--- !u!1 &5436007408952557947
GameObject:
m_ObjectHideFlags: 0
Expand Down Expand Up @@ -219,7 +227,7 @@ MonoBehaviour:
SourceHashToOverride: 0
OverridingTargetPrefab: {fileID: 0}
TickRate: 30
ClientConnectionBufferTimeout: 10
ClientConnectionBufferTimeout: 5
ConnectionApproval: 1
ConnectionData:
EnableTimeResync: 0
Expand Down
25 changes: 11 additions & 14 deletions Assets/BossRoom/Scripts/Client/UI/Lobby/LobbyUIMediator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ public class LobbyUIMediator : MonoBehaviour
NameGenerationData m_NameGenerationData;
GameNetPortal m_GameNetPortal;
ClientGameNetPortal m_ClientNetPortal;
IDisposable m_Subscriptions;

const string k_DefaultLobbyName = "no-name";

Expand All @@ -39,6 +40,7 @@ void InjectDependenciesAndInitialize(
LocalLobby localLobby,
NameGenerationData nameGenerationData,
GameNetPortal gameNetPortal,
ISubscriber<ConnectStatus> connectStatusSub,
ClientGameNetPortal clientGameNetPortal
)
{
Expand All @@ -51,17 +53,22 @@ ClientGameNetPortal clientGameNetPortal

RegenerateName();

m_ClientNetPortal.NetworkTimedOut += OnNetworkTimeout;
m_Subscriptions = connectStatusSub.Subscribe(OnConnectStatus);
}

void OnDestroy()
void OnConnectStatus(ConnectStatus status)
{
if (m_ClientNetPortal != null)
if (status == ConnectStatus.GenericDisconnect)
{
m_ClientNetPortal.NetworkTimedOut -= OnNetworkTimeout;
UnblockUIAfterLoadingIsComplete();
}
}

void OnDestroy()
{
m_Subscriptions?.Dispose();
}

//Lobby and Relay calls done from UI

public void CreateLobbyRequest(string lobbyName, bool isPrivate, int maxPlayers, OnlineMode onlineMode)
Expand Down Expand Up @@ -236,15 +243,5 @@ void UnblockUIAfterLoadingIsComplete()
m_LoadingSpinner.SetActive(false);
}
}

/// <summary>
/// Invoked when the client sent a connection request to the server and didn't hear back at all.
/// This should create a UI letting the player know that something went wrong and to try again
/// </summary>
void OnNetworkTimeout()
{
m_LobbyServiceFacade.EndTracking();
UnblockUIAfterLoadingIsComplete();
}
}
}
3 changes: 2 additions & 1 deletion Assets/BossRoom/Scripts/Client/UI/PostGameUI.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
using UnityEngine.SceneManagement;
using UnityEngine.UI;
using TMPro;
using Unity.Multiplayer.Samples.BossRoom.Client;
using Unity.Multiplayer.Samples.BossRoom.Shared;
using Unity.Multiplayer.Samples.BossRoom.Shared.Infrastructure;
using Unity.Multiplayer.Samples.Utilities;
Expand Down Expand Up @@ -102,7 +103,7 @@ public void OnPlayAgainClicked()

public void OnMainMenuClicked()
{
m_ApplicationController.LeaveSession();
m_ApplicationController.LeaveSession(withReason: ConnectStatus.UserRequestedDisconnect);
}
}
}
Expand Down
2 changes: 1 addition & 1 deletion Assets/BossRoom/Scripts/Client/UI/UIQuitPanel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ public void Quit()
}
else
{
m_ApplicationController.LeaveSession();
m_ApplicationController.LeaveSession(withReason: ConnectStatus.UserRequestedDisconnect);
}

gameObject.SetActive(false);
Expand Down
4 changes: 2 additions & 2 deletions Assets/BossRoom/Scripts/Shared/ApplicationController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -100,15 +100,15 @@ private bool OnWantToQuit()
return canQuit;
}

public void LeaveSession()
public void LeaveSession(ConnectStatus withReason = ConnectStatus.Undefined)
{
m_LobbyServiceFacade.ForceLeaveLobbyAttempt();

// first disconnect then return to menu
var gameNetPortal = GameNetPortal.Instance;
if (gameNetPortal != null)
{
gameNetPortal.RequestDisconnect();
gameNetPortal.RequestDisconnect(withReason);
}

SceneLoaderWrapper.Instance.LoadScene("MainMenu");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,14 +31,8 @@ public class ClientGameNetPortal : MonoBehaviour
/// <summary>
/// Time in seconds before the client considers a lack of server response a timeout
/// </summary>
private const int k_TimeoutDuration = 10;
const int k_NbReconnectAttempts = 1;

/// <summary>
/// This event fires when the client sent out a request to start the client, but failed to hear back after an allotted amount of
/// time from the host.
/// </summary>
public event Action NetworkTimedOut;
private const int k_TimeoutDuration = 5;
const int k_NbReconnectAttempts = 2;

ApplicationController m_ApplicationController;
LobbyServiceFacade m_LobbyServiceFacade;
Expand Down Expand Up @@ -93,14 +87,15 @@ public void OnNetworkReady()
}
}

/// <summary>
/// Invoked when the user has requested a disconnect via the UI, e.g. when hitting "Return to Main Menu" in the post-game scene.
/// </summary>
public void OnUserDisconnectRequest()
public void OnDisconnectRequest(ConnectStatus withDisconnectReason = ConnectStatus.Undefined)
{
if (m_Portal.NetManager.IsClient)
{
DisconnectReason.SetDisconnectReason(ConnectStatus.UserRequestedDisconnect);
if (withDisconnectReason != ConnectStatus.Undefined)
{
DisconnectReason.SetDisconnectReason(withDisconnectReason);
}

if (m_TryToReconnectCoroutine != null)
{
StopCoroutine(m_TryToReconnectCoroutine);
Expand All @@ -116,7 +111,7 @@ public void OnUserDisconnectRequest()
}

// only do it here if we are not the host. The host will do it in ServerGameNetPortal
if (!m_Portal.NetManager.IsHost)
if (!m_Portal.NetManager.IsHost && m_Portal.NetManager.IsListening)
{
m_Portal.NetManager.Shutdown();
}
Expand Down Expand Up @@ -165,25 +160,26 @@ void OnDisconnectOrTimeout(ulong clientID)

//On a client disconnect we want to take them back to the main menu.
//We have to check here in SceneManager if our active scene is the main menu, as if it is, it means we timed out rather than a raw disconnect;
if (SceneManager.GetActiveScene().name != "MainMenu")
switch (DisconnectReason.Reason)
{
if (DisconnectReason.Reason == ConnectStatus.UserRequestedDisconnect || DisconnectReason.Reason == ConnectStatus.HostDisconnected || NetworkManager.Singleton.IsHost)
{
// simply shut down and go back to main menu
m_ApplicationController.LeaveSession();
}
else
{
case ConnectStatus.UserRequestedDisconnect:
case ConnectStatus.HostDisconnected:
case ConnectStatus.LoggedInAgain:
case ConnectStatus.ServerFull:
m_ApplicationController.LeaveSession(); // go through the normal leave flow
break;
case ConnectStatus.GenericDisconnect:
case ConnectStatus.Undefined:
DisconnectReason.SetDisconnectReason(ConnectStatus.Reconnecting);

// load new scene to workaround MTT-2684
SceneManager.LoadScene("Loading");

// try reconnecting
m_TryToReconnectCoroutine ??= StartCoroutine(TryToReconnect(lobbyCode));
}
}
else
{
NetworkTimedOut?.Invoke();
break;
default:
throw new NotImplementedException(DisconnectReason.Reason.ToString());
}

m_ConnectStatusPub.Publish(DisconnectReason.Reason);
Expand All @@ -197,7 +193,11 @@ private IEnumerator TryToReconnect(string lobbyCode)
int nbTries = 0;
while (nbTries < k_NbReconnectAttempts)
{
NetworkManager.Singleton.Shutdown();
if (NetworkManager.Singleton.IsListening)
{
NetworkManager.Singleton.Shutdown();
}

yield return new WaitWhile(() => NetworkManager.Singleton.ShutdownInProgress); // wait until NetworkManager completes shutting down
Debug.Log($"Reconnecting attempt {nbTries + 1}/{k_NbReconnectAttempts}...");
if (!string.IsNullOrEmpty(lobbyCode))
Expand All @@ -223,7 +223,11 @@ private IEnumerator TryToReconnect(string lobbyCode)
// If the coroutine has not been stopped before this, it means we failed to connect during all attempts
Debug.Log("All tries failed, returning to main menu");
m_LobbyServiceFacade.ForceLeaveLobbyAttempt();
NetworkManager.Singleton.Shutdown();
if (NetworkManager.Singleton.IsListening)
{
NetworkManager.Singleton.Shutdown();
}

SceneLoaderWrapper.Instance.LoadScene("MainMenu");
if (!DisconnectReason.HasTransitionReason)
{
Expand Down Expand Up @@ -283,11 +287,9 @@ async void ConnectClient(Action<string> onFailure)
{
try
{
var clientRelayUtilityTask = UnityRelayUtilities.JoinRelayServerFromJoinCode(m_JoinCode);
await clientRelayUtilityTask;
var (ipv4Address, port, allocationIdBytes, connectionData, hostConnectionData, key) = clientRelayUtilityTask.Result;
var (ipv4Address, port, allocationId, allocationIdBytes, connectionData, hostConnectionData, key) = await UnityRelayUtilities.JoinRelayServerFromJoinCode(m_JoinCode);

m_LobbyServiceFacade.UpdatePlayerRelayInfoAsync(allocationIdBytes.ToString(), m_JoinCode, null, null);
m_LobbyServiceFacade.UpdatePlayerRelayInfoAsync(allocationId.ToString(), m_JoinCode, null, null);
var utp = (UnityTransport)NetworkManager.Singleton.NetworkConfig.NetworkTransport;
utp.SetRelayServerData(ipv4Address, port, allocationIdBytes, key, connectionData, hostConnectionData);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -203,14 +203,11 @@ public async void StartUnityRelayHost()
// we now need to get the joinCode?
var GDCRegion = "us-west2";
// var GDCRegion = "us-east4";
var serverRelayUtilityTask = UnityRelayUtilities.AllocateRelayServerAndGetJoinCode(k_MaxUnityRelayConnections, region: GDCRegion);
await serverRelayUtilityTask;
// we now have the info from the relay service
var (ipv4Address, port, allocationIdBytes, connectionData, key, joinCode) = serverRelayUtilityTask.Result;
var (ipv4Address, port, allocationId, allocationIdBytes, connectionData, key, joinCode) = await UnityRelayUtilities.AllocateRelayServerAndGetJoinCode(k_MaxUnityRelayConnections, region: GDCRegion);

m_LocalLobby.RelayJoinCode = joinCode;
//next line enabled lobby and relay services integration
m_LobbyServiceFacade.UpdatePlayerRelayInfoAsync(allocationIdBytes.ToString(), joinCode, null, null);
m_LobbyServiceFacade.UpdatePlayerRelayInfoAsync(allocationId.ToString(), joinCode, null, null);

// we now need to set the RelayCode somewhere :P
utp.SetRelayServerData(ipv4Address, port, allocationIdBytes, key, connectionData);
Expand Down Expand Up @@ -238,14 +235,14 @@ void StartHost()
/// This will disconnect (on the client) or shutdown the server (on the host).
/// It's a local signal (not from the network), indicating that the user has requested a disconnect.
/// </summary>
public void RequestDisconnect()
public void RequestDisconnect(ConnectStatus withDisconnectReason = ConnectStatus.Undefined)
{
if (NetManager.IsServer)
{
NetManager.SceneManager.OnSceneEvent -= OnSceneEvent;
}
m_ClientPortal.OnUserDisconnectRequest();
m_ServerPortal.OnUserDisconnectRequest();
m_ClientPortal.OnDisconnectRequest(withDisconnectReason);
m_ServerPortal.OnDisconnectRequest();
}

public string GetPlayerId()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,7 @@ public void OnClientSceneChanged(ulong clientId, int sceneIndex)
/// Handles the flow when a user has requested a disconnect via UI (which can be invoked on the Host, and thus must be
/// handled in server code).
/// </summary>
public void OnUserDisconnectRequest()
public void OnDisconnectRequest()
{
Clear();
if (m_Portal.NetManager.IsServer)
Expand All @@ -145,7 +145,11 @@ IEnumerator WaitToShutdown()
yield return null; // todo still needed? wait for UTP's update for it to send it's batched messages
yield return null;
SessionManager<SessionPlayerData>.Instance.OnUserDisconnectRequest();
m_Portal.NetManager.Shutdown();
if (m_Portal.NetManager.IsListening)
{
m_Portal.NetManager.Shutdown();
}

SceneLoaderWrapper.Instance.IsClosingClients = false;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ public static class UnityRelayUtilities
{

public static async
Task<(string ipv4address, ushort port, byte[] allocationIdBytes, byte[] connectionData, byte[] key, string
Task<(string ipv4address, ushort port, Guid allocationId, byte[] allocationIdBytes, byte[] connectionData, byte[] key, string
joinCode)> AllocateRelayServerAndGetJoinCode(int maxConnections, string region = null)
{
Allocation allocation;
Expand All @@ -37,12 +37,12 @@ public static async
throw new Exception($"Creating join code request has failed: \n {exception.Message}");
}

return (allocation.RelayServer.IpV4, (ushort)allocation.RelayServer.Port, allocation.AllocationIdBytes,
return (allocation.RelayServer.IpV4, (ushort)allocation.RelayServer.Port, allocation.AllocationId, allocation.AllocationIdBytes,
allocation.ConnectionData, allocation.Key, joinCode);
}

public static async
Task<(string ipv4address, ushort port, byte[] allocationIdBytes, byte[] connectionData, byte[]
Task<(string ipv4address, ushort port, Guid allocationId, byte[] allocationIdBytes, byte[] connectionData, byte[]
hostConnectionData, byte[] key)> JoinRelayServerFromJoinCode(string joinCode)
{
JoinAllocation allocation;
Expand All @@ -59,7 +59,7 @@ public static async
Debug.Log($"host: {allocation.HostConnectionData[0]} {allocation.HostConnectionData[1]}");
Debug.Log($"client: {allocation.AllocationId}");

return (allocation.RelayServer.IpV4, (ushort)allocation.RelayServer.Port, allocation.AllocationIdBytes,
return (allocation.RelayServer.IpV4, (ushort)allocation.RelayServer.Port, allocation.AllocationId, allocation.AllocationIdBytes,
allocation.ConnectionData, allocation.HostConnectionData, allocation.Key);
}
}
Expand Down