Add persistent per-install player identity
Introduce PersistentPlayerId: a stable id that survives an app restart and is unique per install (built on the UGS install-path-namespaced anonymous PlayerId, with a local PlayerPrefs GUID fallback for loopback). Clones on the same machine stay distinct. Each client reports its id to the server on connect via a new Match_Identity named message (mirroring Match_ReportHit, so no ConnectionApproval timing risk); the host records its own directly. The server keeps an ephemeral clientId -> persistent id map, exposed via PersistentIdOf(clientId) as the foundation for later reconnect recognition. Map entries are cleared on disconnect and net stop. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
1 parent
17bb37cb92
commit
a59a5e53ab
3 files changed
+123
No files matched your search
@@ -0,0 +1,58 @@
|
||||
using System;
|
||||
using Unity.Services.Authentication;
|
||||
using UnityEngine;
|
||||
|
||||
/// <summary>
|
||||
/// A stable, per-install unique player id that survives application restarts, so the server can recognise a
|
||||
/// returning client across sessions (the NGO clientId is ephemeral and reused).
|
||||
///
|
||||
/// Primary source is the UGS anonymous <see cref="AuthenticationService"/> PlayerId, which is already cached
|
||||
/// per machine AND namespaced per install via the auth profile (see OnlineSessionManager.ProfileForThisInstall),
|
||||
/// so it is restart-stable and stays distinct even for same-machine clone tests. When there was no UGS sign-in
|
||||
/// (pure loopback / offline play) it falls back to a locally generated GUID persisted in PlayerPrefs.
|
||||
/// </summary>
|
||||
public static class PersistentPlayerId
|
||||
{
|
||||
private const string PrefKey = "chameleon.persistentPlayerId";
|
||||
|
||||
private static string _ugsId; // authoritative once signed in; cached permanently
|
||||
private static string _localFallback; // loopback/offline only
|
||||
|
||||
/// <summary>The persistent id for THIS install. Stable across restarts, never null/empty. Prefers the
|
||||
/// signed-in UGS id (the send path runs after sign-in, so online clients always report that); only pure
|
||||
/// loopback play resolves the local fallback.</summary>
|
||||
public static string Value
|
||||
{
|
||||
get
|
||||
{
|
||||
if (!string.IsNullOrEmpty(_ugsId)) return _ugsId;
|
||||
|
||||
// AuthenticationService.Instance throws if UGS was never initialised (loopback) - guard it.
|
||||
try
|
||||
{
|
||||
var auth = AuthenticationService.Instance;
|
||||
if (auth != null && auth.IsSignedIn && !string.IsNullOrEmpty(auth.PlayerId))
|
||||
return _ugsId = auth.PlayerId;
|
||||
}
|
||||
catch (Exception) { /* services not initialised - use the local fallback */ }
|
||||
|
||||
return LocalFallback();
|
||||
}
|
||||
}
|
||||
|
||||
// NOT cached into _ugsId: a later signed-in read must be able to upgrade to the authoritative UGS id.
|
||||
// The fallback itself is restart-stable (PlayerPrefs), which is all offline play needs.
|
||||
private static string LocalFallback()
|
||||
{
|
||||
if (!string.IsNullOrEmpty(_localFallback)) return _localFallback;
|
||||
|
||||
_localFallback = PlayerPrefs.GetString(PrefKey, "");
|
||||
if (string.IsNullOrEmpty(_localFallback))
|
||||
{
|
||||
_localFallback = Guid.NewGuid().ToString("N");
|
||||
PlayerPrefs.SetString(PrefKey, _localFallback);
|
||||
PlayerPrefs.Save();
|
||||
}
|
||||
return _localFallback;
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user