EM_Task/CoreUObject/Private/UObject/FieldPathProperty.cpp

196 lines
5.9 KiB
C++
Raw Permalink Normal View History

2026-02-13 16:18:33 +08:00
// Copyright Epic Games, Inc. All Rights Reserved.
#include "UObject/FieldPathProperty.h"
#include "UObject/PropertyPortFlags.h"
#include "UObject/Package.h"
#include "UObject/UnrealTypePrivate.h"
#include "UObject/LinkerLoad.h"
#include "UObject/ConstructorHelpers.h"
#include "Misc/Parse.h"
#include "UObject/PropertyHelper.h"
// WARNING: This should always be the last include in any file that needs it (except .generated.h)
#include "UObject/UndefineUPropertyMacros.h"
IMPLEMENT_FIELD(FFieldPathProperty)
#if WITH_EDITORONLY_DATA
FFieldPathProperty::FFieldPathProperty(UField* InField)
: FFieldPathProperty_Super(InField), PropertyClass(nullptr)
{
check(InField);
PropertyClass = FFieldClass::GetNameToFieldClassMap().FindRef(InField->GetClass()->GetFName());
}
#endif // WITH_EDITORONLY_DATA
EConvertFromTypeResult FFieldPathProperty::ConvertFromType(const FPropertyTag& Tag, FStructuredArchive::FSlot Slot, uint8* Data, UStruct* DefaultsStruct)
{
// Convert UProperty object to TFieldPath
if (Tag.Type == NAME_ObjectProperty)
{
FArchive& UnderlyingArchive = Slot.GetUnderlyingArchive();
check(UnderlyingArchive.IsLoading() && UnderlyingArchive.IsPersistent());
FLinker* Linker = UnderlyingArchive.GetLinker();
check(Linker);
FFieldPath ConvertedValue;
FPackageIndex Index;
UnderlyingArchive << Index;
bool bExport = Index.IsExport();
while (!Index.IsNull())
{
const FObjectResource& Res = Linker->ImpExp(Index);
ConvertedValue.Path.Add(Res.ObjectName);
Index = Res.OuterIndex;
}
if (bExport)
{
check(Linker->LinkerRoot);
ConvertedValue.Path.Add(Linker->LinkerRoot->GetFName());
}
if (ConvertedValue.Path.Num())
{
ConvertedValue.ConvertFromFullPath(Cast<FLinkerLoad>(Linker));
}
SetPropertyValue_InContainer(Data, ConvertedValue, Tag.ArrayIndex);
return EConvertFromTypeResult::Converted;
}
return EConvertFromTypeResult::UseSerializeItem;
}
bool FFieldPathProperty::Identical(const void* A, const void* B, uint32 PortFlags) const
{
const FFieldPath ValueA = GetPropertyValue(A);
if (B)
{
const FFieldPath ValueB = GetPropertyValue(B);
return ValueA == ValueB;
}
return !ValueA.GetTyped(FField::StaticClass());
}
void FFieldPathProperty::SerializeItem(FStructuredArchive::FSlot Slot, void* Value, void const* Defaults) const
{
FFieldPath* FieldPtr = GetPropertyValuePtr(Value);
Slot << *FieldPtr;
}
void FFieldPathProperty::ExportTextItem(FString& ValueStr, const void* PropertyValue, const void* DefaultValue, UObject* Parent, int32 PortFlags, UObject* ExportRootScope) const
{
const FFieldPath& Value = GetPropertyValue(PropertyValue);
if (PortFlags & PPF_ExportCpp)
{
ValueStr += TEXT("TEXT(\"");
ValueStr += Value.ToString();
ValueStr += TEXT("\")");
}
else if (PortFlags & PPF_PropertyWindow)
{
if (PortFlags & PPF_Delimited)
{
ValueStr += TEXT("\"");
ValueStr += Value.ToString();
ValueStr += TEXT("\"");
}
else
{
ValueStr += Value.ToString();
}
}
else
{
ValueStr += Value.ToString();
}
}
const TCHAR* FFieldPathProperty::ImportText_Internal(const TCHAR* Buffer, void* Data, int32 PortFlags, UObject* Parent, FOutputDevice* ErrorText) const
{
check(Buffer);
FFieldPath* PathPtr = GetPropertyValuePtr(Data);
check(PathPtr);
FString PathName;
if (!(PortFlags & PPF_Delimited))
{
PathName = Buffer;
// in order to indicate that the value was successfully imported, advance the buffer past the last character that was imported
Buffer += PathName.Len();
}
else
{
// Advance to the next delimiter (comma) or the end of the buffer
int32 SeparatorIndex = 0;
while (Buffer[SeparatorIndex] != '\0' && Buffer[SeparatorIndex] != ',' && Buffer[SeparatorIndex] != ')')
{
++SeparatorIndex;
}
// Copy the value string
PathName = FString(SeparatorIndex, Buffer);
// Advance the buffer to let the calling function know we succeeded
Buffer += SeparatorIndex;
}
if (PathName.Len())
{
// Strip the class name if present, we don't need it
ConstructorHelpers::StripObjectClass(PathName);
if (PathName[0] == '\"')
{
FString UnquotedPathName;
if (!FParse::QuotedString(*PathName, UnquotedPathName))
{
UE_LOG(LogProperty, Warning, TEXT("FieldPathProperty: Bad quoted string: %s"), *PathName);
return nullptr;
}
PathName = MoveTemp(UnquotedPathName);
}
PathPtr->Generate(*PathName);
}
return Buffer;
}
void FFieldPathProperty::Serialize(FArchive& Ar)
{
Super::Serialize(Ar);
Ar << PropertyClass;
}
FString FFieldPathProperty::GetCPPMacroType(FString& ExtendedTypeText) const
{
check(PropertyClass);
ExtendedTypeText = FString::Printf(TEXT("TFieldPath<F%s>"), *PropertyClass->GetName());
return TEXT("STRUCT");
}
FString FFieldPathProperty::GetCPPTypeForwardDeclaration() const
{
check(PropertyClass);
return FString::Printf(TEXT("class F%s;"), *PropertyClass->GetName());
}
FString FFieldPathProperty::GetCPPType(FString* ExtendedTypeText, uint32 CPPExportFlags) const
{
checkSlow(PropertyClass);
if (ExtendedTypeText != nullptr)
{
FString& InnerTypeText = *ExtendedTypeText;
InnerTypeText = TEXT("<F");
InnerTypeText += PropertyClass->GetName();
InnerTypeText += TEXT(">");
}
return TEXT("TFieldPath");
}
bool FFieldPathProperty::SupportsNetSharedSerialization() const
{
return false;
}
#include "UObject/DefineUPropertyMacros.h"