Skip to content

feat: replace guid with auth playerid for session management #488

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 32 commits into from
Mar 14, 2022
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
97c2ee1
Replaced custom guid with playerid for session management
LPLafontaineB Feb 24, 2022
4ce6534
Removed code handling duplicate connections in debug builds
LPLafontaineB Feb 24, 2022
5958c9b
Removed AddHostData method
LPLafontaineB Feb 24, 2022
3d9ebfa
Removed guid from ClientPrefs
LPLafontaineB Feb 24, 2022
62d5ea7
Made ClientPrefs class static
LPLafontaineB Feb 24, 2022
47b02ba
cleaning up
LPLafontaineB Feb 24, 2022
e6bb5d5
Merge develop into feature/replace-guid-with-auth-playerid
netcode-ci-service Mar 8, 2022
020cce1
Merge develop into feature/replace-guid-with-auth-playerid
netcode-ci-service Mar 8, 2022
0d874b5
Merge develop into feature/replace-guid-with-auth-playerid
netcode-ci-service Mar 8, 2022
77b939f
Merge develop into feature/replace-guid-with-auth-playerid
netcode-ci-service Mar 8, 2022
b974e90
Merge develop into feature/replace-guid-with-auth-playerid
netcode-ci-service Mar 8, 2022
2d83fcf
Merge develop into feature/replace-guid-with-auth-playerid
netcode-ci-service Mar 9, 2022
5296213
Merge develop into feature/replace-guid-with-auth-playerid
netcode-ci-service Mar 9, 2022
1babc3f
Merge develop into feature/replace-guid-with-auth-playerid
netcode-ci-service Mar 9, 2022
8975d19
Merge develop into feature/replace-guid-with-auth-playerid
netcode-ci-service Mar 9, 2022
40d2f89
Merge develop into feature/replace-guid-with-auth-playerid
netcode-ci-service Mar 9, 2022
f13fd7a
Merge develop into feature/replace-guid-with-auth-playerid
netcode-ci-service Mar 9, 2022
6f27732
Merge develop into feature/replace-guid-with-auth-playerid
netcode-ci-service Mar 9, 2022
0d34e9c
Revert "Removed guid from ClientPrefs"
LPLafontaineB Mar 9, 2022
4063c42
Merge develop into feature/replace-guid-with-auth-playerid
netcode-ci-service Mar 9, 2022
41790b7
Adding back GUID with IP connections
LPLafontaineB Mar 9, 2022
9008d77
Merge branch 'feature/replace-guid-with-auth-playerid' of https://git…
LPLafontaineB Mar 9, 2022
f479872
Exctracted GetPlayerId to GameNetPortal
LPLafontaineB Mar 10, 2022
d164192
refactored GetPlayerId to use AuthService's playerId when signed in o…
LPLafontaineB Mar 10, 2022
d119ffb
cleanup using directives
LPLafontaineB Mar 10, 2022
788eb23
Merge develop into feature/replace-guid-with-auth-playerid
netcode-ci-service Mar 10, 2022
2973861
reverted unneeded change
LPLafontaineB Mar 11, 2022
346bb7f
Simplified ProfileManager property
LPLafontaineB Mar 11, 2022
d66f779
Removed OnlineMode responsability from GameNetPortal
LPLafontaineB Mar 11, 2022
a44aeaa
Merge branch 'develop' into feature/replace-guid-with-auth-playerid
LPLafontaineB Mar 11, 2022
b525df7
Adding namespace
LPLafontaineB Mar 11, 2022
eabe77c
Merge branch 'develop' into feature/replace-guid-with-auth-playerid
LPLafontaineB Mar 11, 2022
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
24 changes: 3 additions & 21 deletions Assets/BossRoom/Scripts/Shared/ClientPrefs.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,10 @@ namespace Unity.Multiplayer.Samples.BossRoom.Client
/// (This is just a wrapper around the PlayerPrefs system,
/// so that all the calls are in the same place.)
/// </summary>
public class ClientPrefs
public static class ClientPrefs
{
private const float k_DefaultMasterVolume = 0.5f;
private const float k_DefaultMusicVolume = 0.8f;
const float k_DefaultMasterVolume = 0.5f;
const float k_DefaultMusicVolume = 0.8f;

public static float GetMasterVolume()
{
Expand All @@ -32,23 +32,5 @@ public static void SetMusicVolume(float volume)
PlayerPrefs.SetFloat("MusicVolume", volume);
}

/// <summary>
/// Either loads a Guid string from Unity preferences, or creates one and checkpoints it, then returns it.
/// </summary>
/// <returns>The Guid that uniquely identifies this client install, in string form. </returns>
public static string GetGuid()
{
if (PlayerPrefs.HasKey("client_guid"))
{
return PlayerPrefs.GetString("client_guid");
}

var guid = System.Guid.NewGuid();
var guidString = guid.ToString();

PlayerPrefs.SetString("client_guid", guidString);
return guidString;
}

}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
using UnityEngine.SceneManagement;
using Unity.Netcode;
using Unity.Netcode.Transports.UNET;
using Unity.Services.Authentication;

