Skip to content
Merged
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
73 changes: 54 additions & 19 deletions com.playeveryware.eos/Runtime/Core/EOSManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,16 @@ public partial class EOSManager : MonoBehaviour, IEOSCoroutineOwner
public delegate void OnAuthLogoutCallback(LogoutCallbackInfo data);

public delegate void OnConnectLoginCallback(Epic.OnlineServices.Connect.LoginCallbackInfo loginCallbackInfo);
/// <summary>
/// Raised whenever the EOS overlay’s visibility changes, or when the title
/// loses/regains focus and we must indicate whether the overlay was open
/// before the interruption. Some platform-specific managers use
/// this to synchronize their native overlay state.
/// </summary>
/// <param name="isOccluded">Whether the overlay was open when focus was lost</param>
public delegate void OnOverlayOccludedChangedDelegate(bool isOccluded);

public static event OnOverlayOccludedChangedDelegate OnOverlayOccludedChanged;
private static event OnAuthLoginCallback OnAuthLogin;
private static event OnAuthLogoutCallback OnAuthLogout;
private static event OnConnectLoginCallback OnConnectLogin;
Expand Down Expand Up @@ -147,8 +156,12 @@ public delegate void OnAuthLinkExternalAccountCallback(
/// <value>True if EOS Overlay is visible and has exclusive input.</value>
private static bool s_isOverlayVisible;

private static bool s_isOverlayOccluded;

private static bool s_DoesOverlayHaveExcusiveInput;

private static Coroutine s_restoreOverlayCoroutine;

//cached log levels for retrieving later
private static Dictionary<LogCategory, LogLevel> logLevels;

Expand Down Expand Up @@ -192,7 +205,7 @@ enum EOSState
public partial class EOSSingleton
{
private const float NetworkStatusUpdateIntervalSecs = 0.5f;

private static float s_nextNetworkStatusUpdateTime = 0.0f;
static private EpicAccountId s_localUserId;
static private ProductUserId s_localProductUserId;
Expand Down Expand Up @@ -499,6 +512,7 @@ private void InitializeOverlay(IEOSCoroutineOwner coroutineOwner)
{
s_isOverlayVisible = data.IsVisible;
s_DoesOverlayHaveExcusiveInput = data.IsExclusiveInput;
OnOverlayOccludedChanged?.Invoke(s_isOverlayOccluded);
});
}

Expand Down Expand Up @@ -690,7 +704,7 @@ public void Init(IEOSCoroutineOwner coroutineOwner, string configFileName = null

InitializeNetworkChecks(coroutineOwner);
InitializeOverlay(coroutineOwner);

Log("EOS loaded");
}

Expand Down Expand Up @@ -1275,7 +1289,7 @@ public void StartPersistentLogin(OnAuthLoginCallback onLoginCallback)
public void StartLoginWithLoginTypeAndToken(LoginCredentialType loginType, string id, string token,
OnAuthLoginCallback onLoginCallback)
{
if(loginType == LoginCredentialType.ExchangeCode && string.IsNullOrEmpty(token))
if (loginType == LoginCredentialType.ExchangeCode && string.IsNullOrEmpty(token))
{
Debug.LogError($"{nameof(EOSManager)} {nameof(StartLoginWithLoginTypeAndToken)}: ExchangeCode login attempted with empty token. Abort login.");
onLoginCallback?.Invoke(new LoginCallbackInfo
Expand Down Expand Up @@ -1712,21 +1726,6 @@ private void UpdateEOSApplicationStatus()
// Application is in the foreground and running normally
SetEOSApplicationStatus(ApplicationStatus.Foreground);
}
else // NOT Focused
{
#if UNITY_GAMECORE_XBOXONE || UNITY_GAMECORE_SCARLETT
if (s_isConstrained)
{
// Application is in the background but running with reduced CPU/GPU resouces (it's constrained)
SetEOSApplicationStatus(ApplicationStatus.BackgroundConstrained);
}
else // NOT Constrained
{
// Application is in the background but running normally (should be non-interactable since it's in the background)
SetEOSApplicationStatus(ApplicationStatus.BackgroundUnconstrained);
}
#endif
Comment thread
matt-clarke marked this conversation as resolved.
}
}
}

Expand Down Expand Up @@ -1858,7 +1857,7 @@ void Awake()
enabled = false;
return;
}

// Indicate that a EOSManager has been created, and mark it to not be destroyed
s_EOSManagerInstance = this;
DontDestroyOnLoad(this.gameObject);
Expand All @@ -1881,11 +1880,47 @@ void Update()
/// <summary>Unity [OnApplicationFocus](https://docs.unity3d.com/ScriptReference/MonoBehaviour.OnApplicationFocus.html) is called when the application loses or gains focus.
/// <list type="bullet">
/// <item><description>Calls <c>OnApplicationFocus()</c></description></item>
/// <item>When the application loses focus (system UI opened), record whether the overlay
/// was visible at that moment and immediately notify listeners that the overlay is
/// now considered “occluded”. Platform modules use this to maintain correct
/// ApplicationStatus behavior or defer overlay restoration.</item>
/// </list>
/// </summary>
void OnApplicationFocus(bool hasFocus)
{
Instance.OnApplicationFocus(hasFocus);

if (!hasFocus)
{
if (s_isOverlayVisible)
{
s_isOverlayOccluded = s_isOverlayVisible;
OnOverlayOccludedChanged?.Invoke(s_isOverlayOccluded);
}
return;
}

if (s_restoreOverlayCoroutine == null)
{
s_restoreOverlayCoroutine = StartCoroutine(RestoreOverlayAfterDelay());
}
}


/// <summary>
/// After regaining focus, wait several frames before clearing occlusion state.
/// This allows system UI dismissal, swapchain stabilization, and PrePresent
/// to resume before native overlay state is re-enabled. This delay prevents
/// race conditions where overlay state is updated too early.
/// </summary>
private System.Collections.IEnumerator RestoreOverlayAfterDelay()
{
yield return null;
yield return null;
yield return null;
s_isOverlayOccluded = false;
OnOverlayOccludedChanged?.Invoke(s_isOverlayOccluded);
s_restoreOverlayCoroutine = null;
}

//-------------------------------------------------------------------------
Expand Down