EM_Task/CoreUObject/Private/UObject/PropertyDelegate.cpp

202 lines
7.5 KiB
C++
Raw Permalink Normal View History

2026-02-13 16:18:33 +08:00
// Copyright Epic Games, Inc. All Rights Reserved.
#include "CoreMinimal.h"
#include "UObject/ObjectMacros.h"
#include "UObject/Class.h"
#include "UObject/UnrealType.h"
#include "UObject/UnrealTypePrivate.h"
#include "UObject/PropertyHelper.h"
#include "UObject/LinkerPlaceholderFunction.h"
#include "Serialization/ArchiveUObjectFromStructuredArchive.h"
// WARNING: This should always be the last include in any file that needs it (except .generated.h)
#include "UObject/UndefineUPropertyMacros.h"
/*-----------------------------------------------------------------------------
FDelegateProperty.
-----------------------------------------------------------------------------*/
IMPLEMENT_FIELD(FDelegateProperty)
#if WITH_EDITORONLY_DATA
FDelegateProperty::FDelegateProperty(UField* InField)
: FDelegateProperty_Super(InField)
{
UDelegateProperty* SourceProperty = CastChecked<UDelegateProperty>(InField);
SignatureFunction = SourceProperty->SignatureFunction;
}
#endif // WITH_EDITORONLY_DATA
void FDelegateProperty::PostDuplicate(const FField& InField)
{
const FDelegateProperty& Source = static_cast<const FDelegateProperty&>(InField);
SignatureFunction = Source.SignatureFunction;
Super::PostDuplicate(InField);
}
void FDelegateProperty::InstanceSubobjects(void* Data, void const* DefaultData, UObject* InOwner, FObjectInstancingGraph* InstanceGraph)
{
for (int32 i = 0; i < ArrayDim; i++)
{
FScriptDelegate& DestDelegate = ((FScriptDelegate*)Data)[i];
UObject* CurrentUObject = DestDelegate.GetUObject();
if (CurrentUObject)
{
UObject* Template = NULL;
if (DefaultData)
{
FScriptDelegate& DefaultDelegate = ((FScriptDelegate*)DefaultData)[i];
Template = DefaultDelegate.GetUObject();
}
UObject* NewUObject = InstanceGraph->InstancePropertyValue(Template, CurrentUObject, InOwner, HasAnyPropertyFlags(CPF_Transient), false, true);
DestDelegate.BindUFunction(NewUObject, DestDelegate.GetFunctionName());
}
}
}
bool FDelegateProperty::Identical(const void* A, const void* B, uint32 PortFlags) const
{
const FScriptDelegate* DA = (const FScriptDelegate*)A;
const FScriptDelegate* DB = (const FScriptDelegate*)B;
if (!DB)
{
return DA->GetFunctionName() == NAME_None;
}
if (DA->GetUObject() != DB->GetUObject())
{
return false;
}
if (DA->GetFunctionName() != DB->GetFunctionName())
{
return false;
}
return true;
}
void FDelegateProperty::SerializeItem(FStructuredArchive::FSlot Slot, void* Value, void const* Defaults) const
{
Slot << *GetPropertyValuePtr(Value);
}
bool FDelegateProperty::NetSerializeItem(FArchive& Ar, UPackageMap* Map, void* Data, TArray<uint8>* MetaData) const
{
// Do not allow replication of delegates, as there is no way to make this secure (it allows the execution of any function in any object, on the remote client/server)
return 1;
}
FString FDelegateProperty::GetCPPType(FString* ExtendedTypeText /*=NULL*/, uint32 CPPExportFlags /*=0*/) const
{
check(SignatureFunction);
FString UnmangledFunctionName = SignatureFunction->GetName().LeftChop(FString(HEADER_GENERATED_DELEGATE_SIGNATURE_SUFFIX).Len());
const bool bBlueprintCppBackend = (0 != (CPPExportFlags & EPropertyExportCPPFlags::CPPF_BlueprintCppBackend));
const bool bNative = SignatureFunction->IsNative();
if (bBlueprintCppBackend && bNative)
{
UStruct* StructOwner = Cast<UStruct>(SignatureFunction->GetOuter());
if (StructOwner)
{
return FString::Printf(TEXT("%s%s::F%s"), StructOwner->GetPrefixCPP(), *StructOwner->GetName(), *UnmangledFunctionName);
}
}
else
{
const bool NonNativeClassOwner = (SignatureFunction->GetOwnerClass() && !SignatureFunction->GetOwnerClass()->HasAnyClassFlags(CLASS_Native));
if (bBlueprintCppBackend && NonNativeClassOwner)
{
// The name must be valid, this removes spaces, ?, etc from the user's function name. It could
// be slightly shorter because the postfix ("__pf") is not needed here because we further post-
// pend to the string. Normally the postfix is needed to make sure we don't mangle to a valid
// identifier and collide:
UnmangledFunctionName = UnicodeToCPPIdentifier(UnmangledFunctionName, false, TEXT(""));
// the name must be unique
const FString OwnerName = UnicodeToCPPIdentifier(SignatureFunction->GetOwnerClass()->GetName(), false, TEXT(""));
const FString NewUnmangledFunctionName = FString::Printf(TEXT("%s__%s"), *UnmangledFunctionName, *OwnerName);
UnmangledFunctionName = NewUnmangledFunctionName;
}
if (0 != (CPPExportFlags & EPropertyExportCPPFlags::CPPF_CustomTypeName))
{
UnmangledFunctionName += TEXT("__SinglecastDelegate");
}
}
return FString(TEXT("F")) + UnmangledFunctionName;
}
FString FDelegateProperty::GetCPPTypeForwardDeclaration() const
{
return FString();
}
void FDelegateProperty::ExportTextItem(FString& ValueStr, const void* PropertyValue, const void* DefaultValue, UObject* Parent, int32 PortFlags, UObject* ExportRootScope) const
{
if (0 != (PortFlags & PPF_ExportCpp))
{
ValueStr += TEXT("{}");
return;
}
FScriptDelegate* ScriptDelegate = (FScriptDelegate*)PropertyValue;
check(ScriptDelegate != NULL);
bool bDelegateHasValue = ScriptDelegate->GetFunctionName() != NAME_None;
ValueStr += FString::Printf(TEXT("%s.%s"),
ScriptDelegate->GetUObject() != NULL ? *ScriptDelegate->GetUObject()->GetName() : TEXT("(null)"),
*ScriptDelegate->GetFunctionName().ToString());
}
const TCHAR* FDelegateProperty::ImportText_Internal(const TCHAR* Buffer, void* PropertyValue, int32 PortFlags, UObject* Parent, FOutputDevice* ErrorText) const
{
return DelegatePropertyTools::ImportDelegateFromText(*(FScriptDelegate*)PropertyValue, SignatureFunction, Buffer, Parent, ErrorText);
}
void FDelegateProperty::Serialize(FArchive& Ar)
{
Super::Serialize(Ar);
Ar << SignatureFunction;
#if USE_CIRCULAR_DEPENDENCY_LOAD_DEFERRING
if (Ar.IsLoading() || Ar.IsObjectReferenceCollector())
{
if (auto PlaceholderFunc = Cast<ULinkerPlaceholderFunction>(SignatureFunction))
{
PlaceholderFunc->AddReferencingProperty(this);
}
}
#endif // USE_CIRCULAR_DEPENDENCY_LOAD_DEFERRING
}
void FDelegateProperty::AddReferencedObjects(FReferenceCollector& Collector)
{
#if USE_CIRCULAR_DEPENDENCY_LOAD_DEFERRING
if (SignatureFunction && !SignatureFunction->IsA<ULinkerPlaceholderFunction>())
#endif // USE_CIRCULAR_DEPENDENCY_LOAD_DEFERRING
{
Collector.AddReferencedObject(SignatureFunction);
}
Super::AddReferencedObjects(Collector);
}
bool FDelegateProperty::SameType(const FProperty* Other) const
{
return Super::SameType(Other) && (SignatureFunction == ((FDelegateProperty*)Other)->SignatureFunction);
}
void FDelegateProperty::BeginDestroy()
{
#if USE_CIRCULAR_DEPENDENCY_LOAD_DEFERRING
if (auto PlaceholderFunc = Cast<ULinkerPlaceholderFunction>(SignatureFunction))
{
PlaceholderFunc->RemoveReferencingProperty(this);
}
#endif // USE_CIRCULAR_DEPENDENCY_LOAD_DEFERRING
Super::BeginDestroy();
}
#include "UObject/DefineUPropertyMacros.h"