diff --git a/Runtime/Client/LootLockerHTTPClient.cs b/Runtime/Client/LootLockerHTTPClient.cs index 0f0c5f73..db67275b 100644 --- a/Runtime/Client/LootLockerHTTPClient.cs +++ b/Runtime/Client/LootLockerHTTPClient.cs @@ -739,7 +739,7 @@ private void CallListenersAndMarkDone(LootLockerHTTPExecutionQueueItem execution private IEnumerator RefreshSession(string refreshForPlayerUlid, string forExecutionItemId, Action onSessionRefreshedCallback) { - var playerData = LootLockerStateData.GetStateForPlayerOrDefaultStateOrEmpty(refreshForPlayerUlid); + var playerData = LootLockerStateData.GetPlayerDataForPlayerWithUlidWithoutChangingState(refreshForPlayerUlid); if (playerData == null) { LootLockerLogger.Log($"No stored player data for player with ulid {refreshForPlayerUlid}. Can't refresh session.", LootLockerLogger.LogLevel.Warning); @@ -863,6 +863,12 @@ private void HandleSessionRefreshResult(LootLockerResponse newSessionResponse, s LootLockerLogger.Log($"Session refresh callback ulid {forPlayerWithUlid} does not match the execution item ulid {executionItem.RequestData.ForPlayerWithUlid}. Ignoring.", LootLockerLogger.LogLevel.Error); return; } + if (newSessionResponse == null || !newSessionResponse.success) + { + LootLockerLogger.Log($"Session refresh failed for player with ulid {forPlayerWithUlid}.", LootLockerLogger.LogLevel.Error); + return; + } + var playerData = LootLockerStateData.GetStateForPlayerOrDefaultStateOrEmpty(executionItem.RequestData.ForPlayerWithUlid); string tokenBeforeRefresh = executionItem.RequestData.ExtraHeaders.TryGetValue("x-session-token", out var existingToken) ? existingToken : ""; string tokenAfterRefresh = playerData?.SessionToken; @@ -923,19 +929,19 @@ private static bool IsAuthorizedAdminRequest(LootLockerHTTPExecutionQueueItem re private static bool CanRefreshUsingRefreshToken(LootLockerHTTPRequestData cachedRequest) { - var playerData = LootLockerStateData.GetStateForPlayerOrDefaultStateOrEmpty(cachedRequest.ForPlayerWithUlid); + var playerData = LootLockerStateData.GetPlayerDataForPlayerWithUlidWithoutChangingState(cachedRequest.ForPlayerWithUlid); if (!LootLockerAuthPlatformSettings.PlatformsWithRefreshTokens.Contains(playerData == null ? LL_AuthPlatforms.None : playerData.CurrentPlatform.Platform)) { return false; } // The failed request isn't a refresh session request but we have a refresh token stored, so try to refresh the session automatically before failing string json = cachedRequest.Content.dataType == LootLockerHTTPRequestDataType.JSON ? ((LootLockerJsonBodyRequestContent)cachedRequest.Content).jsonBody : null; - return (string.IsNullOrEmpty(json) || !json.Contains("refresh_token")) && !string.IsNullOrEmpty(LootLockerStateData.GetStateForPlayerOrDefaultStateOrEmpty(cachedRequest.ForPlayerWithUlid)?.RefreshToken); + return (string.IsNullOrEmpty(json) || !json.Contains("refresh_token")) && !string.IsNullOrEmpty(playerData?.RefreshToken); } private static bool CanStartNewSessionUsingCachedAuthData(string forPlayerWithUlid) { - var playerData = LootLockerStateData.GetStateForPlayerOrDefaultStateOrEmpty(forPlayerWithUlid); + var playerData = LootLockerStateData.GetPlayerDataForPlayerWithUlidWithoutChangingState(forPlayerWithUlid); if (playerData == null) { return false; diff --git a/Runtime/Client/LootLockerPresenceClient.cs b/Runtime/Client/LootLockerPresenceClient.cs index 49c8e064..6ec7abb8 100644 --- a/Runtime/Client/LootLockerPresenceClient.cs +++ b/Runtime/Client/LootLockerPresenceClient.cs @@ -25,7 +25,9 @@ public enum LootLockerPresenceConnectionState Authenticating, Active, Reconnecting, - Failed + Failed, + Destroying, + Destroyed } #endregion @@ -202,8 +204,6 @@ public class LootLockerPresenceClient : MonoBehaviour, IDisposable private Coroutine pingCoroutine; private Coroutine statusUpdateCoroutine; private Coroutine webSocketListenerCoroutine; - private bool isDestroying = false; - private bool isDisposed = false; private bool isClientInitiatedDisconnect = false; // Track if disconnect is expected (due to session end) private LootLockerPresenceCallback pendingConnectionCallback; // Store callback until authentication completes @@ -254,7 +254,13 @@ public class LootLockerPresenceClient : MonoBehaviour, IDisposable /// /// Get connection statistics including latency to LootLocker /// - public LootLockerPresenceConnectionStats ConnectionStats => connectionStats; + public LootLockerPresenceConnectionStats ConnectionStats { + get { + connectionStats.connectionState = connectionState; + return connectionStats; + } + set { connectionStats = value; } + } #endregion @@ -271,7 +277,6 @@ private void Update() private void OnDestroy() { - isDestroying = true; Dispose(); } @@ -281,9 +286,10 @@ private void OnDestroy() /// public void Dispose() { - if (isDisposed) return; - - isDisposed = true; + if (connectionState == LootLockerPresenceConnectionState.Destroying || connectionState == LootLockerPresenceConnectionState.Destroyed) return; + + ChangeConnectionState(LootLockerPresenceConnectionState.Destroying); + shouldReconnect = false; StopCoroutines(); @@ -296,7 +302,7 @@ public void Dispose() pendingPingTimestamps.Clear(); recentLatencies.Clear(); - ChangeConnectionState(LootLockerPresenceConnectionState.Disconnected); + ChangeConnectionState(LootLockerPresenceConnectionState.Destroyed); } /// @@ -383,9 +389,10 @@ internal void Initialize(string playerUlid, string sessionToken) /// internal void Connect(LootLockerPresenceCallback onComplete = null) { - if (isDisposed) + if (connectionState == LootLockerPresenceConnectionState.Destroying || + connectionState == LootLockerPresenceConnectionState.Destroyed) { - onComplete?.Invoke(false, "Client has been disposed"); + onComplete?.Invoke(false, "Client has been destroyed"); return; } @@ -415,17 +422,11 @@ internal void Connect(LootLockerPresenceCallback onComplete = null) internal void Disconnect(LootLockerPresenceCallback onComplete = null) { // Prevent multiple disconnect attempts - if (isDestroying || isDisposed) - { - onComplete?.Invoke(true, null); - return; - } - - // Check if already disconnected - if (connectionState == LootLockerPresenceConnectionState.Disconnected || + if (connectionState == LootLockerPresenceConnectionState.Destroying || + connectionState == LootLockerPresenceConnectionState.Destroyed || + connectionState == LootLockerPresenceConnectionState.Disconnected || connectionState == LootLockerPresenceConnectionState.Failed) { - LootLockerLogger.Log($"Presence client already in disconnected state: {connectionState}", LootLockerLogger.LogLevel.Debug); onComplete?.Invoke(true, null); return; } @@ -537,9 +538,10 @@ internal void SendPing(LootLockerPresenceCallback onComplete = null) private IEnumerator ConnectCoroutine() { - if (isDestroying || isDisposed) + if (connectionState == LootLockerPresenceConnectionState.Destroying || + connectionState == LootLockerPresenceConnectionState.Destroyed) { - HandleConnectionError("Presence client is destroying or disposed"); + HandleConnectionError("Presence client is destroyed"); yield break; } if (string.IsNullOrEmpty(sessionToken)) @@ -646,7 +648,8 @@ private void HandleAuthenticationError(string errorMessage) private IEnumerator DisconnectCoroutine(LootLockerPresenceCallback onComplete = null) { // Don't attempt disconnect if already destroyed - if (isDestroying || isDisposed) + if (connectionState == LootLockerPresenceConnectionState.Destroying || + connectionState == LootLockerPresenceConnectionState.Destroyed) { onComplete?.Invoke(true, null); yield break; @@ -873,9 +876,9 @@ private IEnumerator ListenForMessagesCoroutine() var receiveTask = webSocket.ReceiveAsync(new ArraySegment(buffer), cancellationTokenSource.Token); - yield return new WaitUntil(() => receiveTask.IsCompleted || receiveTask.IsFaulted || isDestroying || isDisposed); + yield return new WaitUntil(() => receiveTask.IsCompleted || receiveTask.IsFaulted || connectionState == LootLockerPresenceConnectionState.Destroying || connectionState == LootLockerPresenceConnectionState.Destroyed); - if(isDestroying || isDisposed) + if(connectionState == LootLockerPresenceConnectionState.Destroying || connectionState == LootLockerPresenceConnectionState.Destroyed) { yield break; } @@ -1084,15 +1087,7 @@ private void ChangeConnectionState(LootLockerPresenceConnectionState newState, s // Update connection stats with new state connectionStats.connectionState = newState; - LootLockerLogger.Log($"Presence connection state changed: {previousState} -> {newState}", LootLockerLogger.LogLevel.Debug); - - // Stop ping routine if we're no longer active - if (newState != LootLockerPresenceConnectionState.Active && pingCoroutine != null) - { - LootLockerLogger.Log("Stopping ping routine due to connection state change", LootLockerLogger.LogLevel.Debug); - StopCoroutine(pingCoroutine); - pingCoroutine = null; - } + LootLockerLogger.Log($"Presence state changed from {previousState} to {newState} for player {playerUlid}", LootLockerLogger.LogLevel.Debug); // Then notify external systems via the unified event system LootLockerEventSystem.TriggerPresenceConnectionStateChanged(playerUlid, previousState, newState, error); @@ -1102,18 +1097,16 @@ private void ChangeConnectionState(LootLockerPresenceConnectionState newState, s private IEnumerator PingCoroutine() { - while (IsConnectedAndAuthenticated && !isDestroying) + while (IsConnectedAndAuthenticated) { SendPing(); yield return new WaitForSeconds(PING_INTERVAL); } - - LootLockerLogger.Log($"Ping routine ended. Connected: {IsConnectedAndAuthenticated}, Destroying: {isDestroying}", LootLockerLogger.LogLevel.Debug); } private IEnumerator ScheduleReconnectCoroutine(float customDelay = -1f) { - if (!shouldReconnect || isDestroying || reconnectAttempts >= MAX_RECONNECT_ATTEMPTS) + if (!shouldReconnect || reconnectAttempts >= MAX_RECONNECT_ATTEMPTS) { yield break; } @@ -1121,10 +1114,11 @@ private IEnumerator ScheduleReconnectCoroutine(float customDelay = -1f) reconnectAttempts++; float delayToUse = customDelay > 0 ? customDelay : RECONNECT_DELAY; LootLockerLogger.Log($"Scheduling Presence reconnect attempt {reconnectAttempts}/{MAX_RECONNECT_ATTEMPTS} in {delayToUse} seconds", LootLockerLogger.LogLevel.Debug); + ChangeConnectionState(LootLockerPresenceConnectionState.Reconnecting); yield return new WaitForSeconds(delayToUse); - if (shouldReconnect && !isDestroying) + if (shouldReconnect && connectionState == LootLockerPresenceConnectionState.Reconnecting) { StartCoroutine(ConnectCoroutine()); } diff --git a/Runtime/Client/LootLockerPresenceManager.cs b/Runtime/Client/LootLockerPresenceManager.cs index bc520f13..e5685253 100644 --- a/Runtime/Client/LootLockerPresenceManager.cs +++ b/Runtime/Client/LootLockerPresenceManager.cs @@ -131,9 +131,14 @@ public static LootLockerPresenceManager Get() void ILootLockerService.Initialize() { if (IsInitialized) return; + + #if UNITY_EDITOR + _isEnabled = LootLockerConfig.current.enablePresence && LootLockerConfig.current.enablePresenceInEditor; + #else _isEnabled = LootLockerConfig.current.enablePresence; - _autoConnectEnabled = LootLockerConfig.current.enablePresenceAutoConnect; - _autoDisconnectOnFocusChange = LootLockerConfig.current.enablePresenceAutoDisconnectOnFocusChange; + #endif + _autoConnectEnabled = LootLockerConfig.current.enablePresenceAutoConnect; + _autoDisconnectOnFocusChange = LootLockerConfig.current.enablePresenceAutoDisconnectOnFocusChange; IsInitialized = true; } @@ -880,7 +885,9 @@ private void _DisconnectPresenceForUlid(string playerUlid, LootLockerPresenceCal // Check connection state to prevent multiple disconnect attempts var connectionState = client.ConnectionState; if (connectionState == LootLockerPresenceConnectionState.Disconnected || - connectionState == LootLockerPresenceConnectionState.Failed) + connectionState == LootLockerPresenceConnectionState.Failed || + connectionState == LootLockerPresenceConnectionState.Destroying || + connectionState == LootLockerPresenceConnectionState.Destroyed) { alreadyDisconnectedOrFailed = true; } diff --git a/Runtime/Editor/ProjectSettings.cs b/Runtime/Editor/ProjectSettings.cs index 19c40ad8..e5ed6319 100644 --- a/Runtime/Editor/ProjectSettings.cs +++ b/Runtime/Editor/ProjectSettings.cs @@ -227,6 +227,16 @@ private void DrawPresenceSettings() } EditorGUILayout.Space(); + + // Enable presence in editor toggle + EditorGUI.BeginChangeCheck(); + EditorGUILayout.PropertyField(m_CustomSettings.FindProperty("enablePresenceInEditor"), new GUIContent("Enable Presence in Editor")); + if (EditorGUI.EndChangeCheck()) + { + gameSettings.enablePresenceInEditor = m_CustomSettings.FindProperty("enablePresenceInEditor").boolValue; + } + + EditorGUILayout.Space(); } EditorGUILayout.Space(); diff --git a/Runtime/Game/LootLockerSDKManager.cs b/Runtime/Game/LootLockerSDKManager.cs index 1cdd6bbe..a8bd633c 100644 --- a/Runtime/Game/LootLockerSDKManager.cs +++ b/Runtime/Game/LootLockerSDKManager.cs @@ -74,7 +74,11 @@ static bool LoadConfig() /// True if a token is found, false otherwise. private static bool CheckActiveSession(string forPlayerWithUlid = null) { - var playerData = LootLockerStateData.GetStateForPlayerOrDefaultStateOrEmpty(forPlayerWithUlid); + if(string.IsNullOrEmpty(forPlayerWithUlid)) + { + forPlayerWithUlid = GetDefaultPlayerUlid(); + } + var playerData = LootLockerStateData.GetPlayerDataForPlayerWithUlidWithoutChangingState(forPlayerWithUlid); return !string.IsNullOrEmpty(playerData?.SessionToken); } @@ -236,7 +240,7 @@ public static bool SetDefaultPlayerUlid(string playerUlid) /// The player state for the specified player, or the default player state if the supplied ULID is empty or could not be found, or an empty state if none of the previous are valid. public static LootLockerPlayerData GetSavedStateOrDefaultOrEmptyForPlayer(string playerUlid) { - return LootLockerStateData.GetStateForPlayerOrDefaultStateOrEmpty(playerUlid); + return LootLockerStateData.GetPlayerDataForPlayerWithUlidWithoutChangingState(playerUlid) ?? new LootLockerPlayerData(); } /// @@ -291,7 +295,7 @@ public static void VerifyID(string deviceId, Action on return; } - var playerData = LootLockerStateData.GetStateForPlayerOrDefaultStateOrEmpty(forPlayerWithUlid); + var playerData = LootLockerStateData.GetPlayerDataForPlayerWithUlidWithoutChangingState(forPlayerWithUlid); if (playerData == null || !playerData.Identifier.Equals(deviceId)) { onComplete?.Invoke(LootLockerResponseFactory.ClientError($"The provided deviceId did not match the identifier on player with ulid {forPlayerWithUlid}", forPlayerWithUlid)); @@ -1014,7 +1018,7 @@ public static void RefreshGoogleSession(string refresh_token, Action(playerData?.ULID)); @@ -1026,7 +1030,7 @@ public static void RefreshGoogleSession(string refresh_token, Action(null)); return; } - var playerData = LootLockerStateData.GetStateForPlayerOrDefaultStateOrEmpty(forPlayerWithUlid); + var playerData = LootLockerStateData.GetPlayerDataForPlayerWithUlidWithoutChangingState(forPlayerWithUlid); if (string.IsNullOrEmpty(playerData?.RefreshToken)) { onComplete?.Invoke(LootLockerResponseFactory.TokenExpiredError(playerData?.ULID)); @@ -1277,7 +1281,7 @@ public static void RefreshAppleSession(string refresh_token, Action(playerData?.ULID)); @@ -1289,7 +1293,7 @@ public static void RefreshAppleSession(string refresh_token, Action(playerData?.ULID)); @@ -1407,7 +1411,7 @@ public static void RefreshAppleGameCenterSession(Action(playerData?.ULID)); @@ -1538,7 +1542,7 @@ public static void RefreshEpicSession(string refresh_token, Action(playerData?.ULID)); @@ -1671,7 +1675,7 @@ public static void RefreshMetaSession(string refresh_token, ActionOptional : Execute the request for the specified player. If not supplied, the default player will be used. public static void RefreshDiscordSession(Action onComplete, string forPlayerWithUlid = null, LootLockerSessionOptionals Optionals = null) { - var playerData = LootLockerStateData.GetStateForPlayerOrDefaultStateOrEmpty(forPlayerWithUlid); + var playerData = LootLockerStateData.GetPlayerDataForPlayerWithUlidWithoutChangingState(forPlayerWithUlid); if (string.IsNullOrEmpty(playerData?.RefreshToken)) { onComplete?.Invoke(LootLockerResponseFactory.TokenExpiredError(playerData?.ULID)); @@ -1775,7 +1779,7 @@ public static void RefreshDiscordSession(Action(playerData?.ULID)); @@ -1813,7 +1817,7 @@ public static void RefreshDiscordSession(string refresh_token, Action("No valid session token found for source player", FromPlayerWithUlid)); return; } - var toPlayer = LootLockerStateData.GetStateForPlayerOrDefaultStateOrEmpty(ToPlayerWithUlid); + var toPlayer = LootLockerStateData.GetPlayerDataForPlayerWithUlidWithoutChangingState(ToPlayerWithUlid); if (string.IsNullOrEmpty(toPlayer?.SessionToken)) { onComplete?.Invoke(LootLockerResponseFactory.ClientError("No valid session token found for target player", ToPlayerWithUlid)); return; } + if(fromPlayer.Equals(toPlayer)) + { + onComplete?.Invoke(LootLockerResponseFactory.ClientError("Source player and target player can not be the same", FromPlayerWithUlid)); + return; + } + if (ProvidersToTransfer.Count == 0) { onComplete?.Invoke(LootLockerResponseFactory.ClientError("No providers submitted", FromPlayerWithUlid)); @@ -2502,7 +2512,7 @@ public static void RefreshRemoteSession(string refreshToken, Action(playerData?.ULID)); @@ -2700,7 +2710,7 @@ public static void CheckWhiteLabelSession(Action onComplete, string forPla return; } - var playerData = LootLockerStateData.GetStateForPlayerOrDefaultStateOrEmpty(forPlayerWithUlid); + var playerData = LootLockerStateData.GetPlayerDataForPlayerWithUlidWithoutChangingState(forPlayerWithUlid); string existingSessionEmail = playerData?.WhiteLabelEmail; string existingSessionToken = playerData?.WhiteLabelToken; if (string.IsNullOrEmpty(existingSessionToken) || string.IsNullOrEmpty(existingSessionEmail)) @@ -2737,7 +2747,7 @@ public static void CheckWhiteLabelSession(string email, Action onComplete) string token = null; if (!string.IsNullOrEmpty(playerUlid)) { - var playerData = LootLockerStateData.GetStateForPlayerOrDefaultStateOrEmpty(playerUlid); + var playerData = LootLockerStateData.GetPlayerDataForPlayerWithUlidWithoutChangingState(playerUlid); token = playerData?.WhiteLabelToken; } else @@ -2814,7 +2824,7 @@ public static void StartWhiteLabelSession(Action onCo string email = null; string token = null; - var playerData = LootLockerStateData.GetStateForPlayerOrDefaultStateOrEmpty(forPlayerWithUlid); + var playerData = LootLockerStateData.GetPlayerDataForPlayerWithUlidWithoutChangingState(forPlayerWithUlid); if (playerData == null || string.IsNullOrEmpty(playerData.WhiteLabelEmail)) { if (_wllProcessesDictionary.Count == 0) @@ -2876,7 +2886,7 @@ public static void StartWhiteLabelSession(string email, Action($"No White Label data stored for {email}", null)); return; } - var playerData = LootLockerStateData.GetStateForPlayerOrDefaultStateOrEmpty(playerUlidInStateData); + var playerData = LootLockerStateData.GetPlayerDataForPlayerWithUlidWithoutChangingState(playerUlidInStateData); token = playerData.WhiteLabelToken; if(Optionals == null) @@ -3307,17 +3317,18 @@ public static void SetPlayerName(string name, Action onCompl return; } - var playerData = LootLockerStateData.GetStateForPlayerOrDefaultStateOrEmpty(forPlayerWithUlid); + if (name.ToLower().Contains("player")) + { + onComplete?.Invoke(LootLockerResponseFactory.ClientError("Setting the Player name to 'Player' is not allowed", forPlayerWithUlid)); + return; + + } + + var playerData = LootLockerStateData.GetPlayerDataForPlayerWithUlidWithoutChangingState(forPlayerWithUlid); if (playerData != null && playerData.CurrentPlatform.Platform == LL_AuthPlatforms.Guest) { - if (name.ToLower().Contains("player")) - { - onComplete?.Invoke(LootLockerResponseFactory.ClientError("Setting the Player name to 'Player' is not allowed", forPlayerWithUlid)); - return; - - } - else if (name.ToLower().Contains(playerData.Identifier.ToLower())) + if (name.ToLower().Contains(playerData.Identifier.ToLower())) { onComplete?.Invoke(LootLockerResponseFactory.ClientError("Setting the Player name to the Identifier is not allowed", forPlayerWithUlid)); return; @@ -4584,7 +4595,7 @@ public static void GetClassLoadout(Action onComp /// Optional : Execute the request for the specified player. If not supplied, the default player will be used. public static void GetOtherPlayersClassLoadout(string playerID, Action onComplete, string forPlayerWithUlid = null) { - var playerData = LootLockerStateData.GetStateForPlayerOrDefaultStateOrEmpty(forPlayerWithUlid); + var playerData = LootLockerStateData.GetPlayerDataForPlayerWithUlidWithoutChangingState(forPlayerWithUlid); GetOtherPlayersClassLoadout(playerID, playerData == null ? LL_AuthPlatforms.None : playerData.CurrentPlatform.Platform, onComplete, forPlayerWithUlid); } @@ -4818,7 +4829,7 @@ public static void GetCurrentLoadoutToDefaultClass(ActionOptional : Execute the request for the specified player. If not supplied, the default player will be used. public static void GetCurrentLoadoutToOtherClass(string playerID, Action onComplete, string forPlayerWithUlid = null) { - var playerData = LootLockerStateData.GetStateForPlayerOrDefaultStateOrEmpty(forPlayerWithUlid); + var playerData = LootLockerStateData.GetPlayerDataForPlayerWithUlidWithoutChangingState(forPlayerWithUlid); GetCurrentLoadoutToOtherClass(playerID, playerData == null ? LL_AuthPlatforms.None : playerData.CurrentPlatform.Platform, onComplete, forPlayerWithUlid); } @@ -7986,7 +7997,7 @@ public static void DeleteFriend(string playerID, ActionOptional : Execute the request for the specified player. If not supplied, the default player will be used. public static void ListFollowers(Action onComplete, string forPlayerWithUlid = null) { - var playerData = LootLockerStateData.GetStateForPlayerOrDefaultStateOrEmpty(forPlayerWithUlid); + var playerData = LootLockerStateData.GetPlayerDataForPlayerWithUlidWithoutChangingState(forPlayerWithUlid); ListFollowers(playerData.PublicUID, onComplete, forPlayerWithUlid); } /// @@ -7998,7 +8009,7 @@ public static void ListFollowers(Action onCompl /// Optional : Execute the request for the specified player. If not supplied, the default player will be used. public static void ListFollowersPaginated(string Cursor, int Count, Action onComplete, string forPlayerWithUlid = null) { - var playerData = LootLockerStateData.GetStateForPlayerOrDefaultStateOrEmpty(forPlayerWithUlid); + var playerData = LootLockerStateData.GetPlayerDataForPlayerWithUlidWithoutChangingState(forPlayerWithUlid); ListFollowersPaginated(playerData.PublicUID, Cursor, Count, onComplete, forPlayerWithUlid); } @@ -8048,7 +8059,7 @@ public static void ListFollowersPaginated(string playerPublicUID, string Cursor, /// Optional : Execute the request for the specified player. If not supplied, the default player will be used. public static void ListFollowing(Action onComplete, string forPlayerWithUlid = null) { - var playerData = LootLockerStateData.GetStateForPlayerOrDefaultStateOrEmpty(forPlayerWithUlid); + var playerData = LootLockerStateData.GetPlayerDataForPlayerWithUlidWithoutChangingState(forPlayerWithUlid); ListFollowing(playerData.PublicUID, onComplete, forPlayerWithUlid); } @@ -8061,7 +8072,7 @@ public static void ListFollowing(Action onCompl /// Optional : Execute the request for the specified player. If not supplied, the default player will be used. public static void ListFollowingPaginated(string Cursor, int Count, Action onComplete, string forPlayerWithUlid = null) { - var playerData = LootLockerStateData.GetStateForPlayerOrDefaultStateOrEmpty(forPlayerWithUlid); + var playerData = LootLockerStateData.GetPlayerDataForPlayerWithUlidWithoutChangingState(forPlayerWithUlid); ListFollowingPaginated(playerData.PublicUID, Cursor, Count, onComplete, forPlayerWithUlid); } @@ -8887,7 +8898,7 @@ public static void GetGameInfo(Action onComplete) /// The platform that was last used by the user public static LL_AuthPlatforms GetLastActivePlatform(string forPlayerWithUlid = null) { - var playerData = LootLockerStateData.GetStateForPlayerOrDefaultStateOrEmpty(forPlayerWithUlid); + var playerData = LootLockerStateData.GetPlayerDataForPlayerWithUlidWithoutChangingState(forPlayerWithUlid); if (playerData == null) { return LL_AuthPlatforms.None; diff --git a/Runtime/Game/Resources/LootLockerConfig.cs b/Runtime/Game/Resources/LootLockerConfig.cs index fc7305c2..9b2c51be 100644 --- a/Runtime/Game/Resources/LootLockerConfig.cs +++ b/Runtime/Game/Resources/LootLockerConfig.cs @@ -411,6 +411,9 @@ public static bool IsTargetingProductionEnvironment() [Tooltip("Automatically disconnect presence when app loses focus or is paused (useful for battery saving). Can be controlled at runtime via SetPresenceAutoDisconnectOnFocusChangeEnabled().")] public bool enablePresenceAutoDisconnectOnFocusChange = false; + + [Tooltip("Enable presence functionality while in the Unity Editor. Disable this if you don't want development to affect presence data.")] + public bool enablePresenceInEditor = true; #if UNITY_EDITOR [InitializeOnEnterPlayMode]