diff --git a/Content/BlueprintSampleContent/ImtblUnauthenticatedWidget4_26.uasset b/Content/BlueprintSampleContent/ImtblUnauthenticatedWidget4_26.uasset index 065a7ba..143a398 100644 Binary files a/Content/BlueprintSampleContent/ImtblUnauthenticatedWidget4_26.uasset and b/Content/BlueprintSampleContent/ImtblUnauthenticatedWidget4_26.uasset differ diff --git a/Source/Immutable/Private/Immutable/Actions/ImtblConnectImxAsyncAction.cpp b/Source/Immutable/Private/Immutable/Actions/ImtblConnectImxAsyncAction.cpp index 14428fb..54de3a3 100644 --- a/Source/Immutable/Private/Immutable/Actions/ImtblConnectImxAsyncAction.cpp +++ b/Source/Immutable/Private/Immutable/Actions/ImtblConnectImxAsyncAction.cpp @@ -7,24 +7,26 @@ #include "Immutable/Misc/ImtblLogging.h" -UImtblConnectionAsyncActions* UImtblConnectionAsyncActions::Login(UObject* WorldContextObject) +UImtblConnectionAsyncActions* UImtblConnectionAsyncActions::Login(UObject* WorldContextObject, EImmutableDirectLoginMethod DirectLoginMethod) { UImtblConnectionAsyncActions* PassportInitBlueprintNode = NewObject(); PassportInitBlueprintNode->WorldContextObject = WorldContextObject; PassportInitBlueprintNode->bIsConnectImx = false; PassportInitBlueprintNode->bIsPKCE = true; + PassportInitBlueprintNode->DirectLoginMethod = DirectLoginMethod; return PassportInitBlueprintNode; } -UImtblConnectionAsyncActions* UImtblConnectionAsyncActions::ConnectImx(UObject* WorldContextObject) +UImtblConnectionAsyncActions* UImtblConnectionAsyncActions::ConnectImx(UObject* WorldContextObject, EImmutableDirectLoginMethod DirectLoginMethod) { UImtblConnectionAsyncActions* PassportInitBlueprintNode = NewObject(); PassportInitBlueprintNode->WorldContextObject = WorldContextObject; PassportInitBlueprintNode->bIsConnectImx = true; PassportInitBlueprintNode->bIsPKCE = true; + PassportInitBlueprintNode->DirectLoginMethod = DirectLoginMethod; return PassportInitBlueprintNode; } @@ -52,7 +54,7 @@ void UImtblConnectionAsyncActions::DoConnect(TWeakObjectPtr J if (bIsPKCE) { #if PLATFORM_ANDROID | PLATFORM_IOS | PLATFORM_MAC | PLATFORM_WINDOWS - Passport->Connect(bIsConnectImx, UImmutablePassport::FImtblPassportResponseDelegate::CreateUObject(this, &UImtblConnectionAsyncActions::OnConnect)); + Passport->Connect(bIsConnectImx, UImmutablePassport::FImtblPassportResponseDelegate::CreateUObject(this, &UImtblConnectionAsyncActions::OnConnect), DirectLoginMethod); #endif } } diff --git a/Source/Immutable/Private/Immutable/ImmutablePassport.cpp b/Source/Immutable/Private/Immutable/ImmutablePassport.cpp index 181c69a..c951f78 100644 --- a/Source/Immutable/Private/Immutable/ImmutablePassport.cpp +++ b/Source/Immutable/Private/Immutable/ImmutablePassport.cpp @@ -87,7 +87,7 @@ void UImmutablePassport::Initialize(const FImtblPassportResponseDelegate& Respon } #if PLATFORM_ANDROID | PLATFORM_IOS | PLATFORM_MAC | PLATFORM_WINDOWS -void UImmutablePassport::Connect(bool IsConnectImx, const FImtblPassportResponseDelegate& ResponseDelegate) +void UImmutablePassport::Connect(bool IsConnectImx, const FImtblPassportResponseDelegate& ResponseDelegate, EImmutableDirectLoginMethod DirectLoginMethod) { SetStateFlags(IPS_CONNECTING | IPS_PKCE); @@ -108,7 +108,34 @@ void UImmutablePassport::Connect(bool IsConnectImx, const FImtblPassportResponse } PKCEResponseDelegate = ResponseDelegate; Analytics->Track(IsConnectImx ? UImmutableAnalytics::EEventName::START_CONNECT_IMX_PKCE : UImmutableAnalytics::EEventName::START_LOGIN_PKCE); - CallJS(ImmutablePassportAction::GetPKCEAuthUrl, TEXT(""), PKCEResponseDelegate, FImtblJSResponseDelegate::CreateUObject(this, &UImmutablePassport::OnGetAuthUrlResponse)); + + FImmutableGetPKCEAuthUrlRequest PKCERequest; + PKCERequest.isConnectImx = IsConnectImx; + PKCERequest.directLoginMethod = DirectLoginMethod; + + // Custom export callback to handle all enums to use lowercase + FJsonObjectConverter::CustomExportCallback CustomCallback; + CustomCallback.BindLambda([](FProperty* Property, const void* Value) -> TSharedPtr + { + if (FEnumProperty* EnumProperty = CastField(Property)) + { + int64 EnumValue = EnumProperty->GetUnderlyingProperty()->GetSignedIntPropertyValue(Value); + + if (UEnum* Enum = EnumProperty->GetEnum()) + { + FString EnumNameString = Enum->GetNameStringByValue(EnumValue); + return MakeShareable(new FJsonValueString(EnumNameString.ToLower())); + } + } + + // Return null to use default serialization for non-enum properties + return TSharedPtr(); + }); + + FString PKCERequestJson; + FJsonObjectConverter::UStructToJsonObjectString(PKCERequest, PKCERequestJson, 0, 0, 0, &CustomCallback); + + CallJS(ImmutablePassportAction::GetPKCEAuthUrl, PKCERequestJson, PKCEResponseDelegate, FImtblJSResponseDelegate::CreateUObject(this, &UImmutablePassport::OnGetAuthUrlResponse)); } #endif @@ -754,4 +781,4 @@ void UImmutablePassport::LaunchAndroidUrl(FString Url) CallJniStaticVoidMethod(Env, jimmutableAndroidClass, jlaunchUrl, FJavaWrapper::GameActivityThis, jurl); } } -#endif +#endif \ No newline at end of file diff --git a/Source/Immutable/Public/Immutable/Actions/ImtblConnectImxAsyncAction.h b/Source/Immutable/Public/Immutable/Actions/ImtblConnectImxAsyncAction.h index 6de45f3..b9cd8da 100644 --- a/Source/Immutable/Public/Immutable/Actions/ImtblConnectImxAsyncAction.h +++ b/Source/Immutable/Public/Immutable/Actions/ImtblConnectImxAsyncAction.h @@ -22,21 +22,23 @@ class IMMUTABLE_API UImtblConnectionAsyncActions : public UImtblBlueprintAsyncAc * Log into Passport * * @param WorldContextObject World context + * @param DirectLoginMethod Direct login method to use for authentication (defaults to None for standard login page) * * @return A reference to the object represented by this node */ UFUNCTION(BlueprintCallable, meta = (WorldContext = "WorldContextObject", BlueprintInternalUseOnly = "true"), Category = "Immutable") - static UImtblConnectionAsyncActions* Login(UObject* WorldContextObject); + static UImtblConnectionAsyncActions* Login(UObject* WorldContextObject, EImmutableDirectLoginMethod DirectLoginMethod = EImmutableDirectLoginMethod::None); /** * Log into Passport, initialise the gamer's wallet and instantiate the IMX provider. * * @param WorldContextObject World context + * @param DirectLoginMethod Direct login method to use for authentication (defaults to None for standard login page) * * @return A reference to the object represented by this node */ UFUNCTION(BlueprintCallable, meta = (WorldContext = "WorldContextObject", BlueprintInternalUseOnly = "true"), Category = "Immutable") - static UImtblConnectionAsyncActions* ConnectImx(UObject* WorldContextObject); + static UImtblConnectionAsyncActions* ConnectImx(UObject* WorldContextObject, EImmutableDirectLoginMethod DirectLoginMethod = EImmutableDirectLoginMethod::None); virtual void Activate() override; @@ -54,4 +56,5 @@ class IMMUTABLE_API UImtblConnectionAsyncActions : public UImtblBlueprintAsyncAc bool bUseCachedSession = false; bool bIsConnectImx = false; bool bIsPKCE = false; + EImmutableDirectLoginMethod DirectLoginMethod = EImmutableDirectLoginMethod::None; }; diff --git a/Source/Immutable/Public/Immutable/ImmutableDataTypes.h b/Source/Immutable/Public/Immutable/ImmutableDataTypes.h index ef9cf1a..7ff7136 100644 --- a/Source/Immutable/Public/Immutable/ImmutableDataTypes.h +++ b/Source/Immutable/Public/Immutable/ImmutableDataTypes.h @@ -14,6 +14,18 @@ DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FImmutableDeepLinkDynamicMulticastDe // This hardcoded value will be updated by a workflow during the release process. #define ENGINE_SDK_VERSION TEXT("1.11.0") +/** + * Enum representing direct login methods for authentication providers + */ +UENUM(BlueprintType) +enum class EImmutableDirectLoginMethod : uint8 +{ + None, + Google, + Apple, + Facebook +}; + USTRUCT() struct FImmutableEngineVersionData { @@ -147,6 +159,23 @@ struct FImmutablePassportConnectData FString state; }; +/** + * Structure to hold PKCE authentication URL request data + */ +USTRUCT() +struct IMMUTABLE_API FImmutableGetPKCEAuthUrlRequest +{ + GENERATED_BODY() + + /** Whether this is a ConnectImx operation (true) or just Login (false) */ + UPROPERTY() + bool isConnectImx = false; + + /** Direct login method to use for authentication */ + UPROPERTY() + EImmutableDirectLoginMethod directLoginMethod = EImmutableDirectLoginMethod::None; +}; + USTRUCT() struct IMMUTABLE_API FImmutablePassportResult { diff --git a/Source/Immutable/Public/Immutable/ImmutablePassport.h b/Source/Immutable/Public/Immutable/ImmutablePassport.h index 37646a3..c9c546d 100644 --- a/Source/Immutable/Public/Immutable/ImmutablePassport.h +++ b/Source/Immutable/Public/Immutable/ImmutablePassport.h @@ -103,8 +103,9 @@ class IMMUTABLE_API UImmutablePassport : public UObject * @param IsConnectImx If true, player will connect to Immutable X after logging in. * Else, just perform the login without connecting to Immutable X. * @param ResponseDelegate Callback delegate. + * @param DirectLoginMethod Direct login method to use for authentication (defaults to None for standard login page). */ - void Connect(bool IsConnectImx, const FImtblPassportResponseDelegate& ResponseDelegate); + void Connect(bool IsConnectImx, const FImtblPassportResponseDelegate& ResponseDelegate, EImmutableDirectLoginMethod DirectLoginMethod = EImmutableDirectLoginMethod::None); #endif /**