exposing FViewport::FOnViewportResized delegate in BlueprintFunctionLibrary to Blueprints

Hi everyone,

I’m writing a BlueprintFunctionLibrary as a Plugin and try to expose the delegate of FViewport::FOnViewportResized to bind some custom Blueprint events.

on compile I get

error : Unable to find 'class', 'delegate', 'enum', or 'struct' with name 'FViewport::FOnViewportResized'

I read that this error occurs when the Unreal Reflection system can not find it due to not being declared with UFUCNTION() Or UOBJECT().

Can I somehow work around that?

My current function definition is this:

.h file

#include "UnrealClient.h"

UFUNCTION(BlueprintCallable)
		static void BindToViewportResizeEvent(UPARAM(DisplayName = "Event") FViewport::FOnViewportResized Delegate);

.ccp file

void UMyFuncitonBPLib::BindToViewportResizeEvent(FViewport::FOnViewportResized Delegate)
{
    // theoretically binding like this?
    //FViewport::ViewportResizedEvent.AddUObject(this, &Delegate);
}

i would create a new dynamic delegate (not multicast) for my param. and use that.
then bind in a different way. either bind your functionbp, and let your function bp receive the event, then call the delegate (maybe youll need a list for this).
or somehow connect the delegate to the viewport delegate (maybe with a lambda if it allows you).

here’s an example of how i wrap delegates, JUtils/Source/JUtils/Actors/DelegateWrappers.h at master - jerobarraco/JUtils - Codeberg.org
it’s a different use case but can be an example.

1 Like

Thank you for the suggestion.

But I already fail at the definitions :frowning: The Unreal reflection system seem to fail to recognize the existence of the FViewport Class defined in UnrealClient.h. Sorry, I’m still a c++ novice.

#pragma once
#include "UnrealClient.h" // for ViewportResize event bind
#include "ExposedFunctionsBPLibrary.generated.h"

UCLASS()
class UExposedFunctionsBPLibrary : public UBlueprintFunctionLibrary
{
   DECLARE_DYNAMIC_MULTICAST_DELEGATE_TwoParams(FOnViewportResized, FViewport*, 
   Viewport, uint32, ViewportSize);

   UPROPERTY()
   FOnViewportResized OnViewportResize;
}
error : Unable to find 'class', 'delegate', 'enum', or 'struct' with name 'FViewport'

skip the viewport then. only declare one param, the size.
though i think you might be importing something wrong.
though, also, i wouldn’t expect that struct to be blueprintable.

I got help from a friendly fellow on Discord (@Philoko in the forums here) and we figured out a way without the wrapper.

.h

DECLARE_DYNAMIC_DELEGATE(FOnMyViewportSizeChange);

UFUNCTION(BlueprintCallable)
static void BindToViewportResizeEvent(const FOnMyViewportSizeChange& ViewportSizeChanged);

.cpp

void UExposedFunctionsBPLibrary::BindToViewportResizeEvent(const FOnMyViewportSizeChange& ViewportSizeChanged)
{
   FViewport::ViewportResizedEvent.AddUFunction(
       const_cast<FOnMyViewportSizeChange&>(ViewportSizeChanged).GetUObjectRef().Get(), 
       const_cast<FOnMyViewportSizeChange&>(ViewportSizeChanged).GetFunctionName());
}

In Blueprints I just use the globally available GetViewportSize when the event executes.
My functions are static since I’m defining them in a BlueprintFunctionLibrary.
My delegate has no parameters, since FViewport is no UPREPERTY() can not be used in Blueprint. And the uint32 ViewportSize seems to be unused in UE5.4. It is hard coded to 0, at all places it is called. One parameter name for it was ResizeCode. It’s either some leftover or something for the future.


The following code is an unsafe way, but it works too
.h

UFUNCTION(BlueprintCallable)
		static void BindToViewportResizeEvent(UObject* TargetObject, FName FunctionName);

.cpp

void UExposedFunctionsBPLibrary::BindToViewportResizeEvent(UObject* TargetObject, FName FunctionName)
{
    FViewport::ViewportResizedEvent.AddUFunction(TargetObject, FunctionName);
}

@Philoko looked into how AddUFunction works.

  • If I’m not mistaken then your blueprint function will be ultimately invoked in
void UObject::ProcessEvent(UFunction* Function, void* Parms)

(yes they actually misspelled “Params” and never fixed it )

  • The problem that I see is the line 2083 in ScriptCore.cpp (at least in UE 5.4; line numbers maybe different when the code changed in different engine version):
FMemory::Memcpy(Frame, Parms, Function->ParmsSize);
  • That means that what ever is passed as parameters to your blueprint function will just bit-wise copied from the calling event. In our case that would be a memory block that consists of FViewport* and uint32 plus probably some memory alignment. This is just “clamped” by Function->ParmsSize .

Conclusion:

  • As long as your blueprint function does not have any parameters this will actually work without issue.
  • It is not checked at any point if the signatures of the delegate and of the function actually match so you won’t get any error message.
  • When the blueprint function has any parameters and the signatures don’t match this can lead to all sorts of issues - probably crashes or worse.

I tested to add some parameters to a custom event in BP and it really reads out some numbers if you add something like an Integer or byte, but it crashes with an UObject as parameter.

1 Like