// 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(InField); SignatureFunction = SourceProperty->SignatureFunction; } #endif // WITH_EDITORONLY_DATA void FDelegateProperty::PostDuplicate(const FField& InField) { const FDelegateProperty& Source = static_cast(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* 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(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(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()) #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(SignatureFunction)) { PlaceholderFunc->RemoveReferencingProperty(this); } #endif // USE_CIRCULAR_DEPENDENCY_LOAD_DEFERRING Super::BeginDestroy(); } #include "UObject/DefineUPropertyMacros.h"