Skip to content
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
10 changes: 8 additions & 2 deletions Runtime/Client/LootLockerHTTPClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -625,7 +625,10 @@ private HTTPExecutionQueueProcessingResult ProcessOngoingRequest(LootLockerHTTPE
if (ShouldRetryRequest(executionItem.WebRequest.responseCode, executionItem.RequestData.TimesRetried) && !(executionItem.WebRequest.responseCode == 401 && !IsAuthorizedRequest(executionItem)))
{
var playerData = LootLockerStateData.GetPlayerDataForPlayerWithUlidWithoutChangingState(executionItem.RequestData.ForPlayerWithUlid);
if (ShouldRefreshSession(executionItem, playerData == null ? LL_AuthPlatforms.None : playerData.CurrentPlatform.Platform) && (CanRefreshUsingRefreshToken(executionItem.RequestData) || CanStartNewSessionUsingCachedAuthData(executionItem.RequestData.ForPlayerWithUlid)))
bool shouldRefreshSession = ShouldRefreshSession(executionItem, playerData == null ? LL_AuthPlatforms.None : playerData.CurrentPlatform.Platform);
bool canRefreshWithToken = CanRefreshUsingRefreshToken(executionItem.RequestData);
bool canReAuth = CanStartNewSessionUsingCachedAuthData(executionItem.RequestData.ForPlayerWithUlid);
if (shouldRefreshSession && (canRefreshWithToken || canReAuth))
{
return HTTPExecutionQueueProcessingResult.NeedsSessionRefresh;
}
Expand Down Expand Up @@ -909,7 +912,10 @@ private static bool ShouldRetryRequest(long statusCode, int timesRetried)

private static bool ShouldRefreshSession(LootLockerHTTPExecutionQueueItem request, LL_AuthPlatforms platform)
{
return IsAuthorizedGameRequest(request) && (request.WebRequest?.responseCode == 401 || request.WebRequest?.responseCode == 403) && LootLockerConfig.current.allowTokenRefresh && !new List<LL_AuthPlatforms>{ LL_AuthPlatforms.Steam, LL_AuthPlatforms.NintendoSwitch, LL_AuthPlatforms.None }.Contains(platform);
bool isAuthorized = IsAuthorizedRequest(request);
bool isRefreshableResponseCode = (request.WebRequest?.responseCode == 401 || request.WebRequest?.responseCode == 403);
bool isRefreshablePlatform = LootLockerConfig.current.allowTokenRefresh && !new List<LL_AuthPlatforms>{ LL_AuthPlatforms.Steam, LL_AuthPlatforms.NintendoSwitch, LL_AuthPlatforms.None }.Contains(platform);
return isAuthorized && isRefreshableResponseCode && isRefreshablePlatform;
}

private static bool IsAuthorizedRequest(LootLockerHTTPExecutionQueueItem request)
Expand Down
10 changes: 9 additions & 1 deletion Runtime/Client/LootLockerLifecycleManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,11 @@ namespace LootLocker
/// </summary>
public enum LifecycleManagerState
{
/// <summary>
/// Manager is not initialized or has been destroyed - can be recreated
/// </summary>
Uninitialized,

/// <summary>
/// Normal operation - services can be accessed and managed
/// </summary>
Expand Down Expand Up @@ -132,6 +137,9 @@ private static void TeardownInstance()
_instanceId = 0;
_hostingGameObject = null;
}

// Set to Uninitialized after teardown to allow recreation
_state = LifecycleManagerState.Uninitialized;
}
}

Expand Down Expand Up @@ -180,7 +188,7 @@ static void OnEnterPlaymodeInEditor(UnityEditor.EnterPlayModeOptions options)
private bool _isInitialized = false;
private bool _serviceHealthMonitoringEnabled = true;
private Coroutine _healthMonitorCoroutine = null;
private static LifecycleManagerState _state = LifecycleManagerState.Ready;
private static LifecycleManagerState _state = LifecycleManagerState.Uninitialized;
private readonly object _serviceLock = new object();

/// <summary>
Expand Down
48 changes: 48 additions & 0 deletions Runtime/Client/LootLockerPresenceClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -246,6 +246,11 @@ public class LootLockerPresenceClient : MonoBehaviour, IDisposable
/// </summary>
public string PlayerUlid => playerUlid;

/// <summary>
/// The session token this client is using for authentication
/// </summary>
public string SessionToken => sessionToken;

/// <summary>
/// The last status that was sent to the server (e.g., "online", "in_game", "away")
/// </summary>
Expand Down Expand Up @@ -384,6 +389,14 @@ internal void Initialize(string playerUlid, string sessionToken)
ChangeConnectionState(LootLockerPresenceConnectionState.Initializing);
}

/// <summary>
/// Update the session token for this client (used during token refresh)
/// </summary>
internal void UpdateSessionToken(string newSessionToken)
{
this.sessionToken = newSessionToken;
}

/// <summary>
/// Connect to the Presence WebSocket
/// </summary>
Expand Down Expand Up @@ -983,6 +996,14 @@ private void HandleAuthenticationResponse(string message)

pingCoroutine = StartCoroutine(PingCoroutine());

// Auto-resend last status if we have one
if (!string.IsNullOrEmpty(connectionStats.lastSentStatus))
{
LootLockerLogger.Log($"Auto-resending last status '{connectionStats.lastSentStatus}' after reconnection", LootLockerLogger.LogLevel.Debug);
// Use a coroutine to avoid blocking the authentication flow
StartCoroutine(AutoResendLastStatusCoroutine());
}

// Reset reconnect attempts on successful authentication
reconnectAttempts = 0;
}
Expand Down Expand Up @@ -1124,6 +1145,33 @@ private IEnumerator ScheduleReconnectCoroutine(float customDelay = -1f)
}
}

/// <summary>
/// Coroutine to auto-resend the last status after successful reconnection
/// </summary>
private IEnumerator AutoResendLastStatusCoroutine()
{
// Wait a frame to ensure we're fully connected
yield return null;

// Double-check we're still connected and have a status to send
if (IsConnectedAndAuthenticated && !string.IsNullOrEmpty(connectionStats.lastSentStatus))
{
// Find the last sent metadata if any
// Note: We don't store metadata currently, so we'll resend with null metadata
// This could be enhanced later if metadata preservation is needed
UpdateStatus(connectionStats.lastSentStatus, null, (success, error) => {
if (success)
{
LootLockerLogger.Log($"Successfully auto-resent status '{connectionStats.lastSentStatus}' after reconnection", LootLockerLogger.LogLevel.Debug);
}
else
{
LootLockerLogger.Log($"Failed to auto-resend status after reconnection: {error}", LootLockerLogger.LogLevel.Warning);
}
});
}
}

#endregion
}
}
Loading
Loading