Skip to content

feat: popup panel for connection status messages (#494) #506

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 1 commit into from
Mar 4, 2022
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
508 changes: 503 additions & 5 deletions Assets/BossRoom/Prefabs/UI/SettingsPanelCanvas.prefab

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions Assets/BossRoom/Scenes/Startup.unity
Git LFS file not shown
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ void OnAuthSignIn()

void OnSignInFailed()
{
Debug.LogError("For some reason we can't authenticate the user anonymously - that typically means that project is not properly set up with Unity services.");
PopupPanel.ShowPopupPanel("Authentication Error", "For some reason we can't authenticate the user anonymously - that typically means that project is not properly set up with Unity services.");
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
using System;
using Unity.Multiplayer.Samples.BossRoom.Shared.Infrastructure;
using UnityEngine;

namespace Unity.Multiplayer.Samples.BossRoom.Visual
{
/// <summary>
/// Subscribes to connection status messages to display them through the popup panel.
/// </summary>
public class ConnectionStatusMessageUIManager : MonoBehaviour
{
IDisposable m_Subscriptions;

[Inject]
void InjectDependencies(ISubscriber<ConnectStatus> connectStatusSub)
{
m_Subscriptions = connectStatusSub.Subscribe(OnConnectStatus);
}

void Awake()
{
DontDestroyOnLoad(gameObject);
}

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

void OnConnectStatus(ConnectStatus status)
{
switch (status)
{
case ConnectStatus.Undefined:
case ConnectStatus.UserRequestedDisconnect:
break;
case ConnectStatus.ServerFull:
PopupPanel.ShowPopupPanel("Connection Failed", "The Host is full and cannot accept any additional connections.");
break;
case ConnectStatus.Success:
break;
case ConnectStatus.LoggedInAgain:
PopupPanel.ShowPopupPanel("Connection Failed", "You have logged in elsewhere using the same account.");
break;
case ConnectStatus.GenericDisconnect:
PopupPanel.ShowPopupPanel("Disconnected From Host", "The connection to the host was lost");
break;
default:
Debug.LogWarning($"New ConnectStatus {status} has been added, but no connect message defined for it.");
break;
}
}
}
}

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

51 changes: 1 addition & 50 deletions Assets/BossRoom/Scripts/Client/UI/Lobby/LobbyUIMediator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -46,19 +46,13 @@ ClientGameNetPortal clientGameNetPortal
RegenerateName();

m_ClientNetPortal.NetworkTimedOut += OnNetworkTimeout;
m_ClientNetPortal.ConnectFinished += OnConnectFinished;

//any disconnect reason set? Show it to the user here.
ConnectStatusToMessage(m_ClientNetPortal.DisconnectReason.Reason, false);
m_ClientNetPortal.DisconnectReason.Clear();
}

void OnDestroy()
{
if (m_ClientNetPortal != null)
{
m_ClientNetPortal.NetworkTimedOut -= OnNetworkTimeout;
m_ClientNetPortal.ConnectFinished -= OnConnectFinished;
}
}

Expand Down Expand Up @@ -157,6 +151,7 @@ void OnJoinedLobby(Lobby remoteLobby)

void OnRelayJoinFailed(string message)
{
PopupPanel.ShowPopupPanel("Relay join failed", message);
Debug.Log($"Relay join failed: {message}");
//leave the lobby if relay failed for some reason
m_LobbyServiceFacade.EndTracking();
Expand Down Expand Up @@ -217,15 +212,6 @@ void UnblockUIAfterLoadingIsComplete()
}
}

/// <summary>
/// Callback when the server sends us back a connection finished event.
/// </summary>
/// <param name="status"></param>
void OnConnectFinished(ConnectStatus status)
{
ConnectStatusToMessage(status, true);
}

/// <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
Expand All @@ -234,40 +220,5 @@ void OnNetworkTimeout()
{
UnblockUIAfterLoadingIsComplete();
}

/// <summary>
/// Takes a ConnectStatus and shows an appropriate message to the user. This can be called on: (1) successful connect,
/// (2) failed connect, (3) disconnect.
/// </summary>
/// <param name="connecting">pass true if this is being called in response to a connect finishing.</param>
void ConnectStatusToMessage(ConnectStatus status, bool connecting)
{
switch (status)
{
case ConnectStatus.Undefined:
case ConnectStatus.UserRequestedDisconnect:
break;
case ConnectStatus.ServerFull:
Debug.Log("Connection Failed, The Host is full and cannot accept any additional connections");
break;
case ConnectStatus.Success:
if (connecting)
{
Debug.Log("Success!, Joining Now");
}
break;
case ConnectStatus.LoggedInAgain:
Debug.Log("Connection Failed, You have logged in elsewhere using the same account");
break;
case ConnectStatus.GenericDisconnect:
var title = connecting ? "Connection Failed" : "Disconnected From Host";
var text = connecting ? "Something went wrong" : "The connection to the host was lost";
Debug.Log($"{title}, {text}");
break;
default:
Debug.LogWarning($"New ConnectStatus {status} has been added, but no connect message defined for it.");
break;
}
}
}
}
85 changes: 85 additions & 0 deletions Assets/BossRoom/Scripts/Client/UI/PopupPanel.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
using System;
using UnityEngine;
using TMPro;

