Can't bind function to a deligate

I’m trying to bind my function to OnTakePointDamage, but it acts unstable. I couldn’t get it to work yesterday but managed to do it eventually, however today it doesn’t work again. Am I missing something? Also hitting play for the first time in the session triggers a breakpoint in VS in some internal script and UE log in shows this: Ensure condition failed InvocationList[ CurFunctionIndex ] != InDelegate. But I can just press resume and this error won’t show up until the next session in Unreal

.h

UCLASS()
class MYPROJ_API CPP_EnemyBase : public ACharacter
{
	GENERATED_BODY()

public:
	ACPP_EnemyBase();

protected:
	virtual void BeginPlay() override;
...
	UFUNCTION()
		void HandlePointDamage(AActor* DamagedActor, float Damage, class AController* InstigatedBy, FVector HitLocation, class UPrimitiveComponent* FHitComponent, FName BoneName, FVector ShotFromDirection, const class UDamageType* DamageType, AActor* DamageCauser); //The function I want to bind

public:	
	virtual void Tick(float DeltaTime) override;

	virtual void SetupPlayerInputComponent(class UInputComponent* PlayerInputComponent) override;

};

.cpp

void ACPP_EnemyBase::BeginPlay()
{
	Super::BeginPlay();
	
	GetOwner()->OnTakePointDamage.AddDynamic(this, &ACPP_EnemyBase::HandlePointDamage);
}

void ACPP_EnemyBase::HandlePointDamage(AActor* DamagedActor, float Damage, AController* InstigatedBy, FVector HitLocation, UPrimitiveComponent* FHitComponent, FName BoneName, FVector ShotFromDirection, const UDamageType* DamageType, AActor* DamageCauser)
{
	UE_LOG(LogTemp, Warning, TEXT("Ouch"); //This doesn't fire, breakpoint too
}

Why do use GetOwner() ?
Your class is derived from ACharacter, which is derived from APawn, which is derived from AActor, which has the OnTakePointDamage delegate declared in it. So you have the access to it directly. I guess GetOwner() returns something you don’t need. Try removing it maybe?

2 Likes

Tuerer is right. I think this error means you are binding a delegate twice, which you might be doing with GetOwner. I remember something very similar, didn’t check the source to be sure.

*Edit, yep, that’s it.
ScriptDelegates.h line 556:

void AddInternal( const TScriptDelegate<TWeakPtr>& InDelegate )
{
#if !(UE_BUILD_SHIPPING || UE_BUILD_TEST)
	// Verify same function isn't already bound
	const int32 NumFunctions = InvocationList.Num();
	for( int32 CurFunctionIndex = 0; CurFunctionIndex < NumFunctions; ++CurFunctionIndex )
	{
		(void)ensure( InvocationList[ CurFunctionIndex ] != InDelegate );
	}
#endif // !(UE_BUILD_SHIPPING || UE_BUILD_TEST)
	InvocationList.Add( InDelegate );
}

So, I got rid of GetOwner(), but the error still pops up and I’m sure I don’t have other binds. It doesn’t seem to cause any problems, Tuerer’s solution worked, but should I be worried about it?

It’s absolutely bound somewhere. Unsure if it causes any trouble.

What if you use AddUniqueDynamic() instead of AddDynamic() ?

Documentation says:

  • “Helper macro to bind a UObject instance and a member UFUNCTION to a dynamic multi-cast delegate, but only if it hasn’t been bound before.”

So that would still cause one binding to silently fail. Vefery has to find out why / where it is bound > 1.

You can scan c++ files quickly with Agent Ransack, it’s a tool perfect for these situations.

I fugered out what causes the error, but it’s the bind from another class. I recently moved the binding there from initialization to BeginPlay, I reverted the change and now it doesn’t throw errors
I’m confused, I’ve read that I shouldn’t put bindings in initialization because it might be corrupted in the process (which happened with OnTakePointDamage bind from the first post initially)

Initialization? From what method?
BeginPlay is correct to make all bindings.

I mean this in .cpp

// Sets default values
CPP_Class::CPP_Class()
{
 	// Set this character to call Tick() every frame.  You can turn this off to improve performance if you don't need it.
	PrimaryActorTick.bCanEverTick = true;

}

Why is this giving me the error then?
.h

UCLASS()
class MYPROJ_API ACPP_BattleArea : public AActor
{
	GENERATED_BODY()
	
public:	
	ACPP_BattleArea();

	virtual void Tick(float DeltaTime) override;

	UFUNCTION()
	void BeginOverlap(UPrimitiveComponent* OverlappedComponent, AActor* OtherActor, UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep, const FHitResult& SweepResult);

	UFUNCTION()
	void EndOverlap(UPrimitiveComponent* OverlappedComponent, AActor* OtherActor, UPrimitiveComponent* OtherComp, int32 OtherBodyIndex);
};

.cpp

ACPP_BattleArea::ACPP_BattleArea()
{
	PrimaryActorTick.bCanEverTick = false;

	Root = CreateDefaultSubobject<USceneComponent>(TEXT("Scene"));
	Collision = CreateDefaultSubobject<UBoxComponent>(TEXT("Area"));
}

void ACPP_BattleArea::BeginPlay()
{
	Super::BeginPlay();

	Collision->OnComponentBeginOverlap.AddDynamic(this, &ACPP_BattleArea::BeginOverlap);
	Collision->OnComponentEndOverlap.AddDynamic(this, &ACPP_BattleArea::EndOverlap);
}

I see no mistake in the latter .cpp and .h files. The error

Ensure condition failed InvocationList[ CurFunctionIndex ] != InDelegate

Is described in source as

// Verify same function isn't already bound (or throw error)

I have no other explanation than just to believe the source code comment, I doubt that somehow a previously made binding has survived a change in source code but if there is no other place you are making a binding I can’t think of any.
You could go into VS and set breakpoints to read when / where it was previously set from .

Well, I solved it with AddUniqudDynamic() as Tuerer suggested

1 Like