EM_Task/CoreUObject/Private/UObject/PropertyClass.cpp

181 lines
6.9 KiB
C++
Raw 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 "Templates/Casts.h"
#include "UObject/UnrealType.h"
#include "UObject/UnrealTypePrivate.h"
#include "UObject/LinkerPlaceholderClass.h"
#include "Misc/ConfigCacheIni.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"
/*-----------------------------------------------------------------------------
FClassProperty.
-----------------------------------------------------------------------------*/
IMPLEMENT_FIELD(FClassProperty)
#if WITH_EDITORONLY_DATA
FClassProperty::FClassProperty(UField* InField)
: FObjectProperty(InField)
{
UClassProperty* SourceProperty = CastChecked<UClassProperty>(InField);
MetaClass = SourceProperty->MetaClass;
}
#endif // WITH_EDITORONLY_DATA
void FClassProperty::BeginDestroy()
{
#if USE_CIRCULAR_DEPENDENCY_LOAD_DEFERRING
if (ULinkerPlaceholderClass* PlaceholderClass = Cast<ULinkerPlaceholderClass>(MetaClass))
{
PlaceholderClass->RemoveReferencingProperty(this);
}
#endif // USE_CIRCULAR_DEPENDENCY_LOAD_DEFERRING
Super::BeginDestroy();
}
void FClassProperty::PostDuplicate(const FField& InField)
{
const FClassProperty& Source = static_cast<const FClassProperty&>(InField);
MetaClass = Source.MetaClass;
Super::PostDuplicate(InField);
}
void FClassProperty::Serialize(FArchive& Ar)
{
Super::Serialize(Ar);
Ar << MetaClass;
#if USE_CIRCULAR_DEPENDENCY_LOAD_DEFERRING
if (Ar.IsLoading() || Ar.IsObjectReferenceCollector())
{
if (ULinkerPlaceholderClass* PlaceholderClass = Cast<ULinkerPlaceholderClass>(MetaClass))
{
PlaceholderClass->AddReferencingProperty(this);
}
}
#endif // USE_CIRCULAR_DEPENDENCY_LOAD_DEFERRING
if (!MetaClass)
{
// If we failed to load the MetaClass and we're not a CDO, that means we relied on a class that has been removed or doesn't exist.
// The most likely cause for this is either an incomplete recompile, or if content was migrated between games that had native class dependencies
// that do not exist in this game. We allow blueprint classes to continue, because compile on load will error out, and stub the class that was using it
UClass* TestClass = dynamic_cast<UClass*>(GetOwnerStruct());
if (TestClass && TestClass->HasAllClassFlags(CLASS_Native) && !TestClass->HasAllClassFlags(CLASS_NewerVersionExists) && (TestClass->GetOutermost() != GetTransientPackage()))
{
checkf(false, TEXT("Class property tried to serialize a missing class. Did you remove a native class and not fully recompile?"));
}
}
}
#if USE_CIRCULAR_DEPENDENCY_LOAD_DEFERRING
void FClassProperty::SetMetaClass(UClass* NewMetaClass)
{
if (ULinkerPlaceholderClass* NewPlaceholderClass = Cast<ULinkerPlaceholderClass>(NewMetaClass))
{
NewPlaceholderClass->AddReferencingProperty(this);
}
if (ULinkerPlaceholderClass* OldPlaceholderClass = Cast<ULinkerPlaceholderClass>(MetaClass))
{
OldPlaceholderClass->RemoveReferencingProperty(this);
}
MetaClass = NewMetaClass;
}
#endif // USE_CIRCULAR_DEPENDENCY_LOAD_DEFERRING
void FClassProperty::AddReferencedObjects(FReferenceCollector& Collector)
{
Collector.AddReferencedObject(MetaClass);
Super::AddReferencedObjects(Collector);
}
const TCHAR* FClassProperty::ImportText_Internal(const TCHAR* Buffer, void* Data, int32 PortFlags, UObject* Parent, FOutputDevice* ErrorText) const
{
const TCHAR* Result = FObjectProperty::ImportText_Internal(Buffer, Data, PortFlags, Parent, ErrorText);
if (Result)
{
if (UClass* AssignedPropertyClass = dynamic_cast<UClass*>(GetObjectPropertyValue(Data)))
{
#if USE_CIRCULAR_DEPENDENCY_LOAD_DEFERRING
FLinkerLoad* ObjectLinker = (Parent != nullptr) ? Parent->GetClass()->GetLinker() : GetLinker();
auto IsDeferringValueLoad = [](const UClass* Class) -> bool
{
const ULinkerPlaceholderClass* Placeholder = Cast<ULinkerPlaceholderClass>(Class);
return Placeholder && !Placeholder->IsMarkedResolved();
};
const bool bIsDeferringValueLoad = IsDeferringValueLoad(MetaClass) || ((!ObjectLinker || (ObjectLinker->LoadFlags & LOAD_DeferDependencyLoads) != 0) && IsDeferringValueLoad(AssignedPropertyClass));
#if USE_DEFERRED_DEPENDENCY_CHECK_VERIFICATION_TESTS
check(bIsDeferringValueLoad || !(Cast<ULinkerPlaceholderClass>(MetaClass) || Cast<ULinkerPlaceholderClass>(AssignedPropertyClass)));
#endif // USE_DEFERRED_DEPENDENCY_CHECK_VERIFICATION_TESTS
#else // USE_CIRCULAR_DEPENDENCY_LOAD_DEFERRING
bool const bIsDeferringValueLoad = false;
#endif // USE_CIRCULAR_DEPENDENCY_LOAD_DEFERRING
// Validate metaclass.
if ((!AssignedPropertyClass->IsChildOf(MetaClass)) && !bIsDeferringValueLoad)
{
// the object we imported doesn't implement our interface class
ErrorText->Logf(TEXT("Invalid object '%s' specified for property '%s'"), *AssignedPropertyClass->GetFullName(), *GetName());
SetObjectPropertyValue(Data, NULL);
Result = NULL;
}
}
}
return Result;
}
FString FClassProperty::GetCPPType(FString* ExtendedTypeText, uint32 CPPExportFlags) const
{
check(MetaClass);
return GetCPPTypeCustom(ExtendedTypeText, CPPExportFlags,
FString::Printf(TEXT("%s%s"), MetaClass->GetPrefixCPP(), *MetaClass->GetName()));
}
FString FClassProperty::GetCPPTypeCustom(FString* ExtendedTypeText, uint32 CPPExportFlags, const FString& InnerNativeTypeName) const
{
if (PropertyFlags & CPF_UObjectWrapper)
{
ensure(!InnerNativeTypeName.IsEmpty());
return FString::Printf(TEXT("TSubclassOf<%s> "), *InnerNativeTypeName);
}
else
{
return TEXT("UClass*");
}
}
FString FClassProperty::GetCPPTypeForwardDeclaration() const
{
return FString::Printf(TEXT("class %s%s;"), MetaClass->GetPrefixCPP(), *MetaClass->GetName());
}
FString FClassProperty::GetCPPMacroType(FString& ExtendedTypeText) const
{
ExtendedTypeText = TEXT("UClass");
return TEXT("OBJECT");
}
bool FClassProperty::SameType(const FProperty* Other) const
{
return Super::SameType(Other) && (MetaClass == ((FClassProperty*)Other)->MetaClass);
}
bool FClassProperty::Identical(const void* A, const void* B, uint32 PortFlags) const
{
UObject* ObjectA = A ? GetObjectPropertyValue(A) : nullptr;
UObject* ObjectB = B ? GetObjectPropertyValue(B) : nullptr;
check(ObjectA == nullptr || ObjectA->IsA<UClass>());
check(ObjectB == nullptr || ObjectB->IsA<UClass>());
return (ObjectA == ObjectB);
}
#include "UObject/DefineUPropertyMacros.h"