FArchive& FArchiveDescribeReference::operator<<( class UObject*& Obj ) { if (Obj == Target) { if (GSerializedProperty) { Output.Logf(TEXT(" [%s]"), *GSerializedProperty->GetFullName()); } else { Output.Logf(TEXT(" [native]")); } PTRINT BigOffset = ((uint8*)&Obj) - (uint8*)Source; if (BigOffset > 0 && BigOffset < Source->GetClass()->GetPropertiesSize()) { int32 Offset = int32(BigOffset); UClass* UseClass = Source->GetClass(); UClass* SuperClass = UseClass->GetSuperClass(); while (1) { if (!SuperClass || Offset >= SuperClass->GetPropertiesSize()) { break; } UseClass = SuperClass; SuperClass = UseClass->GetSuperClass(); } Output.Logf(TEXT(" class %s offset %d, offset from UObject %d "), *UseClass->GetName(), SuperClass ? Offset - SuperClass->GetPropertiesSize() : Offset, Offset); } } return *this; }
UActorFactory* FPlacementMode::FindLastUsedFactoryForAssetType( UObject* Asset ) const { if ( Asset == NULL ) { return NULL; } UActorFactory* LastUsedFactory = NULL; UClass* CurrentClass = Cast<UClass>( Asset ); if ( CurrentClass == NULL ) { CurrentClass = Asset->GetClass(); } while ( LastUsedFactory == NULL && CurrentClass != NULL && CurrentClass != UClass::StaticClass() ) { const TWeakObjectPtr< UActorFactory >* FoundFactory = AssetTypeToFactory.Find( *CurrentClass->GetPathName() ); if ( FoundFactory != NULL && FoundFactory->IsValid() ) { LastUsedFactory = FoundFactory->Get(); } else { CurrentClass = CurrentClass->GetSuperClass(); } } return LastUsedFactory; }
FText FSimpleAssetEditor::GetToolkitName() const { const TArray<UObject*>& EditingObjs = GetEditingObjects(); check( EditingObjs.Num() > 0 ); FFormatNamedArguments Args; Args.Add( TEXT("ToolkitName"), GetBaseToolkitName() ); if( EditingObjs.Num() == 1 ) { const UObject* EditingObject = EditingObjs[ 0 ]; const bool bDirtyState = EditingObject->GetOutermost()->IsDirty(); Args.Add( TEXT("ObjectName"), FText::FromString( EditingObject->GetName() ) ); Args.Add( TEXT("DirtyState"), bDirtyState ? FText::FromString( TEXT( "*" ) ) : FText::GetEmpty() ); return FText::Format( LOCTEXT("ToolkitTitle", "{ObjectName}{DirtyState} - {ToolkitName}"), Args ); } else { bool bDirtyState = false; UClass* SharedBaseClass = nullptr; for( int32 x = 0; x < EditingObjs.Num(); ++x ) { UObject* Obj = EditingObjs[ x ]; check( Obj ); UClass* ObjClass = Cast<UClass>(Obj); if (ObjClass == nullptr) { ObjClass = Obj->GetClass(); } check( ObjClass ); // Initialize with the class of the first object we encounter. if( SharedBaseClass == nullptr ) { SharedBaseClass = ObjClass; } // If we've encountered an object that's not a subclass of the current best baseclass, // climb up a step in the class hierarchy. while( !ObjClass->IsChildOf( SharedBaseClass ) ) { SharedBaseClass = SharedBaseClass->GetSuperClass(); } // If any of the objects are dirty, flag the label bDirtyState |= Obj->GetOutermost()->IsDirty(); } check(SharedBaseClass); Args.Add( TEXT("NumberOfObjects"), EditingObjs.Num() ); Args.Add( TEXT("ClassName"), FText::FromString( SharedBaseClass->GetName() ) ); Args.Add( TEXT("DirtyState"), bDirtyState ? FText::FromString( TEXT( "*" ) ) : FText::GetEmpty() ); return FText::Format( LOCTEXT("ToolkitTitle_EditingMultiple", "{NumberOfObjects} {ClassName}{DirtyState} - {ToolkitName}"), Args ); } }
FPrimaryAssetId AAFCueActor::GetPrimaryAssetId() const { FName dupa1 = FPackageName::GetShortFName(GetOutermost()->GetFName()); const AAFCueActor* A = this; return FPrimaryAssetId(FPrimaryAssetType("ActorCue"), dupa1); //if (HasAnyFlags(RF_ClassDefaultObject)) { UClass* SearchNativeClass = GetClass(); while (SearchNativeClass && !SearchNativeClass->HasAnyClassFlags(CLASS_Native | CLASS_Intrinsic)) { SearchNativeClass = SearchNativeClass->GetSuperClass(); } if (SearchNativeClass && SearchNativeClass != GetClass()) { // If blueprint, return native class and asset name } // Native CDO, return nothing return FPrimaryAssetId(); } // Data assets use Class and ShortName by default, there's no inheritance so class works fine //return FPrimaryAssetId(GetClass()->GetFName(), GetFName()); }
FName FClassIconFinder::FindIconNameForClass(UClass* InClass, const FName& InDefaultName ) { FName BrushName = InDefaultName; const FSlateBrush* Brush = NULL; if ( InClass != NULL ) { // walk up class hierarchy until we find an icon UClass* ActorClass = InClass; while( (Brush == NULL || Brush == FEditorStyle::GetDefaultBrush()) && ActorClass && (ActorClass != AActor::StaticClass()) ) { BrushName = *FString::Printf( TEXT( "ClassIcon.%s" ), *ActorClass->GetName() ); Brush = FEditorStyle::GetBrush( BrushName ); ActorClass = ActorClass->GetSuperClass(); } } if( Brush == NULL || Brush == FEditorStyle::GetDefaultBrush() ) { // If we didn't supply an override name for the default icon use default class icon. if( InDefaultName == "" ) { BrushName = TEXT( "ClassIcon.Default" ); } else { BrushName = InDefaultName; } } return BrushName; }
UField* FMemberReference::FindRemappedField(UClass* InitialScope, FName InitialName, bool bInitialScopeMustBeOwnerOfField) { FFieldRemapInfo NewFieldInfo; bool bFoundReplacement = false; // Step up the class chain to check if us or any of our parents specify a redirect UClass* TestRemapClass = InitialScope; while( TestRemapClass != NULL ) { if( FindReplacementFieldName(TestRemapClass, InitialName, NewFieldInfo) ) { // Found it, stop our search bFoundReplacement = true; break; } TestRemapClass = TestRemapClass->GetSuperClass(); } // In the case of a bifurcation of a variable (e.g. moved from a parent into certain children), verify that we don't also define the variable in the current scope first if( bFoundReplacement && (FindField<UField>(InitialScope, InitialName) != nullptr)) { bFoundReplacement = false; } if( bFoundReplacement ) { const FName NewFieldName = NewFieldInfo.FieldName; UClass* SearchClass = (NewFieldInfo.FieldClass != NAME_None) ? (UClass*)StaticFindObject(UClass::StaticClass(), ANY_PACKAGE, *NewFieldInfo.FieldClass.ToString()) : (UClass*)TestRemapClass; // Find the actual field specified by the redirector, so we can return it and update the node that uses it UField* NewField = FindField<UField>(SearchClass, NewFieldInfo.FieldName); if( NewField != NULL ) { if (bInitialScopeMustBeOwnerOfField && !InitialScope->IsChildOf(SearchClass)) { UE_LOG(LogBlueprint, Log, TEXT("UK2Node: Unable to update field. Remapped field '%s' in not owned by given scope. Scope: '%s', Owner: '%s'."), *InitialName.ToString(), *InitialScope->GetName(), *NewFieldInfo.FieldClass.ToString()); } else { UE_LOG(LogBlueprint, Log, TEXT("UK2Node: Fixed up old field '%s' to new name '%s' on class '%s'."), *InitialName.ToString(), *NewFieldInfo.FieldName.ToString(), *SearchClass->GetName()); return NewField; } } else if (SearchClass != NULL) { UE_LOG(LogBlueprint, Log, TEXT("UK2Node: Unable to find updated field name for '%s' on class '%s'."), *InitialName.ToString(), *SearchClass->GetName()); } else { UE_LOG(LogBlueprint, Log, TEXT("UK2Node: Unable to find updated field name for '%s' on unknown class '%s'."), *InitialName.ToString(), *NewFieldInfo.FieldClass.ToString()); } } return NULL; }
/** * Gathers all blueprints for the actors in question, outputting them to the classes array */ void GatherBlueprintsForActors( TArray< AActor* >& Actors, TArray< FMenuBlueprintClass >& Classes ) { struct Local { static void AddBlueprint( TArray< FMenuBlueprintClass >& InClasses, const FString& ClassName, UBlueprint* Blueprint = NULL ) { check( !ClassName.IsEmpty() ); // Check to see if we already have this class name in our list FMenuBlueprintClass* FoundClass = NULL; for( int32 CurClassIndex = 0; CurClassIndex < InClasses.Num(); ++CurClassIndex ) { FMenuBlueprintClass& CurClass = InClasses[ CurClassIndex ]; if( CurClass.Name == ClassName ) { FoundClass = &CurClass; break; } } // Add a new class to our list if we need to if( FoundClass == NULL ) { FoundClass = new( InClasses ) FMenuBlueprintClass(); FoundClass->Name = ClassName; FoundClass->Blueprint = Blueprint; } else { check(FoundClass->Blueprint.Get() == Blueprint); } } }; for( TArray< AActor* >::TIterator It( Actors ); It; ++It ) { AActor* Actor = static_cast<AActor*>( *It ); checkSlow( Actor->IsA(AActor::StaticClass()) ); // Grab the class of this actor UClass* ActorClass = Actor->GetClass(); check( ActorClass != NULL ); // Walk the inheritance hierarchy for this class for( UClass* CurClass = ActorClass; CurClass != NULL; CurClass = CurClass->GetSuperClass() ) { if (UBlueprint* Blueprint = Cast<UBlueprint>(CurClass->ClassGeneratedBy)) { // Class was created by a blueprint, so don't offer C++ editing of functions declared in it // Instead offer to edit the events and graphs of the blueprint Local::AddBlueprint( Classes, CurClass->GetName(), Blueprint ); } } } }
void FHotReloadClassReinstancer::SetupNewClassReinstancing(UClass* InNewClass, UClass* InOldClass) { // Set base class members to valid values ClassToReinstance = InNewClass; DuplicatedClass = InOldClass; OriginalCDO = InOldClass->GetDefaultObject(); bHasReinstanced = false; bSkipGarbageCollection = false; bNeedsReinstancing = true; NewClass = InNewClass; // Collect the original CDO property values SerializeCDOProperties(InOldClass->GetDefaultObject(), OriginalCDOProperties); // Collect the property values of the new CDO SerializeCDOProperties(InNewClass->GetDefaultObject(), ReconstructedCDOProperties); SaveClassFieldMapping(InOldClass); ObjectsThatShouldUseOldStuff.Add(InOldClass); //CDO of REINST_ class can be used as archetype TArray<UClass*> ChildrenOfClass; GetDerivedClasses(InOldClass, ChildrenOfClass); for (auto ClassIt = ChildrenOfClass.CreateConstIterator(); ClassIt; ++ClassIt) { UClass* ChildClass = *ClassIt; UBlueprint* ChildBP = Cast<UBlueprint>(ChildClass->ClassGeneratedBy); if (ChildBP && !ChildBP->HasAnyFlags(RF_BeingRegenerated)) { // If this is a direct child, change the parent and relink so the property chain is valid for reinstancing if (!ChildBP->HasAnyFlags(RF_NeedLoad)) { if (ChildClass->GetSuperClass() == InOldClass) { ReparentChild(ChildBP); } Children.AddUnique(ChildBP); if (ChildBP->ParentClass == InOldClass) { ChildBP->ParentClass = NewClass; } } else { // If this is a child that caused the load of their parent, relink to the REINST class so that we can still serialize in the CDO, but do not add to later processing ReparentChild(ChildClass); } } } // Finally, remove the old class from Root so that it can get GC'd and mark it as CLASS_NewerVersionExists InOldClass->RemoveFromRoot(); InOldClass->ClassFlags |= CLASS_NewerVersionExists; }
FString UInterfaceProperty::GetCPPTypeForwardDeclaration() const { checkSlow(InterfaceClass); UClass* ExportClass = InterfaceClass; while (ExportClass && !ExportClass->HasAnyClassFlags(CLASS_Native)) { ExportClass = ExportClass->GetSuperClass(); } check(ExportClass); check(ExportClass->HasAnyClassFlags(CLASS_Interface)); return FString::Printf(TEXT("class I%s;"), *ExportClass->GetName()); }
FText FSimpleAssetEditor::GetToolkitToolTipText() const { const TArray<UObject*>& EditingObjs = GetEditingObjects(); check( EditingObjs.Num() > 0 ); FFormatNamedArguments Args; Args.Add( TEXT("ToolkitName"), GetBaseToolkitName() ); if( EditingObjs.Num() == 1 ) { const UObject* EditingObject = EditingObjs[ 0 ]; return FAssetEditorToolkit::GetToolTipTextForObject(EditingObject); } else { UClass* SharedBaseClass = NULL; for( int32 x = 0; x < EditingObjs.Num(); ++x ) { UObject* Obj = EditingObjs[ x ]; check( Obj ); UClass* ObjClass = Cast<UClass>(Obj); if (ObjClass == nullptr) { ObjClass = Obj->GetClass(); } check( ObjClass ); // Initialize with the class of the first object we encounter. if( SharedBaseClass == nullptr ) { SharedBaseClass = ObjClass; } // If we've encountered an object that's not a subclass of the current best baseclass, // climb up a step in the class hierarchy. while( !ObjClass->IsChildOf( SharedBaseClass ) ) { SharedBaseClass = SharedBaseClass->GetSuperClass(); } } check(SharedBaseClass); Args.Add( TEXT("NumberOfObjects"), EditingObjs.Num() ); Args.Add( TEXT("ClassName"), FText::FromString( SharedBaseClass->GetName() ) ); return FText::Format( LOCTEXT("ToolkitTitle_EditingMultipleToolTip", "{NumberOfObjects} {ClassName} - {ToolkitName}"), Args ); } }
/** * Returns the text to use for exporting this property to header file. * * @param ExtendedTypeText for property types which use templates, will be filled in with the type * @param CPPExportFlags flags for modifying the behavior of the export */ FString UInterfaceProperty::GetCPPMacroType( FString& ExtendedTypeText ) const { checkSlow(InterfaceClass); UClass* ExportClass = InterfaceClass; while ( ExportClass && !ExportClass->HasAnyClassFlags(CLASS_Native) ) { ExportClass = ExportClass->GetSuperClass(); } check(ExportClass); check(ExportClass->HasAnyClassFlags(CLASS_Interface)); ExtendedTypeText = FString::Printf(TEXT("I%s"), *ExportClass->GetName()); return TEXT("TINTERFACE"); }
//------------------------------------------------------------------------------ static UClass* BlueprintActionMenuUtilsImpl::FindCommonBaseClass(TArray<UObject*> const& ObjectSet) { UClass* CommonClass = UObject::StaticClass(); if (ObjectSet.Num() > 0) { CommonClass = ObjectSet[0]->GetClass(); for (UObject const* Object : ObjectSet) { UClass* Class = Object->GetClass(); while (!Class->IsChildOf(CommonClass)) { CommonClass = CommonClass->GetSuperClass(); } } } return CommonClass; }
void FClassBrowseHelper::BuildClassGraph() { UClass* RootNodeClass = UBTNode::StaticClass(); TArray<TSharedPtr<FClassDataNode> > NodeList; RootNode.Reset(); // gather all native classes for (TObjectIterator<UClass> It; It; ++It) { UClass* TestClass = *It; if (TestClass->HasAnyClassFlags(CLASS_Native) && TestClass->IsChildOf(RootNodeClass)) { TSharedPtr<FClassDataNode> NewNode = MakeShareable(new FClassDataNode); NewNode->ParentClassName = TestClass->GetSuperClass()->GetName(); FClassData NewData(TestClass); NewNode->Data = NewData; if (TestClass == RootNodeClass) { RootNode = NewNode; } NodeList.Add(NewNode); } } // gather all blueprints FAssetRegistryModule& AssetRegistryModule = FModuleManager::LoadModuleChecked<FAssetRegistryModule>(TEXT("AssetRegistry")); TArray<FAssetData> BlueprintList; FARFilter Filter; Filter.ClassNames.Add(UBlueprint::StaticClass()->GetFName()); AssetRegistryModule.Get().GetAssets(Filter, BlueprintList); for (int32 i = 0; i < BlueprintList.Num(); i++) { TSharedPtr<FClassDataNode> NewNode = CreateClassDataNode(BlueprintList[i]); NodeList.Add(NewNode); } // build class tree AddClassGraphChildren(RootNode, NodeList); }
const UClass* FCSharpWrapperGenerator::GetWrapperSuperClass( const UClass* Class, const TArray<const UClass*>& ExportedClasses ) { // mirror the inheritance in the managed wrapper class while skipping base classes that haven't // been exported (this may change in the future) UClass* superClass = nullptr; // find the top-most exported ancestor in the inheritance hierarchy for (UClass* currentAncestor = Class->GetSuperClass(); currentAncestor;) { if (ExportedClasses.Contains(currentAncestor)) { superClass = currentAncestor; } currentAncestor = currentAncestor->GetSuperClass(); } return superClass; }
/** Find set of components that support this asset */ FComponentClassList FComponentAssetBrokerage::GetComponentsForAsset(const UObject* InAsset) { InitializeMap(); FComponentClassList OutClasses; if (InAsset != NULL) { for (UClass* Class = InAsset->GetClass(); Class != UObject::StaticClass(); Class = Class->GetSuperClass()) { if (FComponentClassList* pTypesForClass = AssetToComponentClassMap.Find(Class)) { OutClasses.Append(*pTypesForClass); } } } return OutClasses; }
unreal::UIntPtr unreal::helpers::ClassMap_obj::wrap(unreal::UIntPtr inUObject) { if (inUObject == 0) return 0; UObject *obj = (UObject *) inUObject; UClass *cls = obj->GetClass(); auto& map = getClassMap(); while (cls != nullptr) { if (cls->HasAllClassFlags(CLASS_Native)) { auto it = map.find(cls); if (it != map.end()) { return (it->second)(inUObject); } } cls = cls->GetSuperClass(); } UE_LOG(LogTemp,Fatal,TEXT("No haxe wrapper was found for the uobject from class %s nor from any of its superclasses"), *obj->GetClass()->GetName()); // won't get here return 0; }
UExporter* UExporter::FindExporter( UObject* Object, const TCHAR* FileType ) { check(Object); TMap<UClass*,UClass*> Exporters; for (TSet< TWeakObjectPtr<UExporter> >::TIterator It(RegisteredExporters); It; ++It) { UExporter* Default = It->Get(); if(Default) { check( Default->FormatExtension.Num() == Default->FormatDescription.Num() ); if (Default->SupportsObject(Object)) { for( int32 i=0; i<Default->FormatExtension.Num(); i++ ) { const bool bIsFileType = (FCString::Stricmp( *Default->FormatExtension[i], FileType ) == 0); const bool bIsWildCardType = ( FCString::Stricmp( *Default->FormatExtension[i], TEXT("*") )== 0 ); if( bIsFileType==true || bIsWildCardType==true ) { Exporters.Add( Default->SupportedClass, Default->GetClass() ); } } } } } UClass** E; auto TransientPackage = GetTransientPackage(); for (UClass* TempClass = Object->GetClass(); TempClass != NULL; TempClass = TempClass->GetSuperClass()) { const bool bFoundExporter = ((E = Exporters.Find( TempClass )) != NULL); if( bFoundExporter ) { return NewObject<UExporter>(TransientPackage, *E); } } return NULL; }
TSubclassOf<UActorComponent> FComponentAssetBrokerage::GetPrimaryComponentForAsset(UClass* InAssetClass) { InitializeMap(); if (InAssetClass != NULL) { for (UClass* Class = InAssetClass; Class != UObject::StaticClass(); Class = Class->GetSuperClass()) { if (FComponentClassList* pTypesForClass = AssetToComponentClassMap.Find(Class)) { if (pTypesForClass->Num() > 0) { return (*pTypesForClass)[0]; } } } } return NULL; }
/** * Constructor * * @param inOutputAr archive to use for logging results * @param LimitOuter only consider objects that have this object as its Outer * @param inTarget object to show referencers to * @param inExclude list of objects that should be ignored if encountered while serializing Target */ FArchiveShowReferences::FArchiveShowReferences( FOutputDevice& inOutputAr, UObject* inOuter, UObject* inSource, TArray<UObject*>& inExclude ) : SourceObject(inSource) , SourceOuter(inOuter) , OutputAr(inOutputAr) , Exclude(inExclude) , DidRef(false) { ArIsObjectReferenceCollector = true; // there are several types of objects we don't want listed, for different reasons. // Prevent them from being logged by adding them to our Found list before we start // serialization, so that they won't be listed // quick sanity check check(SourceObject); check(SourceObject->IsValidLowLevel()); // every object we serialize obviously references our package Found.AddUnique(SourceOuter); // every object we serialize obviously references its linker Found.AddUnique(SourceObject->GetLinker()); // every object we serialize obviously references its class and its class's parent classes for ( UClass* ObjectClass = SourceObject->GetClass(); ObjectClass; ObjectClass = ObjectClass->GetSuperClass() ) { Found.AddUnique( ObjectClass ); } // similarly, if the object is a class, they all obviously reference their parent classes if ( UClass* SourceObjectClass = dynamic_cast<UClass*>(SourceObject) ) { for ( UClass* ParentClass = SourceObjectClass->GetSuperClass(); ParentClass; ParentClass = ParentClass->GetSuperClass() ) { Found.AddUnique( ParentClass ); } } // OK, now we're all set to go - let's see what Target is referencing. SourceObject->Serialize( *this ); }
/** * Returns the text to use for exporting this property to header file. * * @param ExtendedTypeText for property types which use templates, will be filled in with the type * @param CPPExportFlags flags for modifying the behavior of the export */ FString UInterfaceProperty::GetCPPType( FString* ExtendedTypeText/*=NULL*/, uint32 CPPExportFlags/*=0*/ ) const { checkSlow(InterfaceClass); if ( ExtendedTypeText != NULL ) { UClass* ExportClass = InterfaceClass; if (0 == (CPPF_BlueprintCppBackend & CPPExportFlags)) { while (ExportClass && !ExportClass->HasAnyClassFlags(CLASS_Native)) { ExportClass = ExportClass->GetSuperClass(); } } check(ExportClass); check(ExportClass->HasAnyClassFlags(CLASS_Interface) || 0 != (CPPF_BlueprintCppBackend & CPPExportFlags)); *ExtendedTypeText = FString::Printf(TEXT("<I%s>"), *ExportClass->GetName()); } return TEXT("TScriptInterface"); }
UClass* FGatherConvertedClassDependencies::GetFirstNativeOrConvertedClass(UClass* InClass, bool bExcludeBPDataOnly) const { check(InClass); for (UClass* ItClass = InClass; ItClass; ItClass = ItClass->GetSuperClass()) { UBlueprintGeneratedClass* BPGC = Cast<UBlueprintGeneratedClass>(ItClass); if (ItClass->HasAnyClassFlags(CLASS_Native) || WillClassBeConverted(BPGC)) { if (bExcludeBPDataOnly) { UBlueprint* BP = BPGC ? Cast<UBlueprint>(BPGC->ClassGeneratedBy) : nullptr; if (BP && FBlueprintEditorUtils::IsDataOnlyBlueprint(BP)) { continue; } } return ItClass; } } check(false); return nullptr; };
/** * Finds the most-derived class which is a parent of both TestClass and this object's class. * * @param TestClass the class to find the common base for */ const UClass* UObjectBaseUtility::FindNearestCommonBaseClass( const UClass* TestClass ) const { const UClass* Result = NULL; if ( TestClass != NULL ) { const UClass* CurrentClass = GetClass(); // early out if it's the same class or one is the parent of the other // (the check for TestClass->IsChildOf(CurrentClass) returns true if TestClass == CurrentClass if ( TestClass->IsChildOf(CurrentClass) ) { Result = CurrentClass; } else if ( CurrentClass->IsChildOf(TestClass) ) { Result = TestClass; } else { // find the nearest parent of TestClass which is also a parent of CurrentClass for ( UClass* Cls = TestClass->GetSuperClass(); Cls; Cls = Cls->GetSuperClass() ) { if ( CurrentClass->IsChildOf(Cls) ) { Result = Cls; break; } } } } // at this point, Result should only be NULL if TestClass is NULL checkfSlow(Result != NULL || TestClass == NULL, TEXT("No common base class found for object '%s' with TestClass '%s'"), *GetFullName(), *TestClass->GetFullName()); return Result; }
void UBlueprint::Serialize(FArchive& Ar) { Super::Serialize(Ar); #if WITH_EDITORONLY_DATA if(Ar.IsLoading() && Ar.UE4Ver() < VER_UE4_BLUEPRINT_VARS_NOT_READ_ONLY) { // Allow all blueprint defined vars to be read/write. undoes previous convention of making exposed variables read-only for (int32 i = 0; i < NewVariables.Num(); ++i) { FBPVariableDescription& Variable = NewVariables[i]; Variable.PropertyFlags &= ~CPF_BlueprintReadOnly; } } if(Ar.IsLoading() && Ar.UE4Ver() < VER_UE4_ADD_KISMETVISIBLE) { for (int32 i = 0; i < NewVariables.Num(); ++i) { FBPVariableDescription& Variable = NewVariables[i]; Variable.PropertyFlags |= CPF_BlueprintVisible; } } if (Ar.UE4Ver() < VER_UE4_K2NODE_REFERENCEGUIDS) { for (int32 Index = 0; Index < NewVariables.Num(); ++Index) { NewVariables[Index].VarGuid = FGuid::NewGuid(); } } // Preload our parent blueprints if (Ar.IsLoading()) { for (UClass* ClassIt = ParentClass; (ClassIt != NULL) && !(ClassIt->HasAnyClassFlags(CLASS_Native)); ClassIt = ClassIt->GetSuperClass()) { if (ClassIt->ClassGeneratedBy->HasAnyFlags(RF_NeedLoad)) { ClassIt->ClassGeneratedBy->GetLinker()->Preload(ClassIt->ClassGeneratedBy); } } } // If we don't have a skeleton class via compile-on-load, generate one now if( Ar.IsLoading() && (SkeletonGeneratedClass == NULL) ) { bool bWasRegen = bIsRegeneratingOnLoad; bIsRegeneratingOnLoad = true; FBlueprintEditorUtils::PreloadMembers(this); FBlueprintEditorUtils::PreloadConstructionScript(this); FKismetEditorUtilities::GenerateBlueprintSkeleton(this); bIsRegeneratingOnLoad = bWasRegen; } if (Ar.UE4Ver() < VER_UE4_BP_ACTOR_VARIABLE_DEFAULT_PREVENTING) { // Actor variables can't have default values (because Blueprint templates are library elements that can // bridge multiple levels and different levels might not have the actor that the default is referencing). for (int32 i = 0; i < NewVariables.Num(); ++i) { FBPVariableDescription& Variable = NewVariables[i]; const FEdGraphPinType& VarType = Variable.VarType; if (!VarType.PinSubCategoryObject.IsValid()) // ignore variables that don't have associated objects { continue; } const UClass* ClassObject = Cast<UClass>(VarType.PinSubCategoryObject.Get()); // if the object type is an actor... if ((ClassObject == NULL) && ClassObject->IsChildOf(AActor::StaticClass())) { // hide the default value field Variable.PropertyFlags |= CPF_DisableEditOnTemplate; } } } #endif // WITH_EDITORONLY_DATA }
FFindHeadersToInclude(FGatherConvertedClassDependencies& InDependencies) : FGatherConvertedClassDependenciesHelperBase(InDependencies) { FindReferences(Dependencies.GetActualStruct()); // special case - literal enum UBlueprintGeneratedClass* BPGC = Cast<UBlueprintGeneratedClass>(Dependencies.GetActualStruct()); UBlueprint* BP = BPGC ? Cast<UBlueprint>(BPGC->ClassGeneratedBy) : nullptr; if (BP) { TArray<UEdGraph*> Graphs; BP->GetAllGraphs(Graphs); for (UEdGraph* Graph : Graphs) { if (Graph) { TArray<UK2Node_EnumLiteral*> LiteralEnumNodes; Graph->GetNodesOfClass<UK2Node_EnumLiteral>(LiteralEnumNodes); for (UK2Node_EnumLiteral* LiteralEnumNode : LiteralEnumNodes) { UEnum* Enum = LiteralEnumNode ? LiteralEnumNode->Enum : nullptr; IncludeTheHeaderInBody(Enum); } } } } // Include classes of native subobjects if (BPGC) { UClass* NativeSuperClass = BPGC->GetSuperClass(); for (; NativeSuperClass && !NativeSuperClass->HasAnyClassFlags(CLASS_Native); NativeSuperClass = NativeSuperClass->GetSuperClass()) {} UObject* NativeCDO = NativeSuperClass ? NativeSuperClass->GetDefaultObject(false) : nullptr; if (NativeCDO) { TArray<UObject*> DefaultSubobjects; NativeCDO->GetDefaultSubobjects(DefaultSubobjects); for (UObject* DefaultSubobject : DefaultSubobjects) { IncludeTheHeaderInBody(DefaultSubobject ? DefaultSubobject->GetClass() : nullptr); } } } }
void UK2Node_Variable::ReconstructNode() { // update the variable reference if the property was renamed UClass* const VarClass = GetVariableSourceClass(); if (VarClass) { bool bRemappedProperty = false; UClass* SearchClass = VarClass; while (SearchClass != NULL) { const TMap<FName, FName>* const ClassTaggedPropertyRedirects = UStruct::TaggedPropertyRedirects.Find( SearchClass->GetFName() ); if (ClassTaggedPropertyRedirects) { const FName* const NewPropertyName = ClassTaggedPropertyRedirects->Find( VariableReference.GetMemberName() ); if (NewPropertyName) { if (VariableReference.IsSelfContext()) { VariableReference.SetSelfMember( *NewPropertyName ); } else { VariableReference.SetExternalMember( *NewPropertyName, VarClass ); } // found, can break bRemappedProperty = true; break; } } SearchClass = SearchClass->GetSuperClass(); } if (!bRemappedProperty) { static FName OldVariableName(TEXT("UpdatedComponent")); static FName NewVariableName(TEXT("UpdatedPrimitive")); bRemappedProperty = RemapRestrictedLinkReference(OldVariableName, NewVariableName, UMovementComponent::StaticClass(), UPrimitiveComponent::StaticClass(), true); } } const FGuid VarGuid = VariableReference.GetMemberGuid(); if (VarGuid.IsValid()) { const FName VarName = UBlueprint::GetFieldNameFromClassByGuid<UProperty>(VarClass, VarGuid); if (VarName != NAME_None && VarName != VariableReference.GetMemberName()) { if (VariableReference.IsSelfContext()) { VariableReference.SetSelfMember( VarName ); } else { VariableReference.SetExternalMember( VarName, VarClass ); } } } Super::ReconstructNode(); }
FBlueprintCompileReinstancer::FBlueprintCompileReinstancer(UClass* InClassToReinstance, bool bIsBytecodeOnly, bool bSkipGC) : ClassToReinstance(InClassToReinstance) , DuplicatedClass(NULL) , OriginalCDO(NULL) , bHasReinstanced(false) , bSkipGarbageCollection(bSkipGC) , ClassToReinstanceDefaultValuesCRC(0) { if( InClassToReinstance != NULL ) { bIsReinstancingSkeleton = FKismetEditorUtilities::IsClassABlueprintSkeleton(ClassToReinstance); SaveClassFieldMapping(InClassToReinstance); // Remember the initial CDO for the class being resinstanced OriginalCDO = ClassToReinstance->GetDefaultObject(); // Duplicate the class we're reinstancing into the transient package. We'll re-class all objects we find to point to this new class GIsDuplicatingClassForReinstancing = true; ClassToReinstance->ClassFlags |= CLASS_NewerVersionExists; const FName RenistanceName = MakeUniqueObjectName(GetTransientPackage(), ClassToReinstance->GetClass(), *FString::Printf(TEXT("REINST_%s"), *ClassToReinstance->GetName())); DuplicatedClass = (UClass*)StaticDuplicateObject(ClassToReinstance, GetTransientPackage(), *RenistanceName.ToString(), ~RF_Transactional); ClassToReinstance->ClassFlags &= ~CLASS_NewerVersionExists; GIsDuplicatingClassForReinstancing = false; auto BPGDuplicatedClass = Cast<UBlueprintGeneratedClass>(DuplicatedClass); auto DuplicatedClassUberGraphFunction = BPGDuplicatedClass ? BPGDuplicatedClass->UberGraphFunction : nullptr; if (DuplicatedClassUberGraphFunction) { DuplicatedClassUberGraphFunction->Bind(); DuplicatedClassUberGraphFunction->StaticLink(true); } // Bind and link the duplicate class, so that it has the proper duplicate property offsets DuplicatedClass->Bind(); DuplicatedClass->StaticLink(true); // Copy over the ComponentNametoDefaultObjectMap, which tells CopyPropertiesForUnrelatedObjects which components are instanced and which aren't GIsDuplicatingClassForReinstancing = true; UObject* OldCDO = ClassToReinstance->GetDefaultObject(); DuplicatedClass->ClassDefaultObject = (UObject*)StaticDuplicateObject(OldCDO, GetTransientPackage(), *DuplicatedClass->GetDefaultObjectName().ToString()); GIsDuplicatingClassForReinstancing = false; DuplicatedClass->ClassDefaultObject->SetFlags(RF_ClassDefaultObject); DuplicatedClass->ClassDefaultObject->SetClass(DuplicatedClass); OldCDO->SetClass(DuplicatedClass); ObjectsThatShouldUseOldStuff.Add(DuplicatedClass); //CDO of REINST_ class can be used as archetype if( !bIsBytecodeOnly ) { TArray<UObject*> ObjectsToChange; const bool bIncludeDerivedClasses = false; GetObjectsOfClass(ClassToReinstance, ObjectsToChange, bIncludeDerivedClasses); for (auto ObjIt = ObjectsToChange.CreateConstIterator(); ObjIt; ++ObjIt) { (*ObjIt)->SetClass(DuplicatedClass); } TArray<UClass*> ChildrenOfClass; GetDerivedClasses(ClassToReinstance, ChildrenOfClass); for ( auto ClassIt = ChildrenOfClass.CreateConstIterator(); ClassIt; ++ClassIt ) { UClass* ChildClass = *ClassIt; UBlueprint* ChildBP = Cast<UBlueprint>(ChildClass->ClassGeneratedBy); if (ChildBP) { const bool bClassIsDirectlyGeneratedByTheBlueprint = (ChildBP->GeneratedClass == ChildClass) || (ChildBP->SkeletonGeneratedClass == ChildClass); if (ChildBP->HasAnyFlags(RF_BeingRegenerated) || !bClassIsDirectlyGeneratedByTheBlueprint) { if (ChildClass->GetSuperClass() == ClassToReinstance) { ReparentChild(ChildClass); } //TODO: some stronger condition would be nice if (!bClassIsDirectlyGeneratedByTheBlueprint) { ObjectsThatShouldUseOldStuff.Add(ChildClass); } } // If this is a direct child, change the parent and relink so the property chain is valid for reinstancing else if( !ChildBP->HasAnyFlags(RF_NeedLoad) ) { if( ChildClass->GetSuperClass() == ClassToReinstance ) { ReparentChild(ChildBP); } Children.AddUnique(ChildBP); } else { // If this is a child that caused the load of their parent, relink to the REINST class so that we can still serialize in the CDO, but do not add to later processing ReparentChild(ChildClass); } } } } // Pull the blueprint that generated this reinstance target, and gather the blueprints that are dependent on it UBlueprint* GeneratingBP = Cast<UBlueprint>(ClassToReinstance->ClassGeneratedBy); check(GeneratingBP || GIsAutomationTesting); if(GeneratingBP) { ClassToReinstanceDefaultValuesCRC = GeneratingBP->CrcPreviousCompiledCDO; FBlueprintEditorUtils::GetDependentBlueprints(GeneratingBP, Dependencies); } } }
TSharedRef< SWidget > SDetailNameArea::BuildObjectNameArea( const TArray< TWeakObjectPtr<UObject> >& SelectedObjects ) { // Get the common base class of the selected objects UClass* BaseClass = NULL; for( int32 ObjectIndex = 0; ObjectIndex < SelectedObjects.Num(); ++ObjectIndex ) { TWeakObjectPtr<UObject> ObjectWeakPtr = SelectedObjects[ObjectIndex]; if( ObjectWeakPtr.IsValid() ) { UClass* ObjClass = ObjectWeakPtr->GetClass(); if (!BaseClass) { BaseClass = ObjClass; } while (!ObjClass->IsChildOf(BaseClass)) { BaseClass = BaseClass->GetSuperClass(); } } } TSharedRef< SHorizontalBox > ObjectNameArea = SNew( SHorizontalBox ); if (BaseClass) { // Get selection icon based on actor(s) classes and add before the selection label const FSlateBrush* ActorIcon = FClassIconFinder::FindIconForClass(BaseClass); ObjectNameArea->AddSlot() .AutoWidth() .HAlign(HAlign_Left) .VAlign(VAlign_Center) .Padding(0,0,6,0) [ SNew(SImage) .Image(ActorIcon) .ToolTip(FEditorClassUtils::GetTooltip(BaseClass)) ]; } // Add the selected object(s) type name, along with buttons for either opening C++ code or editing blueprints const int32 NumSelectedSurfaces = AssetSelectionUtils::GetNumSelectedSurfaces( GWorld ); if( SelectedObjects.Num() > 0 ) { if ( bShowActorLabel ) { FEditorWidgetsModule& EdWidgetsModule = FModuleManager::LoadModuleChecked<FEditorWidgetsModule>(TEXT("EditorWidgets")); TSharedRef<IObjectNameEditableTextBox> ObjectNameBox = EdWidgetsModule.CreateObjectNameEditableTextBox(SelectedObjects); ObjectNameArea->AddSlot() .AutoWidth() .Padding(0, 0, 3, 0) [ SNew(SBox) .WidthOverride(200.0f) .VAlign(VAlign_Center) [ ObjectNameBox ] ]; } const TWeakObjectPtr< UObject > ObjectWeakPtr = SelectedObjects.Num() == 1 ? SelectedObjects[0] : NULL; BuildObjectNameAreaSelectionLabel( ObjectNameArea, ObjectWeakPtr, SelectedObjects.Num() ); if( bShowLockButton ) { ObjectNameArea->AddSlot() .HAlign(HAlign_Right) .FillWidth(1.0f) [ SNew( SButton ) .ButtonStyle( FEditorStyle::Get(), "NoBorder" ) .OnClicked( OnLockButtonClicked ) .ToolTipText( LOCTEXT("LockSelectionButton_ToolTip", "Locks the current selection into the Details panel") ) [ SNew( SImage ) .Image( this, &SDetailNameArea::OnGetLockButtonImageResource ) ] ]; } } else { if ( SelectionTip.Get() && NumSelectedSurfaces == 0 ) { ObjectNameArea->AddSlot() .FillWidth( 1.0f ) .HAlign( HAlign_Center ) .Padding( 2.0f, 24.0f, 2.0f, 2.0f ) [ SNew( STextBlock ) .Text( LOCTEXT("NoObjectsSelected", "Select an object to view details.") ) ]; } else { // Fill the empty space ObjectNameArea->AddSlot(); } } return ObjectNameArea; }
/** * Finds the metadata for the property specified * * @param Prop the property to search for * * @return pointer to the metadata for the property specified, or NULL * if the property doesn't exist in the list (for example, if it * is declared in a package that is already compiled and has had its * source stripped) */ FTokenData* FClassMetaData::FindTokenData( UProperty* Prop ) { check(Prop); FTokenData* Result = nullptr; UObject* Outer = Prop->GetOuter(); UClass* OuterClass = nullptr; if (Outer->IsA<UStruct>()) { Result = GlobalPropertyData.Find(Prop); if (Result == nullptr) { OuterClass = Cast<UClass>(Outer); if (Result == nullptr && OuterClass != nullptr && OuterClass->GetSuperClass() != OuterClass) { OuterClass = OuterClass->GetSuperClass(); } } } else { UFunction* OuterFunction = Cast<UFunction>(Outer); if ( OuterFunction != NULL ) { // function parameter, return, or local property FFunctionData* FuncData = nullptr; if (FFunctionData::TryFindForFunction(OuterFunction, FuncData)) { FPropertyData& FunctionParameters = FuncData->GetParameterData(); Result = FunctionParameters.Find(Prop); if ( Result == NULL ) { Result = FuncData->GetReturnTokenData(); } } else { OuterClass = OuterFunction->GetOwnerClass(); } } else { // struct property UScriptStruct* OuterStruct = Cast<UScriptStruct>(Outer); check(OuterStruct != NULL); TScopedPointer<FStructData>* pStructInfo = StructData.Find(OuterStruct); if ( pStructInfo != NULL ) { FStructData* StructInfo = pStructInfo->GetOwnedPointer(); check(StructInfo); FPropertyData& StructProperties = StructInfo->GetStructPropertyData(); Result = StructProperties.Find(Prop); } else { OuterClass = OuterStruct->GetOwnerClass(); } } } if (Result == nullptr && OuterClass != nullptr) { FClassMetaData* SuperClassData = GScriptHelper.FindClassData(OuterClass); if (SuperClassData && SuperClassData != this) { Result = SuperClassData->FindTokenData(Prop); } } return Result; }
/** * Parse and import text as property values for the object specified. This function should never be called directly - use ImportObjectProperties instead. * * @param ObjectStruct the struct for the data we're importing * @param DestData the location to import the property values to * @param SourceText pointer to a buffer containing the values that should be parsed and imported * @param SubobjectRoot when dealing with nested subobjects, corresponds to the top-most outer that * is not a subobject/template * @param SubobjectOuter the outer to use for creating subobjects/components. NULL when importing structdefaultproperties * @param Warn output device to use for log messages * @param Depth current nesting level * @param InstanceGraph contains the mappings of instanced objects and components to their templates * * @return NULL if the default values couldn't be imported */ static const TCHAR* ImportProperties( uint8* DestData, const TCHAR* SourceText, UStruct* ObjectStruct, UObject* SubobjectRoot, UObject* SubobjectOuter, FFeedbackContext* Warn, int32 Depth, FObjectInstancingGraph& InstanceGraph, const TMap<FName, AActor*>* ActorRemapper ) { check(!GIsUCCMakeStandaloneHeaderGenerator); check(ObjectStruct!=NULL); check(DestData!=NULL); if ( SourceText == NULL ) return NULL; // Cannot create subobjects when importing struct defaults, or if SubobjectOuter (used as the Outer for any subobject declarations encountered) is NULL bool bSubObjectsAllowed = !ObjectStruct->IsA(UScriptStruct::StaticClass()) && SubobjectOuter != NULL; // true when DestData corresponds to a subobject in a class default object bool bSubObject = false; UClass* ComponentOwnerClass = NULL; if ( bSubObjectsAllowed ) { bSubObject = SubobjectRoot != NULL && SubobjectRoot->HasAnyFlags(RF_ClassDefaultObject); if ( SubobjectRoot == NULL ) { SubobjectRoot = SubobjectOuter; } ComponentOwnerClass = SubobjectOuter != NULL ? SubobjectOuter->IsA(UClass::StaticClass()) ? CastChecked<UClass>(SubobjectOuter) : SubobjectOuter->GetClass() : NULL; } // The PortFlags to use for all ImportText calls uint32 PortFlags = PPF_Delimited | PPF_CheckReferences; if (GIsImportingT3D) { PortFlags |= PPF_AttemptNonQualifiedSearch; } FString StrLine; TArray<FDefinedProperty> DefinedProperties; // Parse all objects stored in the actor. // Build list of all text properties. bool ImportedBrush = 0; int32 LinesConsumed = 0; while (FParse::LineExtended(&SourceText, StrLine, LinesConsumed, true)) { // remove extra whitespace and optional semicolon from the end of the line { int32 Length = StrLine.Len(); while ( Length > 0 && (StrLine[Length - 1] == TCHAR(';') || StrLine[Length - 1] == TCHAR(' ') || StrLine[Length - 1] == 9) ) { Length--; } if (Length != StrLine.Len()) { StrLine = StrLine.Left(Length); } } if ( ContextSupplier != NULL ) { ContextSupplier->CurrentLine += LinesConsumed; } if (StrLine.Len() == 0) { continue; } const TCHAR* Str = *StrLine; int32 NewLineNumber; if( FParse::Value( Str, TEXT("linenumber="), NewLineNumber ) ) { if ( ContextSupplier != NULL ) { ContextSupplier->CurrentLine = NewLineNumber; } } else if( GetBEGIN(&Str,TEXT("Brush")) && ObjectStruct->IsChildOf(ABrush::StaticClass()) ) { // If SubobjectOuter is NULL, we are importing defaults for a UScriptStruct's defaultproperties block if ( !bSubObjectsAllowed ) { Warn->Logf(ELogVerbosity::Error, TEXT("BEGIN BRUSH: Subobjects are not allowed in this context")); return NULL; } // Parse brush on this line. TCHAR BrushName[NAME_SIZE]; if( FParse::Value( Str, TEXT("Name="), BrushName, NAME_SIZE ) ) { // If an initialized brush with this name already exists in the level, rename the existing one. // It is deemed to be initialized if it has a non-zero poly count. // If it is uninitialized, the existing object will have been created by a forward reference in the import text, // and it will now be redefined. This relies on the behavior that NewObject<> will return an existing pointer // if an object with the same name and outer is passed. UModel* ExistingBrush = FindObject<UModel>( SubobjectRoot, BrushName ); if (ExistingBrush && ExistingBrush->Polys && ExistingBrush->Polys->Element.Num() > 0) { ExistingBrush->Rename(); } // Create model. UModelFactory* ModelFactory = NewObject<UModelFactory>(); ModelFactory->FactoryCreateText( UModel::StaticClass(), SubobjectRoot, FName(BrushName, FNAME_Add, true), RF_NoFlags, NULL, TEXT("t3d"), SourceText, SourceText+FCString::Strlen(SourceText), Warn ); ImportedBrush = 1; } } else if (GetBEGIN(&Str, TEXT("Foliage"))) { UFoliageType* SourceFoliageType; FName ComponentName; if (SubobjectRoot && ParseObject<UFoliageType>(Str, TEXT("FoliageType="), SourceFoliageType, ANY_PACKAGE) && FParse::Value(Str, TEXT("Component="), ComponentName) ) { UPrimitiveComponent* ActorComponent = FindObjectFast<UPrimitiveComponent>(SubobjectRoot, ComponentName); if (ActorComponent && ActorComponent->GetComponentLevel()) { AInstancedFoliageActor* IFA = AInstancedFoliageActor::GetInstancedFoliageActorForLevel(ActorComponent->GetComponentLevel(), true); FFoliageMeshInfo* MeshInfo = nullptr; UFoliageType* FoliageType = IFA->AddFoliageType(SourceFoliageType, &MeshInfo); const TCHAR* StrPtr; FString TextLine; while (MeshInfo && FParse::Line(&SourceText, TextLine)) { StrPtr = *TextLine; if (GetEND(&StrPtr, TEXT("Foliage"))) { break; } // Parse the instance properties FFoliageInstance Instance; FString Temp; if (FParse::Value(StrPtr, TEXT("Location="), Temp, false)) { GetFVECTOR(*Temp, Instance.Location); } if (FParse::Value(StrPtr, TEXT("Rotation="), Temp, false)) { GetFROTATOR(*Temp, Instance.Rotation, 1); } if (FParse::Value(StrPtr, TEXT("PreAlignRotation="), Temp, false)) { GetFROTATOR(*Temp, Instance.PreAlignRotation, 1); } if (FParse::Value(StrPtr, TEXT("DrawScale3D="), Temp, false)) { GetFVECTOR(*Temp, Instance.DrawScale3D); } FParse::Value(StrPtr, TEXT("Flags="), Instance.Flags); // Add the instance MeshInfo->AddInstance(IFA, FoliageType, Instance, ActorComponent); } } } } else if( GetBEGIN(&Str,TEXT("Object"))) { // If SubobjectOuter is NULL, we are importing defaults for a UScriptStruct's defaultproperties block if ( !bSubObjectsAllowed ) { Warn->Logf(ELogVerbosity::Error, TEXT("BEGIN OBJECT: Subobjects are not allowed in this context")); return NULL; } // Parse subobject default properties. // Note: default properties subobjects have compiled class as their Outer (used for localization). UClass* TemplateClass = NULL; bool bInvalidClass = false; ParseObject<UClass>(Str, TEXT("Class="), TemplateClass, ANY_PACKAGE, &bInvalidClass); if (bInvalidClass) { Warn->Logf(ELogVerbosity::Error,TEXT("BEGIN OBJECT: Invalid class specified: %s"), *StrLine); return NULL; } // parse the name of the template FName TemplateName = NAME_None; FParse::Value(Str,TEXT("Name="),TemplateName); if(TemplateName == NAME_None) { Warn->Logf(ELogVerbosity::Error,TEXT("BEGIN OBJECT: Must specify valid name for subobject/component: %s"), *StrLine); return NULL; } // points to the parent class's template subobject/component, if we are overriding a subobject/component declared in our parent class UObject* BaseTemplate = NULL; bool bRedefiningSubobject = false; if( TemplateClass ) { } else { // next, verify that a template actually exists in the parent class UClass* ParentClass = ComponentOwnerClass->GetSuperClass(); check(ParentClass); UObject* ParentCDO = ParentClass->GetDefaultObject(); check(ParentCDO); BaseTemplate = StaticFindObjectFast(UObject::StaticClass(), SubobjectOuter, TemplateName); bRedefiningSubobject = (BaseTemplate != NULL); if (BaseTemplate == NULL) { BaseTemplate = StaticFindObjectFast(UObject::StaticClass(), ParentCDO, TemplateName); } if ( BaseTemplate == NULL ) { // wasn't found Warn->Logf(ELogVerbosity::Error, TEXT("BEGIN OBJECT: No base template named %s found in parent class %s: %s"), *TemplateName.ToString(), *ParentClass->GetName(), *StrLine); return NULL; } TemplateClass = BaseTemplate->GetClass(); } // because the outer won't be a default object checkSlow(TemplateClass != NULL); if (bRedefiningSubobject) { // since we're redefining an object in the same text block, only need to import properties again SourceText = ImportObjectProperties( (uint8*)BaseTemplate, SourceText, TemplateClass, SubobjectRoot, BaseTemplate, Warn, Depth + 1, ContextSupplier ? ContextSupplier->CurrentLine : 0, &InstanceGraph, ActorRemapper ); } else { UObject* Archetype = NULL; UObject* ComponentTemplate = NULL; // Since we are changing the class we can't use the Archetype, // however that is fine since we will have been editing the CDO anyways if (!FBlueprintEditorUtils::IsAnonymousBlueprintClass(SubobjectOuter->GetClass())) { // if an archetype was specified in the Begin Object block, use that as the template for the ConstructObject call. FString ArchetypeName; if (FParse::Value(Str, TEXT("Archetype="), ArchetypeName)) { // if given a name, break it up along the ' so separate the class from the name FString ObjectClass; FString ObjectPath; if ( FPackageName::ParseExportTextPath(ArchetypeName, &ObjectClass, &ObjectPath) ) { // find the class UClass* ArchetypeClass = (UClass*)StaticFindObject(UClass::StaticClass(), ANY_PACKAGE, *ObjectClass); if (ArchetypeClass) { // if we had the class, find the archetype Archetype = StaticFindObject(ArchetypeClass, ANY_PACKAGE, *ObjectPath); } } } } if (SubobjectOuter->HasAnyFlags(RF_ClassDefaultObject)) { if (!Archetype) // if an archetype was specified explicitly, we will stick with that { Archetype = ComponentOwnerClass->GetDefaultSubobjectByName(TemplateName); if(Archetype) { if ( BaseTemplate == NULL ) { // BaseTemplate should only be NULL if the Begin Object line specified a class Warn->Logf(ELogVerbosity::Error, TEXT("BEGIN OBJECT: The component name %s is already used (if you want to override the component, don't specify a class): %s"), *TemplateName.ToString(), *StrLine); return NULL; } // the component currently in the component template map and the base template should be the same checkf(Archetype==BaseTemplate,TEXT("OverrideComponent: '%s' BaseTemplate: '%s'"), *Archetype->GetFullName(), *BaseTemplate->GetFullName()); } } } else // handle the non-template case (subobjects and non-template components) { // don't allow Actor-derived subobjects if ( TemplateClass->IsChildOf(AActor::StaticClass()) ) { Warn->Logf(ELogVerbosity::Error,TEXT("Cannot create subobjects from Actor-derived classes: %s"), *StrLine); return NULL; } ComponentTemplate = FindObject<UObject>(SubobjectOuter, *TemplateName.ToString()); if (ComponentTemplate != NULL) { // if we're overriding a subobject declared in a parent class, we should already have an object with that name that // was instanced when ComponentOwnerClass's CDO was initialized; if so, it's archetype should be the BaseTemplate. If it // isn't, then there are two unrelated subobject definitions using the same name. if ( ComponentTemplate->GetArchetype() != BaseTemplate ) { } else if ( BaseTemplate == NULL ) { // BaseTemplate should only be NULL if the Begin Object line specified a class Warn->Logf(ELogVerbosity::Error, TEXT("BEGIN OBJECT: A subobject named %s is already declared in a parent class. If you intended to override that subobject, don't specify a class in the derived subobject definition: %s"), *TemplateName.ToString(), *StrLine); return NULL; } } } // Propagate object flags to the sub object. EObjectFlags NewFlags = SubobjectOuter->GetMaskedFlags( RF_PropagateToSubObjects ); if (!Archetype) // no override and we didn't find one from the class table, so go with the base { Archetype = BaseTemplate; } UObject* OldComponent = NULL; if (ComponentTemplate) { bool bIsOkToReuse = ComponentTemplate->GetClass() == TemplateClass && ComponentTemplate->GetOuter() == SubobjectOuter && ComponentTemplate->GetFName() == TemplateName && (ComponentTemplate->GetArchetype() == Archetype || !Archetype); if (!bIsOkToReuse) { UE_LOG(LogEditorObject, Log, TEXT("Could not reuse component instance %s, name clash?"), *ComponentTemplate->GetFullName()); ComponentTemplate->Rename(); // just abandon the existing component, we are going to create OldComponent = ComponentTemplate; ComponentTemplate = NULL; } } if (!ComponentTemplate) { ComponentTemplate = NewObject<UObject>( SubobjectOuter, TemplateClass, TemplateName, NewFlags, Archetype, !!SubobjectOuter, &InstanceGraph ); } else { // We do not want to set RF_Transactional for construction script created components, so we have to monkey with things here if (NewFlags & RF_Transactional) { UActorComponent* Component = Cast<UActorComponent>(ComponentTemplate); if (Component && Component->IsCreatedByConstructionScript()) { NewFlags &= ~RF_Transactional; } } // Make sure desired flags are set - existing object could be pending kill ComponentTemplate->ClearFlags(RF_AllFlags); ComponentTemplate->SetFlags(NewFlags); } // replace all properties in this subobject outer' class that point to the original subobject with the new subobject TMap<UObject*, UObject*> ReplacementMap; if (Archetype) { checkSlow(ComponentTemplate->GetArchetype() == Archetype); ReplacementMap.Add(Archetype, ComponentTemplate); InstanceGraph.AddNewInstance(ComponentTemplate); } if (OldComponent) { ReplacementMap.Add(OldComponent, ComponentTemplate); } FArchiveReplaceObjectRef<UObject> ReplaceAr(SubobjectOuter, ReplacementMap, false, false, true); // import the properties for the subobject SourceText = ImportObjectProperties( (uint8*)ComponentTemplate, SourceText, TemplateClass, SubobjectRoot, ComponentTemplate, Warn, Depth+1, ContextSupplier ? ContextSupplier->CurrentLine : 0, &InstanceGraph, ActorRemapper ); } } else if( FParse::Command(&Str,TEXT("CustomProperties"))) { check(SubobjectOuter); SubobjectOuter->ImportCustomProperties(Str, Warn); } else if( GetEND(&Str,TEXT("Actor")) || GetEND(&Str,TEXT("DefaultProperties")) || GetEND(&Str,TEXT("structdefaultproperties")) || (GetEND(&Str,TEXT("Object")) && Depth) ) { // End of properties. break; } else if( GetREMOVE(&Str,TEXT("Component")) ) { checkf(false, TEXT("Remove component is illegal in pasted text")); } else { // Property. UProperty::ImportSingleProperty(Str, DestData, ObjectStruct, SubobjectOuter, PortFlags, Warn, DefinedProperties); } } if (ActorRemapper) { for (const auto& DefinedProperty : DefinedProperties) { RemapProperty(DefinedProperty.Property, DefinedProperty.Index, *ActorRemapper, DestData); } } // Prepare brush. if( ImportedBrush && ObjectStruct->IsChildOf<ABrush>() && !ObjectStruct->IsChildOf<AVolume>() ) { check(GIsEditor); ABrush* Actor = (ABrush*)DestData; check(Actor->GetBrushComponent()); if( Actor->GetBrushComponent()->Mobility == EComponentMobility::Static ) { // Prepare static brush. Actor->SetNotForClientOrServer(); } else { // Prepare moving brush. FBSPOps::csgPrepMovingBrush( Actor ); } } return SourceText; }
/** Returns the most base gameplay ability blueprint for a given blueprint (if it is inherited from another ability blueprint, returning null if only native / non-ability BP classes are it's parent) */ UGAEffectBlueprint* UGAEffectBlueprint::FindRootGameplayAbilityBlueprint(UGAEffectBlueprint* DerivedBlueprint) { UGAEffectBlueprint* ParentBP = NULL; // Determine if there is a gameplay ability blueprint in the ancestry of this class for (UClass* ParentClass = DerivedBlueprint->ParentClass; ParentClass != UObject::StaticClass(); ParentClass = ParentClass->GetSuperClass()) { if (UGAEffectBlueprint* TestBP = Cast<UGAEffectBlueprint>(ParentClass->ClassGeneratedBy)) { ParentBP = TestBP; } } return ParentBP; }