namespace Unity.Multiplayer.Samples.BossRoom.Client
{
Expand Down Expand Up @@ -207,10 +208,9 @@ public async void StartClientUnityRelayModeAsync(string joinCode, Action<string>

private void ConnectClient()
{
var clientGuid = ClientPrefs.GetGuid();
var payload = JsonUtility.ToJson(new ConnectionPayload()
{
clientGUID = clientGuid,
playerId = AuthenticationService.Instance.PlayerId,
clientScene = SceneManager.GetActiveScene().buildIndex,
playerName = m_Portal.PlayerName
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ public enum OnlineMode
[Serializable]
public class ConnectionPayload
{
public string clientGUID;
public string playerId;
public int clientScene = -1;
public string playerName;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
using Unity.Multiplayer.Samples.BossRoom.Client;
using UnityEngine;
using Unity.Netcode;
using Unity.Services.Authentication;
using UnityEngine.SceneManagement;

namespace Unity.Multiplayer.Samples.BossRoom.Server
Expand Down Expand Up @@ -146,7 +147,7 @@ private void ApprovalCheck(byte[] connectionData, ulong clientId, NetworkManager
// Approval check happens for Host too, but obviously we want it to be approved
if (clientId == NetworkManager.Singleton.LocalClientId)
{
SessionManager<SessionPlayerData>.Instance.AddHostData(
SessionManager<SessionPlayerData>.Instance.SetupConnectingPlayerSessionData(clientId, AuthenticationService.Instance.PlayerId,
new SessionPlayerData(clientId, m_Portal.PlayerName, m_Portal.AvatarRegistry.GetRandomAvatar().Guid.ToNetworkGuid(), 0, true));

connectionApprovedCallback(true, null, true, null, null);
Expand Down Expand Up @@ -176,9 +177,9 @@ private void ApprovalCheck(byte[] connectionData, ulong clientId, NetworkManager

int clientScene = connectionPayload.clientScene;

Debug.Log("Host ApprovalCheck: connecting client GUID: " + connectionPayload.clientGUID);
Debug.Log("Host ApprovalCheck: connecting client with player ID: " + connectionPayload.playerId);

gameReturnStatus = SessionManager<SessionPlayerData>.Instance.SetupConnectingPlayerSessionData(clientId, connectionPayload.clientGUID,
gameReturnStatus = SessionManager<SessionPlayerData>.Instance.SetupConnectingPlayerSessionData(clientId, connectionPayload.playerId,
new SessionPlayerData(clientId, connectionPayload.playerName, m_Portal.AvatarRegistry.GetRandomAvatar().Guid.ToNetworkGuid(), 0, true))
? ConnectStatus.Success
: ConnectStatus.LoggedInAgain;
Expand All @@ -187,7 +188,7 @@ private void ApprovalCheck(byte[] connectionData, ulong clientId, NetworkManager
if (gameReturnStatus == ConnectStatus.LoggedInAgain)
{
SessionPlayerData? sessionPlayerData =
SessionManager<SessionPlayerData>.Instance.GetPlayerData(connectionPayload.clientGUID);
SessionManager<SessionPlayerData>.Instance.GetPlayerData(connectionPayload.playerId);

ulong oldClientId = sessionPlayerData?.ClientID ?? 0;
// kicking old client to leave only current
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,11 +25,9 @@ public interface ISessionPlayerData
/// <typeparam name="T"></typeparam>
public class SessionManager<T> where T : struct, ISessionPlayerData
{
const string k_HostGUID = "host_guid";

NetworkManager m_NetworkManager;

protected SessionManager()
SessionManager()
{
m_NetworkManager = NetworkManager.Singleton;
if (m_NetworkManager)
Expand All @@ -38,7 +36,7 @@ protected SessionManager()
}

m_ClientData = new Dictionary<string, T>();
m_ClientIDToGuid = new Dictionary<ulong, string>();
m_ClientIDToPlayerId = new Dictionary<ulong, string>();
}

~SessionManager()
Expand All @@ -51,44 +49,31 @@ protected SessionManager()

public static SessionManager<T> Instance => s_Instance ??= new SessionManager<T>();

private static SessionManager<T> s_Instance;
static SessionManager<T> s_Instance;

/// <summary>
/// Maps a given client guid to the data for a given client player.
/// Maps a given client player id to the data for a given client player.
/// </summary>
private Dictionary<string, T> m_ClientData;
Dictionary<string, T> m_ClientData;

/// <summary>
/// Map to allow us to cheaply map from guid to player data.
/// Map to allow us to cheaply map from player id to player data.
/// </summary>
private Dictionary<ulong, string> m_ClientIDToGuid;

public void AddHostData(T sessionPlayerData)
{
if (sessionPlayerData.ClientID == m_NetworkManager.ServerClientId)
{
m_ClientData.Add(k_HostGUID, sessionPlayerData);
m_ClientIDToGuid.Add(sessionPlayerData.ClientID, k_HostGUID);
}
else
{
Debug.LogError($"Invalid ClientId for host. Got {sessionPlayerData.ClientID}, but should have gotten {m_NetworkManager.ServerClientId}.");
}
}
Dictionary<ulong, string> m_ClientIDToPlayerId;

/// <summary>
/// Handles the case where NetworkManager has told us a client has disconnected. This includes ourselves, if we're the host,
/// and the server is stopped."
/// </summary>
private void OnClientDisconnect(ulong clientId)
void OnClientDisconnect(ulong clientId)
{
if (m_ClientIDToGuid.TryGetValue(clientId, out var guid))
if (m_ClientIDToPlayerId.TryGetValue(clientId, out var playerId))
{
if (GetPlayerData(guid)?.ClientID == clientId)
if (GetPlayerData(playerId)?.ClientID == clientId)
{
var clientData = m_ClientData[guid];
var clientData = m_ClientData[playerId];
clientData.IsConnected = false;
m_ClientData[guid] = clientData;
m_ClientData[playerId] = clientData;
}
}

Expand All @@ -109,50 +94,33 @@ public void OnUserDisconnectRequest()
Clear();
}

private void Clear()
void Clear()
{
//resets all our runtime state.
m_ClientData.Clear();
m_ClientIDToGuid.Clear();
m_ClientIDToPlayerId.Clear();
}

/// <summary>
/// Adds a connecting player's session data if it is a new connection, or updates their session data in case of a reconnection. If the connection is not valid, simply returns false.
/// </summary>
/// <param name="clientId">This is the clientId that Netcode assigned us on login. It does not persist across multiple logins from the same client. </param>
/// <param name="clientGUID">This is the clientGUID that is unique to this client and persists accross multiple logins from the same client</param>
/// <param name="playerId">This is the playerId that is unique to this client and persists across multiple logins from the same client</param>
/// <param name="sessionPlayerData">The player's initial data</param>
/// <returns>True if the player connection is valid (i.e. not a duplicate connection)</returns>
public bool SetupConnectingPlayerSessionData(ulong clientId, string clientGUID, T sessionPlayerData)
public bool SetupConnectingPlayerSessionData(ulong clientId, string playerId, T sessionPlayerData)
{
bool success = true;

//Test for Duplicate Login.
if (m_ClientData.ContainsKey(clientGUID))
if (m_ClientData.ContainsKey(playerId))
{
bool isReconnecting = false;

// If another client is connected with the same clientGUID
if (m_ClientData[clientGUID].IsConnected)
// If another client is connected with the same playerId
if (m_ClientData[playerId].IsConnected)
{
if (Debug.isDebugBuild)
{
Debug.Log($"Client GUID {clientGUID} already exists. Because this is a debug build, we will still accept the connection");

// If debug build, accept connection and manually update clientGUID until we get one that either is not connected or that does not already exist
while (m_ClientData.ContainsKey(clientGUID) && m_ClientData[clientGUID].IsConnected) clientGUID += "_Secondary";

if (m_ClientData.ContainsKey(clientGUID) && !m_ClientData[clientGUID].IsConnected)
{
// In this specific case, if the clients with the same GUID reconnect in a different order than when they originally connected,
// they will swap characters, since their GUIDs are manually modified here at runtime.
isReconnecting = true;
}
}
else
{
success = false;
}
success = false;
}
else
{
Expand All @@ -163,7 +131,7 @@ public bool SetupConnectingPlayerSessionData(ulong clientId, string clientGUID,
if (isReconnecting)
{
// Update player session data
sessionPlayerData = m_ClientData[clientGUID];
sessionPlayerData = m_ClientData[playerId];
sessionPlayerData.ClientID = clientId;
sessionPlayerData.IsConnected = true;
}
Expand All @@ -172,8 +140,8 @@ public bool SetupConnectingPlayerSessionData(ulong clientId, string clientGUID,
//Populate our dictionaries with the SessionPlayerData
if (success)
{
m_ClientIDToGuid[clientId] = clientGUID;
m_ClientData[clientGUID] = sessionPlayerData;
m_ClientIDToPlayerId[clientId] = playerId;
m_ClientData[playerId] = sessionPlayerData;
}

return success;
Expand All @@ -186,30 +154,30 @@ public bool SetupConnectingPlayerSessionData(ulong clientId, string clientGUID,
/// <returns>Player data struct matching the given ID</returns>
public T? GetPlayerData(ulong clientId)
{
//First see if we have a guid matching the clientID given.
//First see if we have a playerId matching the clientID given.

if (m_ClientIDToGuid.TryGetValue(clientId, out string clientGUID))
if (m_ClientIDToPlayerId.TryGetValue(clientId, out string playerId))
{
return GetPlayerData(clientGUID);
return GetPlayerData(playerId);
}

Debug.LogError($"No client guid found mapped to the given client ID: {clientId}");
Debug.LogError($"No client player ID found mapped to the given client ID: {clientId}");
return null;
}

/// <summary>
///
/// </summary>
/// <param name="clientGUID"> guid of the client whose data is requested</param>
/// <param name="playerId"> Player ID of the client whose data is requested</param>
/// <returns>Player data struct matching the given ID</returns>
public T? GetPlayerData(string clientGUID)
public T? GetPlayerData(string playerId)
{
if (m_ClientData.TryGetValue(clientGUID, out T data))
if (m_ClientData.TryGetValue(playerId, out T data))
{
return data;
}

Debug.LogError($"No PlayerData of matching guid found: {clientGUID}");
Debug.LogError($"No PlayerData of matching player ID found: {playerId}");
return null;
}

Expand All @@ -220,20 +188,20 @@ public bool SetupConnectingPlayerSessionData(ulong clientId, string clientGUID,
/// <param name="sessionPlayerData"> new data to overwrite the old </param>
public void SetPlayerData(ulong clientId, T sessionPlayerData)
{
if (m_ClientIDToGuid.TryGetValue(clientId, out string clientGUID))
if (m_ClientIDToPlayerId.TryGetValue(clientId, out string playerId))
{
m_ClientData[clientGUID] = sessionPlayerData;
m_ClientData[playerId] = sessionPlayerData;
}
else
{
Debug.LogError($"No client guid found mapped to the given client ID: {clientId}");
Debug.LogError($"No client player ID found mapped to the given client ID: {clientId}");
}
}

/// <summary>
/// Called after the server is created- This is primarily meant for the host server to clean up or handle/set state as its starting up
/// </summary>
private void ServerStartedHandler()
void ServerStartedHandler()
{
if (m_NetworkManager.IsServer)
{
Expand All @@ -254,14 +222,14 @@ public void OnSessionEnded()
{
ClearDisconnectedPlayersData();
List<ulong> connectedClientIds = new List<ulong>(m_NetworkManager.ConnectedClientsIds);
foreach (var id in m_ClientIDToGuid.Keys)
foreach (var id in m_ClientIDToPlayerId.Keys)
{
if (connectedClientIds.Contains(id))
{
string guid = m_ClientIDToGuid[id];
T sessionPlayerData = m_ClientData[guid];
string playerId = m_ClientIDToPlayerId[id];
T sessionPlayerData = m_ClientData[playerId];
sessionPlayerData.Reinitialize();
m_ClientData[guid] = sessionPlayerData;
m_ClientData[playerId] = sessionPlayerData;
}
}
}
Expand All @@ -270,30 +238,30 @@ void ClearDisconnectedPlayersData()
{
List<ulong> idsToClear = new List<ulong>();
List<ulong> connectedClientIds = new List<ulong>(m_NetworkManager.ConnectedClientsIds);
foreach (var id in m_ClientIDToGuid.Keys)
foreach (var id in m_ClientIDToPlayerId.Keys)
{
if (!connectedClientIds.Contains(id))
{
idsToClear.Add(id);
}
else
{
string guid = m_ClientIDToGuid[id];
T sessionPlayerData = m_ClientData[guid];
string playerId = m_ClientIDToPlayerId[id];
T sessionPlayerData = m_ClientData[playerId];
sessionPlayerData.Reinitialize();
m_ClientData[guid] = sessionPlayerData;
m_ClientData[playerId] = sessionPlayerData;
}
}

foreach (var id in idsToClear)
{
string guid = m_ClientIDToGuid[id];
if (GetPlayerData(guid)?.ClientID == id)
string playerId = m_ClientIDToPlayerId[id];
if (GetPlayerData(playerId)?.ClientID == id)
{
m_ClientData.Remove(guid);
m_ClientData.Remove(playerId);
}

m_ClientIDToGuid.Remove(id);
m_ClientIDToPlayerId.Remove(id);
}
}
}
Expand Down