I got help from a friendly fellow on Discord 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);
}
The friendly fellow 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*
anduint32
plus probably some memory alignment. This is just “clamped” byFunction->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.