namespace Unity.Multiplayer.Samples.BossRoom.Visual
{
/// <summary>
/// Simple popup panel to display information to players.
/// </summary>
public class PopupPanel : MonoBehaviour
{
[SerializeField]
TextMeshProUGUI m_TitleText;
[SerializeField]
TextMeshProUGUI m_MainText;

bool m_IsPopupShown;

static PopupPanel s_Instance;

void Awake()
{
if (s_Instance != null) throw new Exception("Invalid state, instance is not null");
s_Instance = this;
ResetState();
}

void OnDestroy()
{
s_Instance = null;
}

public void OnConfirmClick()
{
ResetState();
}

/// <summary>
/// Helper method to help us reset all state for the popup.
/// </summary>
void ResetState()
{
m_TitleText.text = string.Empty;
m_MainText.text = string.Empty;
gameObject.SetActive(false);
m_IsPopupShown = false;
}

/// <summary>
/// Sets the panel to match the given specifications to notify the player. If display image is set to true, it will display
/// </summary>
/// <param name="titleText">The title text at the top of the panel</param>
/// <param name="mainText"> The text just under the title- the main body of text</param>
public static void ShowPopupPanel(string titleText, string mainText)
{
if (s_Instance != null)
{
s_Instance.SetupPopupPanel(titleText, mainText);
}
else
{
Debug.LogError($"No PopupPanel instance found. Cannot display message: {titleText}: {mainText}");
}
}

void SetupPopupPanel(string titleText, string mainText)
{
if (m_IsPopupShown)
{
Debug.Log("Trying to show popup, but another popup is already being shown.");
Debug.Log($"{titleText}. {mainText}");
}
else
{
ResetState();

m_TitleText.text = titleText;
m_MainText.text = mainText;

gameObject.SetActive(true);
m_IsPopupShown = true;
}
}
}
}
11 changes: 11 additions & 0 deletions Assets/BossRoom/Scripts/Client/UI/PopupPanel.cs.meta

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions Assets/BossRoom/Scripts/Shared/ApplicationController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,9 @@ private void Awake()
//this message channel is essential and persists for the lifetime of the lobby and relay services
scope.BindMessageChannel<UnityServiceErrorMessage>();

//this message channel is essential and persists for the lifetime of the lobby and relay services
scope.BindMessageChannel<ConnectStatus>();

//buffered message channels hold the latest received message in buffer and pass to any new subscribers
scope.BindBufferedMessageChannel<LobbyListFetchedMessage>();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,27 +21,27 @@ public class ClientGameNetPortal : MonoBehaviour
/// <summary>
/// If a disconnect occurred this will be populated with any contextual information that was available to explain why.
/// </summary>
public DisconnectReason DisconnectReason { get; private set; } = new DisconnectReason();
public DisconnectReason DisconnectReason { get; } = new DisconnectReason();

/// <summary>
/// Time in seconds before the client considers a lack of server response a timeout
/// </summary>
private const int k_TimeoutDuration = 10;

public event Action<ConnectStatus> ConnectFinished;

/// <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 LobbyServiceFacade m_LobbyServiceFacade;
IPublisher<ConnectStatus> m_ConnectStatusPub;

[Inject]
private void InjectDependencies(LobbyServiceFacade lobbyServiceFacade)
private void InjectDependencies(LobbyServiceFacade lobbyServiceFacade, IPublisher<ConnectStatus> connectStatusPub)
{
m_LobbyServiceFacade = lobbyServiceFacade;
m_ConnectStatusPub = connectStatusPub;
}

private void Awake()
Expand Down Expand Up @@ -107,8 +107,10 @@ public void OnConnectFinished(ConnectStatus status)
//this indicates a game level failure, rather than a network failure. See note in ServerGameNetPortal.
DisconnectReason.SetDisconnectReason(status);
}

ConnectFinished?.Invoke(status);
else
{
m_ConnectStatusPub.Publish(status);
}
}

private void OnDisconnectReasonReceived(ConnectStatus status)
Expand All @@ -133,14 +135,15 @@ private void OnDisconnectOrTimeout(ulong clientID)
//disconnect that happened for some other reason than user UI interaction--should display a message.
DisconnectReason.SetDisconnectReason(ConnectStatus.GenericDisconnect);
}

SceneManager.LoadScene("MainMenu");
}
else if (DisconnectReason.Reason == ConnectStatus.GenericDisconnect || DisconnectReason.Reason == ConnectStatus.Undefined)
{
// only call this if generic disconnect. Else if there's a reason, there's already code handling that popup
NetworkTimedOut?.Invoke();
}
m_ConnectStatusPub.Publish(DisconnectReason.Reason);
DisconnectReason.Clear();
}
}

Expand Down