diff --git a/Plugins/BeamableCore/Source/BeamableCoreRuntime/Private/Runtime/BeamRuntime.cpp b/Plugins/BeamableCore/Source/BeamableCoreRuntime/Private/Runtime/BeamRuntime.cpp index 20fecaee..a2885cfc 100644 --- a/Plugins/BeamableCore/Source/BeamableCoreRuntime/Private/Runtime/BeamRuntime.cpp +++ b/Plugins/BeamableCore/Source/BeamableCoreRuntime/Private/Runtime/BeamRuntime.cpp @@ -314,16 +314,24 @@ void UBeamRuntime::TriggerOnBeamableStarting(FBeamWaitCompleteEvent Evt, TArray Errors; if (RequestTrackerSystem->IsWaitFailed(Evt, Errors)) { + CurrentSdkState = ESDKState::InitializationFailed; + FString Err; for (const auto& Error : Errors) Err += Error + TEXT("\n"); UE_LOG(LogBeamRuntime, Error, TEXT("%s"), *Err); - CurrentSdkState = ESDKState::InitializationFailed; + CachedInitializationErrors.Empty(); + for (auto& Op : Evt.Operations) + { + RequestTrackerSystem->TryGetOperationEvents(Op,EBeamOperationEventType::OET_ERROR,NAME_All,CachedInitializationErrors); + } + OnSDKInitializationFailed.Broadcast(CachedInitializationErrors); + OnSDKInitializationFailedCode.Broadcast(CachedInitializationErrors); // Early out and don't initialize if errors happen here. return; } - + // If everything is fine... so let's continue with initializing Beamable. if (const bool bIsDedicatedServer = GetGameInstance()->IsDedicatedServerInstance()) { @@ -380,12 +388,19 @@ void UBeamRuntime::TriggerOnContentReady(FBeamWaitCompleteEvent Evt, TArray Errors; if (RequestTrackerSystem->IsWaitFailed(Evt, Errors)) { + CurrentSdkState = ESDKState::InitializationFailed; + FString Err; for (const auto& Error : Errors) Err += Error + TEXT("\n"); UE_LOG(LogBeamRuntime, Error, TEXT("%s"), *Err); - CurrentSdkState = ESDKState::InitializationFailed; - + CachedInitializationErrors.Empty(); + for (auto& Op : Evt.Operations) + { + RequestTrackerSystem->TryGetOperationEvents(Op,EBeamOperationEventType::OET_ERROR,NAME_All,CachedInitializationErrors); + } + OnSDKInitializationFailed.Broadcast(CachedInitializationErrors); + OnSDKInitializationFailedCode.Broadcast(CachedInitializationErrors); // Early out and don't initialize if errors happen here. return; } @@ -417,11 +432,19 @@ void UBeamRuntime::TriggerOnStartedAndFrictionlessAuth(FBeamWaitCompleteEvent Ev TArray Errors; if (RequestTrackerSystem->IsWaitFailed(Evt, Errors)) { + CurrentSdkState = ESDKState::InitializationFailed; + FString Err; for (const auto& Error : Errors) Err += Error + TEXT("\n"); UE_LOG(LogBeamRuntime, Error, TEXT("%s"), *Err); - CurrentSdkState = ESDKState::InitializationFailed; + CachedInitializationErrors.Empty(); + for (auto& Op : Evt.Operations) + { + RequestTrackerSystem->TryGetOperationEvents(Op,EBeamOperationEventType::OET_ERROR,NAME_All,CachedInitializationErrors); + } + OnSDKInitializationFailed.Broadcast(CachedInitializationErrors); + OnSDKInitializationFailedCode.Broadcast(CachedInitializationErrors); // Early out and don't initialize if errors happen here. return; } @@ -520,6 +543,14 @@ void UBeamRuntime::TriggerSubsystemPostUserSignIn(FBeamWaitCompleteEvent Evt, FU for (const auto& Error : Errors) Err += Error + TEXT("\n"); UE_LOG(LogBeamRuntime, Error, TEXT("%s"), *Err); + TArray ErrorEvents; + for (auto& Op : Evt.Operations) + { + RequestTrackerSystem->TryGetOperationEvents(Op,EBeamOperationEventType::OET_ERROR,NAME_All,ErrorEvents); + } + + OnSubsystemsUserInitializationFailed.Broadcast(UserSlot,ErrorEvents); + OnSubsystemsUserInitializationFailedCode.Broadcast(UserSlot,ErrorEvents); // Early out and don't initialize if errors happen here. return; } @@ -556,6 +587,15 @@ void UBeamRuntime::TriggerSubsystemPostUserSignIn(FBeamWaitCompleteEvent Evt, FU for (const auto& Error : Errors) Err += Error + TEXT("\n"); UE_LOG(LogBeamRuntime, Error, TEXT("%s"), *Err); + TArray ErrorEvents; + for (auto& Op : PostEvt.Operations) + { + RequestTrackerSystem->TryGetOperationEvents(Op,EBeamOperationEventType::OET_ERROR,NAME_All,ErrorEvents); + } + + OnSubsystemsUserInitializationFailed.Broadcast(UserSlot,ErrorEvents); + OnSubsystemsUserInitializationFailedCode.Broadcast(UserSlot,ErrorEvents); + // Early out and don't initialize if errors happen here. return; } diff --git a/Plugins/BeamableCore/Source/BeamableCoreRuntime/Public/Runtime/BeamRuntime.h b/Plugins/BeamableCore/Source/BeamableCoreRuntime/Public/Runtime/BeamRuntime.h index 8be6b6f3..8fa9f150 100644 --- a/Plugins/BeamableCore/Source/BeamableCoreRuntime/Public/Runtime/BeamRuntime.h +++ b/Plugins/BeamableCore/Source/BeamableCoreRuntime/Public/Runtime/BeamRuntime.h @@ -161,7 +161,17 @@ DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FUserStateChangedEvent, const FUserS DECLARE_MULTICAST_DELEGATE_OneParam(FUserStateChangedEventCode, FUserSlot); +DECLARE_DYNAMIC_DELEGATE_OneParam(FRuntimeError,const TArray&, OperationEventsWithErrors); +DECLARE_DELEGATE_OneParam(FRuntimeErrorCode,const TArray&); + +DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FSDKInitilizationErrorEvent,const TArray&, OperationEventsWithErrors); + +DECLARE_MULTICAST_DELEGATE_OneParam(FSDKInitilizationErrorEventCode,const TArray&) ; + +DECLARE_DYNAMIC_MULTICAST_DELEGATE_TwoParams(FSubsystemsUserInitializationErrorEvent,const FUserSlot&,UserSlot,const TArray&, OperationEventsWithErrors); + +DECLARE_MULTICAST_DELEGATE_TwoParams(FSubsystemsUserInitializationErrorEventCode, const FUserSlot&,const TArray&); /** * State of SDK intialization. * @@ -323,6 +333,18 @@ class BEAMABLECORERUNTIME_API UBeamRuntime : public UGameInstanceSubsystem FRuntimeStateChangedEvent OnStarted; FRuntimeStateChangedEventCode OnStartedCode; + /** + * @brief This is called when the operations for starting the sdk fails. + */ + UPROPERTY() + FSDKInitilizationErrorEvent OnSDKInitializationFailed; + FSDKInitilizationErrorEventCode OnSDKInitializationFailedCode; + /** + * @brief This is a list of the operation that ended with errors after the initialization fails. + */ + UPROPERTY() + TArray CachedInitializationErrors; + /** * @brief Every time a user signs into beamable, we give each subsystem the ability to run an operation for that user. * We also give them the list of currently authenticated UserSlots (so that they can tell if the user that just signed in is the last one for example). @@ -355,7 +377,6 @@ class BEAMABLECORERUNTIME_API UBeamRuntime : public UGameInstanceSubsystem */ UPROPERTY() FRuntimeStateChangedEvent OnReady; - FRuntimeStateChangedEventCode OnReadyCode; /** @@ -519,6 +540,13 @@ class BEAMABLECORERUNTIME_API UBeamRuntime : public UGameInstanceSubsystem FUserStateChangedEvent OnUserCleared; FUserStateChangedEventCode OnUserClearedCode; + /** + * @brief This is called when the initialization of the subsystems user slots fails. + */ + UPROPERTY() + FSubsystemsUserInitializationErrorEvent OnSubsystemsUserInitializationFailed; + FSubsystemsUserInitializationErrorEventCode OnSubsystemsUserInitializationFailedCode; + /** * @brief In BP, use this function to bind initialization functions to OnReady. This will execute the delegate if you're already ready before it binds it. */ @@ -558,6 +586,45 @@ class BEAMABLECORERUNTIME_API UBeamRuntime : public UGameInstanceSubsystem OnReadyCode.Remove(Handle); } + /** + * @brief In BP, use this function to bind error handling logic to OnSDKInitializationFailed. This will execute the delegate if sdk already failed initialization before it binds it. + */ + UFUNCTION(BlueprintCallable) + void RegisterOnSDKInitializationFailed(FRuntimeError Handler) + { + if (CurrentSdkState == ESDKState::InitializationFailed) const auto _ = Handler.ExecuteIfBound(CachedInitializationErrors); + OnSDKInitializationFailed.Add(Handler); + } + + /** + * @brief In BP, use this function to bind error handling logic to OnSDKInitializationFailed. This will NOT execute the delegate if initialization already failed. + */ + UFUNCTION(BlueprintCallable) + void RegisterOnSDKInitializationFailed_NoExecute(FRuntimeError Handler) { OnSDKInitializationFailed.Add(Handler); } + + /** + * @brief In BP, use this function to unbind error handling events to OnSDKInitializationFailed. + */ + UFUNCTION(BlueprintCallable) + void UnRegisterOnSDKInitializationFailed(FRuntimeError Handler) + { + if (OnSDKInitializationFailed.Contains(Handler)) + OnSDKInitializationFailed.Remove(Handler); + } + + FDelegateHandle CPP_RegisterOnSDKInitializationFailed(FRuntimeErrorCode Handler) + { + if (bDidFirstAuthRun) const auto _ = Handler.ExecuteIfBound(CachedInitializationErrors); + return OnSDKInitializationFailedCode.Add(Handler); + } + + FDelegateHandle CPP_RegisterOnSDKInitializationFailed_NoExecute(FRuntimeErrorCode Handler) { return OnSDKInitializationFailedCode.Add(Handler); } + + void CPP_UnRegisterOnSDKInitializationFailed(FDelegateHandle Handle) + { + OnSDKInitializationFailedCode.Remove(Handle); + } + /** * @brief An operation that will authenticate a user with the beamable and persist that authentication locally. */