Unable to bind delegate (function might not be marked as a UFUNCTION)

Hi all,

I am using Github Promoted branch and I’m having this issue with adding delegates in C++. I am using GameSparks and I’m having trouble trying to bind a function to their OnResponse delegate.

// Generate a delegate for the OnGetResult event
DECLARE_DYNAMIC_MULTICAST_DELEGATE_TwoParams(FOnAuthenticationRequest_Response, FGSAuthenticationResponse, AuthenticationResponse, bool, hasErrors);

UCLASS()
class GAMESPARKS_API UGSAuthenticationRequest : public UOnlineBlueprintCallProxyBase
{
	GENERATED_BODY()

public:
	
	/* Event which triggers when the content has been retrieved */
	UPROPERTY(BlueprintAssignable, Category = "GameSparks")
	FOnAuthenticationRequest_Response OnResponse;
	
	/**
	Provides authentication using a username/password combination.
	The username will have been previously created using a RegistrationRequest.
	*/
	UFUNCTION(BlueprintCallable, meta = (DisplayName="GS AuthenticationRequest", BlueprintInternalUseOnly = "true"), Category = "GameSparks|Requests|Authentication")
	static UGSAuthenticationRequest* SendAuthenticationRequest(FString Password = "", FString UserName = "",  UGameSparksScriptData* ScriptData = nullptr, bool Durable = false, int32 RequestTimeoutSeconds = 0);

     //...
	
};

Game Instance header file:

#if IS_GAMESPARKS_PLATFORM
private:
    
        UFUNCTION()
        void OnPlayerLogin(FGSAuthenticationResponse Response, bool bHasErrors);
 #endif

Game instance source file:

#if IS_GAMESPARKS_PLATFORM
void UBaseGameInstance::Internal_LoginPlayer(const FString& Username, const FString& Password)
    {
    	if (Username.IsEmpty() == false && Password.IsEmpty() == false)
    	{
    		UGSAuthenticationRequest* const AuthRequest = UGSAuthenticationRequest::SendAuthenticationRequest(Password, Username);		
    		AuthRequest->OnResponse.AddDynamic(this, &UBaseGameInstance::OnPlayerLogin);
    	}
    }
#endif

It compiles fine and i can launch my game. However when i call Internal_LoginPlayer function (which tries to bind the OnPlayerLogin function) I get the below error:

Unable to bind delegate to 'OnPlayerLogin' (function might not be marked as a UFUNCTION)

Any idea how to fix this?

It looks like delegates fail to bind if they are inside macros. For example the below code will generate Unable to bind delegate to 'FunctionName' error

#if PLATFORM_WINDOWS
	UFUNCTION()
	virtual void OnPlayerLogin(FGSAuthenticationResponse AuthenticationResponse, bool hasErrors);
#endif

where as this one works:

// #if PLATFORM_WINDOWS
	UFUNCTION()
	virtual void OnPlayerLogin(FGSAuthenticationResponse AuthenticationResponse, bool hasErrors);
// #endif

gentle bump

Hello ,

Thank you for reporting this issue. I’ve been able to reproduce the same thing on my end so I’ve entered a bug report in for this issue. For reference, the bug’s number is UE-31627. The only thing I can think to do in the meantime, as a workaround, is to put ONLY the function’s logic into the #if block instead and see if that works, as it seems to have on my end.

Have a nice day!

Thank you Clark. Unfortunately I cant make the function logic wrapped inside the #if block because of the function signature. This function I am using requires a delegate from GameSparks which is not available in Linux build. So because of the first parameter I cant wrap the logic of the function inside :frowning:

Hi,

This type of construct is not supported by UnrealHeaderTool as it does not do full preprocessing and so does not know about most macros, which it treats by ignoring all code within. The macros it does know about are hard-coded: CPP, !CPP, WITH_EDITOR and WITH_EDITORONLY_DATA

We plan to add a feature soon which will detect UPROPERTYs, UFUNCTIONs etc. which will be skipped inside these blocks so that you will at least get an error instead of unexpected behaviour.

However, there are no current plans to add full preprocessing to UnrealHeaderTool, so you will need to find a workaround for your use case.

Steve

Its really sad to hear that because this is the only limitation that is preventing me from creating Linux server instances which I want to run on AWS :frowning:

I’d suggest contacting GameSparks and asking them to provide non-Linux stub versions of FGSAuthenticationResponse. Or you could author it yourself, since it is just in a header. I’m guessing something like:

// GamesparksHeader.h
#include "Gamesparks.generated.h"

USTRUCT()
struct FGSAuthenticationResponse
{
    GENERATED_BODY()

    UFUNCTION()
    void SomeLinuxOnlyFunction();
};

// This will be skipped by UHT anyway
#if !PLATFORM_LINUX
    inline void FGSAuthenticationResponse::SomeLinuxOnlyFunction()
    {
        // Do nothing
    }
#endif

… and on Linux, the function will be provided by their library.

Disclaimer: I don’t know what the GameSparks code is like. :slight_smile:

Steve

Thank you Steve :). I’ll get in touch with them and see if its possible to make GameSparks running in Linux (I’ll refer this post also). In their build file itself they dont support Linux.

case UnrealTargetPlatform.Linux:
			default:
				throw new NotImplementedException("This target platform is not configured for GameSparks SDK: " + Target.Platform.ToString());

I think I can still make it work by breaking down their struct and create functions for each struct properties but then it will harder to maintain and will result in a large header file.