UObject* UFactory::CreateOrOverwriteAsset(UClass* InClass, UObject* InParent, FName InName, EObjectFlags InFlags, UObject* InTemplate) const { // Creates an asset if it doesn't exist. UObject* ExistingAsset = StaticFindObject(NULL, InParent, *InName.ToString()); if ( !ExistingAsset ) { return NewObject<UObject>(InParent, InClass, InName, InFlags, InTemplate); } // If it does exist then it overwrites it if possible. if ( ExistingAsset->GetClass()->IsChildOf(InClass) ) { return NewObject<UObject>(InParent, InClass, InName, InFlags, InTemplate); } // If it can not overwrite then it will delete and replace. if ( ObjectTools::DeleteSingleObject( ExistingAsset ) ) { // Keep InPackage alive through the GC, in case ExistingAsset was the only reason it was around. const bool bRootedPackage = InParent->IsRooted(); if ( !bRootedPackage ) { InParent->AddToRoot(); } // Force GC so we can cleanly create a new asset (and not do an 'in place' replacement) CollectGarbage( GARBAGE_COLLECTION_KEEPFLAGS ); if ( !bRootedPackage ) { InParent->RemoveFromRoot(); } // Try to find the existing asset again now that the GC has occurred ExistingAsset = StaticFindObject(NULL, InParent, *InName.ToString()); if ( ExistingAsset ) { // Even after the delete and GC, the object is still around. Fail this operation. return NULL; } else { // We can now create the asset in the package return NewObject<UObject>(InParent, InClass, InName, InFlags, InTemplate); } } else { // The delete did not succeed. There are still references to the old content. return NULL; } }
VObject* VObject::StaticAllocateObject(const VClass* InClass, FName InName) { if( !InClass ) { debugf(TEXT("Invalid class for object %s"), InName.toString().c_str()); return NULL; } VObject* Obj = NULL; if( InName == NAME_None ) { InName = MakeUniqueObjectName(InClass); } else { Obj = StaticFindObject(InClass, InName); } if( Obj == NULL ) { (*InClass->_ClassStaticConstructor)(&Obj); Obj->_Index = INDEX_NONE; Obj->_HashNext = NULL; Obj->_Name = InName; Obj->AddObject(INDEX_NONE); } return Obj; }
void FKismetCompilerUtilities::EnsureFreeNameForNewClass(UClass* ClassToConsign, FString& ClassName, UBlueprint* Blueprint) { check(Blueprint); UObject* OwnerOutermost = Blueprint->GetOutermost(); // Try to find a class with the name we want to use in the scope UClass* AnyClassWithGoodName = (UClass*)StaticFindObject(UClass::StaticClass(), OwnerOutermost, *ClassName, false); if (AnyClassWithGoodName == ClassToConsign) { // Ignore it if it's the class we're already consigning anyway AnyClassWithGoodName = NULL; } if( ClassToConsign ) { ConsignToOblivion(ClassToConsign, Blueprint->bIsRegeneratingOnLoad); } // Consign the class with the name we want to use if( AnyClassWithGoodName ) { ConsignToOblivion(AnyClassWithGoodName, Blueprint->bIsRegeneratingOnLoad); } }
const UStruct* MaterialExpressionClasses::GetExpressionInputStruct() { static const UStruct* ExpressionInputStruct = CastChecked<UStruct>( StaticFindObject( UStruct::StaticClass(), ANY_PACKAGE, TEXT("ExpressionInput")) ); check( ExpressionInputStruct ); return ExpressionInputStruct; }
UObject* FSlateSound::GetResourceObject( ) const { // We might still be holding a legacy resource name, in which case we need to test that first and load it if required if (LegacyResourceName_DEPRECATED != NAME_None) { // Do we still have a valid reference in our weak-ptr? UObject* LegacyResourceObject = LegacyResourceObject_DEPRECATED.Get(); if (!LegacyResourceObject) { // We can't check the object type against USoundBase as we don't have access to it here // The user is required to cast the result of FSlateSound::GetResourceObject so we should be fine LegacyResourceObject = StaticFindObject(UObject::StaticClass(), nullptr, *LegacyResourceName_DEPRECATED.ToString()); if (!ResourceObject) { LegacyResourceObject = StaticLoadObject(UObject::StaticClass(), nullptr, *LegacyResourceName_DEPRECATED.ToString()); } // Cache this in the weak-ptr to try and avoid having to load it all the time LegacyResourceObject_DEPRECATED = LegacyResourceObject; } return LegacyResourceObject; } return ResourceObject; }
AActor* UEditorTutorial::GetActorReference(FString PathToActor) { #if WITH_EDITOR return Cast<AActor>(StaticFindObject(AActor::StaticClass(), GEditor->GetEditorWorldContext().World(), *PathToActor, false)); #else return nullptr; #endif //WITH_EDITOR }
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; }
void FKismetCompilerUtilities::RemoveObjectRedirectorIfPresent(UObject* Package, const FString& NewName, UObject* ObjectBeingMovedIn) { // We can rename on top of an object redirection (basically destroy the redirection and put us in its place). if (UObjectRedirector* Redirector = Cast<UObjectRedirector>(StaticFindObject(UObjectRedirector::StaticClass(), Package, *NewName))) { ObjectTools::DeleteRedirector(Redirector); Redirector = NULL; } }
UWidget* FWidgetTemplateClass::CreateNamed(class UWidgetTree* Tree, FName NameOverride) { if (NameOverride != NAME_None) { UObject* ExistingObject = StaticFindObject(UObject::StaticClass(), Tree, *NameOverride.ToString()); if (ExistingObject != nullptr) { NameOverride = MakeUniqueObjectName(Tree, WidgetClass.Get(), NameOverride); } } UWidget* NewWidget = Tree->ConstructWidget<UWidget>(WidgetClass.Get(), NameOverride); NewWidget->OnCreationFromPalette(); return NewWidget; }
static void Set(UEdGraphPin& InPin, const FString& Value, bool bIsText, bool bIsObject) { InPin.AutogeneratedDefaultValue = Value; if (bIsText) { InPin.DefaultTextValue = FText::FromString(Value); } else if (bIsObject) { InPin.DefaultObject = StaticFindObject(UObject::StaticClass(), nullptr, *Value); } else { InPin.DefaultValue = Value; } }
FName VObject::MakeUniqueObjectName(const VClass* InClass, FName BaseName /* = NAME_None */) { check(InClass); VClass* Class = (VClass*)InClass; if( BaseName == NAME_None ) { BaseName = InClass->GetClassName(); } EName BaseNameIndex = (EName)BaseName.GetIndex(); FName TestName; do { TestName = FName(BaseNameIndex, ++(Class->_ClassUnique)); } while (StaticFindObject(InClass, TestName)); return TestName; }
/** * Helper method for checking to see if a blueprint is currently loaded. * * @param AssetPath A path detailing the asset in question (in the form of <PackageName>.<AssetName>) * @return True if a blueprint can be found with a matching package/name, false if no corresponding blueprint was found. */ static bool IsBlueprintLoaded(FString const& AssetPath, UBlueprint** BlueprintOut = nullptr) { bool bIsLoaded = false; if (UPackage* ExistingPackage = FindPackageForAsset(AssetPath)) { FString PackagePath, AssetName; SplitPackagePathAndAssetName(AssetPath, PackagePath, AssetName); if (UBlueprint* ExistingBP = Cast<UBlueprint>(StaticFindObject(UBlueprint::StaticClass(), ExistingPackage, *AssetName))) { bIsLoaded = true; if (BlueprintOut != nullptr) { *BlueprintOut = ExistingBP; } } } return bIsLoaded; }
void FStreamableManager::FindInMemory(FStringAssetReference& InOutTargetName, struct FStreamable* Existing) { check(Existing); check(!Existing->bAsyncUnloadRequestOutstanding); check(!Existing->bAsyncLoadRequestOutstanding); UE_LOG(LogStreamableManager, Verbose, TEXT(" Searching in memory for %s"), *InOutTargetName.AssetLongPathname); Existing->Target = StaticFindObject(UObject::StaticClass(), NULL, *InOutTargetName.AssetLongPathname); UObjectRedirector* Redir = Cast<UObjectRedirector>(Existing->Target); if (Redir) { Existing->Target = Redir->DestinationObject; UE_LOG(LogStreamableManager, Verbose, TEXT(" Found redirect %s"), *Redir->GetFullName()); if (!Existing->Target) { Existing->bLoadFailed = true; UE_LOG(LogStreamableManager, Warning, TEXT("Destination of redirector was not found %s -> %s."), *InOutTargetName.AssetLongPathname, *Redir->GetFullName()); } else { UE_LOG(LogStreamableManager, Verbose, TEXT(" Redirect to %s"), *Redir->DestinationObject->GetFullName()); } } if (Existing->Target) { FStringAssetReference PossiblyNewName; PossiblyNewName.AssetLongPathname = Existing->Target->GetPathName(); if (InOutTargetName != PossiblyNewName) { UE_LOG(LogStreamableManager, Verbose, TEXT(" Name changed to %s"), *PossiblyNewName.AssetLongPathname); StreamableRedirects.Add(InOutTargetName, PossiblyNewName); StreamableItems.Add(PossiblyNewName, Existing); StreamableItems.Remove(InOutTargetName); InOutTargetName = PossiblyNewName; // we are done with the old name } UE_LOG(LogStreamableManager, Verbose, TEXT(" Found in memory %s"), *Existing->Target->GetFullName()); Existing->bLoadFailed = false; } }
UObject *FStringAssetReference::ResolveObject() const { // Don't try to resolve if we're saving a package because StaticFindObject can't be used here // and we usually don't want to force references to weak pointers while saving. if (!IsValid() || GIsSavingPackage) { return NULL; } UObject* FoundObject = NULL; // construct full name FString FullPath = ToString(); FoundObject = StaticFindObject( UObject::StaticClass(), NULL, *FullPath); UObjectRedirector* Redir = Cast<UObjectRedirector>(FoundObject); if (Redir) { // If we found a redirector, follow it FoundObject = Redir->DestinationObject; } return FoundObject; }
void FPropertyEditor::SyncToObjectsInNode( const TWeakPtr< FPropertyNode >& WeakPropertyNode ) { #if WITH_EDITOR if ( !GUnrealEd ) { return; } TSharedPtr< FPropertyNode > PropertyNode = WeakPropertyNode.Pin(); check(PropertyNode.IsValid()); UProperty* NodeProperty = PropertyNode->GetProperty(); UObjectPropertyBase* ObjectProperty = Cast<UObjectPropertyBase>( NodeProperty ); UInterfaceProperty* IntProp = Cast<UInterfaceProperty>( NodeProperty ); { UClass* PropertyClass = UObject::StaticClass(); if( ObjectProperty ) { PropertyClass = ObjectProperty->PropertyClass; } else if( IntProp ) { PropertyClass = IntProp->InterfaceClass; } // Get a list of addresses for objects handled by the property window. FReadAddressList ReadAddresses; PropertyNode->GetReadAddress( !!PropertyNode->HasNodeFlags(EPropertyNodeFlags::SingleSelectOnly), ReadAddresses, false ); // GetReadAddresses will only provide a list of addresses if the property was properly formed, objects were selected, and only one object was selected if the node has the SingleSelectOnly flag. // If a list of addresses is provided, GetReadAddress may still return false but we can operate on the property addresses even if they have different values. check( ReadAddresses.Num() > 0 ); // Create a list of object names. TArray<FString> ObjectNames; ObjectNames.Empty( ReadAddresses.Num() ); // Copy each object's object property name off into the name list. for ( int32 AddrIndex = 0 ; AddrIndex < ReadAddresses.Num() ; ++AddrIndex ) { new( ObjectNames ) FString(); uint8* Address = ReadAddresses.GetAddress(AddrIndex); if( Address ) { NodeProperty->ExportText_Direct(ObjectNames[AddrIndex], Address, Address, NULL, PPF_Localized ); } } // Create a list of objects to sync the generic browser to. TArray<UObject*> Objects; for ( int32 ObjectIndex = 0 ; ObjectIndex < ObjectNames.Num() ; ++ObjectIndex ) { UObject* Package = ANY_PACKAGE; if( ObjectNames[ObjectIndex].Contains( TEXT(".")) ) { // Formatted text string, use the exact path instead of any package Package = NULL; } UObject* Object = StaticFindObject( PropertyClass, Package, *ObjectNames[ObjectIndex] ); if( !Object && Package != ANY_PACKAGE ) { Object = StaticLoadObject(PropertyClass, Package, *ObjectNames[ObjectIndex]); } if ( Object ) { // If the selected object is a blueprint generated class, then browsing to it in the content browser should instead point to the blueprint // Note: This code needs to change once classes are the top level asset in the content browser and/or blueprint classes are displayed in the content browser if (UClass* ObjectAsClass = Cast<UClass>(Object)) { if (ObjectAsClass->ClassGeneratedBy != NULL) { Object = ObjectAsClass->ClassGeneratedBy; } } Objects.Add( Object ); } } // If a single actor is selected, sync to its location in the level editor viewport instead of the content browser. if( Objects.Num() == 1 && Objects[0]->IsA(AActor::StaticClass()) ) { TArray<AActor*> Actors; Actors.Add(Cast<AActor>(Objects[0])); GEditor->SelectNone(/*bNoteSelectionChange=*/false, /*bDeselectBSPSurfs=*/true); GEditor->SelectActor(Actors[0], /*InSelected=*/true, /*bNotify=*/true, /*bSelectEvenIfHidden=*/true); // Jump to the location of the actor GEditor->MoveViewportCamerasToActor( Actors, /*bActiveViewportOnly=*/false ); } else if ( Objects.Num() > 0 ) { GEditor->SyncBrowserToObjects(Objects); } } #endif }
/** * 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; }
UObject * UPackageMap::GetObjectFromNetGUID( FNetworkGUID NetGUID ) { if ( !ensure( NetGUID.IsValid() ) ) { return NULL; } if ( !ensure( !NetGUID.IsDefault() ) ) { return NULL; } FNetGuidCacheObject * CacheObjectPtr = Cache->ObjectLookup.Find( NetGUID ); if ( CacheObjectPtr == NULL ) { // We don't have the object mapped yet return NULL; } UObject * Object = CacheObjectPtr->Object.Get(); if ( Object != NULL ) { check( Object->GetPathName() == CacheObjectPtr->FullPath ); return Object; } if ( CacheObjectPtr->FullPath.IsEmpty() ) { // This probably isn't possible, but making it a warning UE_LOG( LogNetPackageMap, Warning, TEXT( "GetObjectFromNetGUID: No full path for %s" ), *NetGUID.ToString() ); return NULL; } if ( NetGUID.IsDynamic() ) { // Dynamic objects don't have stable names, so we can't possibly reload the same object UE_LOG( LogNetPackageMap, VeryVerbose, TEXT( "GetObjectFromNetGUID: Cannot re-create dynamic object after GC <%s, %s>" ), *NetGUID.ToString(), *CacheObjectPtr->FullPath ); return NULL; } // // The object was previously mapped, but we GC'd it // We need to reload it now // Object = StaticFindObject( UObject::StaticClass(), NULL, *CacheObjectPtr->FullPath, false ); if ( Object == NULL ) { if ( IsNetGUIDAuthority() ) { // The authority shouldn't be loading resources on demand, at least for now. // This could be garbage or a security risk // Another possibility is in dynamic property replication if the server reads the previously serialized state // that has a now destroyed actor in it. UE_LOG( LogNetPackageMap, Warning, TEXT( "GetObjectFromNetGUID: Could not find Object for: NetGUID <%s, %s> (and IsNetGUIDAuthority())" ), *NetGUID.ToString(), *CacheObjectPtr->FullPath ); return NULL; } else { UE_LOG( LogNetPackageMap, Log, TEXT( "GetObjectFromNetGUID: Could not find Object for: NetGUID <%s, %s>"), *NetGUID.ToString(), *CacheObjectPtr->FullPath ); } Object = StaticLoadObject( UObject::StaticClass(), NULL, *CacheObjectPtr->FullPath, NULL, LOAD_NoWarn ); if ( Object ) { UE_LOG( LogNetPackageMap, Log, TEXT( "GetObjectFromNetGUID: StaticLoadObject. Found: %s" ), Object ? *Object->GetName() : TEXT( "NULL" ) ); } else { Object = LoadPackage( NULL, *CacheObjectPtr->FullPath, LOAD_None ); UE_LOG( LogNetPackageMap, Log, TEXT( "GetObjectFromNetGUID: LoadPackage. Found: %s" ), Object ? *Object->GetName() : TEXT( "NULL" ) ); } } else { // If we actually found the object, we probably shouldn't have GC'd it, so that's odd UE_LOG( LogNetPackageMap, Warning, TEXT( "GetObjectFromNetGUID: Object should not be found after GC: <%s, %s>" ), *NetGUID.ToString(), *CacheObjectPtr->FullPath ); } if ( Object == NULL ) { // If we get here, that means we have an invalid path, which shouldn't be possible, but making it a warning UE_LOG( LogNetPackageMap, Warning, TEXT( "GetObjectFromNetGUID: FAILED to re-create object after GC: <%s, %s>" ), *NetGUID.ToString(), *CacheObjectPtr->FullPath ); } else { // Reassign the object pointer for quick access next time CacheObjectPtr->Object = Object; // Make sure the object is in the GUIDToObjectLookup. Cache->NetGUIDLookup.Add( Object, NetGUID ); } return Object; }
bool FContentComparisonHelper::CompareClasses(const FString& InBaseClassName, const TArray<FString>& InBaseClassesToIgnore, int32 InRecursionDepth) { TMap<FString,TArray<FContentComparisonAssetInfo> > ClassToAssetsMap; UClass* TheClass = (UClass*)StaticFindObject(UClass::StaticClass(), ANY_PACKAGE, *InBaseClassName, true); if (TheClass != NULL) { TArray<UClass*> IgnoreBaseClasses; for (int32 IgnoreIdx = 0; IgnoreIdx < InBaseClassesToIgnore.Num(); IgnoreIdx++) { UClass* IgnoreClass = (UClass*)StaticFindObject(UClass::StaticClass(), ANY_PACKAGE, *(InBaseClassesToIgnore[IgnoreIdx]), true); if (IgnoreClass != NULL) { IgnoreBaseClasses.Add(IgnoreClass); } } for( TObjectIterator<UClass> It; It; ++It ) { UClass* TheAssetClass = *It; if ((TheAssetClass->IsChildOf(TheClass) == true) && (TheAssetClass->HasAnyClassFlags(CLASS_Abstract) == false)) { bool bSkipIt = false; for (int32 CheckIdx = 0; CheckIdx < IgnoreBaseClasses.Num(); CheckIdx++) { UClass* CheckClass = IgnoreBaseClasses[CheckIdx]; if (TheAssetClass->IsChildOf(CheckClass) == true) { // UE_LOG(LogEngineUtils, Warning, TEXT("Skipping class derived from other content comparison class...")); // UE_LOG(LogEngineUtils, Warning, TEXT("\t%s derived from %s"), *TheAssetClass->GetFullName(), *CheckClass->GetFullName()); bSkipIt = true; } } if (bSkipIt == false) { TArray<FContentComparisonAssetInfo>* AssetList = ClassToAssetsMap.Find(TheAssetClass->GetFullName()); if (AssetList == NULL) { TArray<FContentComparisonAssetInfo> TempAssetList; ClassToAssetsMap.Add(TheAssetClass->GetFullName(), TempAssetList); AssetList = ClassToAssetsMap.Find(TheAssetClass->GetFullName()); } check(AssetList); // Serialize object with reference collector. const int32 MaxRecursionDepth = 6; InRecursionDepth = FMath::Clamp<int32>(InRecursionDepth, 1, MaxRecursionDepth); TMap<UObject*,bool> RecursivelyGatheredReferences; RecursiveObjectCollection(TheAssetClass, 0, InRecursionDepth, RecursivelyGatheredReferences); // Add them to the asset list for (TMap<UObject*,bool>::TIterator GatheredIt(RecursivelyGatheredReferences); GatheredIt; ++GatheredIt) { UObject* Object = GatheredIt.Key(); if (Object) { bool bAddIt = true; if (ReferenceClassesOfInterest.Num() > 0) { FString CheckClassName = Object->GetClass()->GetName(); if (ReferenceClassesOfInterest.Find(CheckClassName) == NULL) { bAddIt = false; } } if (bAddIt == true) { int32 NewIndex = AssetList->AddZeroed(); FContentComparisonAssetInfo& Info = (*AssetList)[NewIndex]; Info.AssetName = Object->GetFullName(); Info.ResourceSize = Object->GetResourceSize(EResourceSizeMode::Inclusive); } } } } } } } else { UE_LOG(LogEngineUtils, Warning, TEXT("Failed to find class: %s"), *InBaseClassName); return false; } #if 0 // Log them all out UE_LOG(LogEngineUtils, Log, TEXT("CompareClasses on %s"), *InBaseClassName); for (TMap<FString,TArray<FContentComparisonAssetInfo>>::TIterator It(ClassToAssetsMap); It; ++It) { FString ClassName = It.Key(); TArray<FContentComparisonAssetInfo>& AssetList = It.Value(); UE_LOG(LogEngineUtils, Log, TEXT("\t%s"), *ClassName); for (int32 AssetIdx = 0; AssetIdx < AssetList.Num(); AssetIdx++) { FContentComparisonAssetInfo& Info = AssetList(AssetIdx); UE_LOG(LogEngineUtils, Log, TEXT("\t\t%s,%f"), *(Info.AssetName), Info.ResourceSize/1024.0f); } } #endif #if ALLOW_DEBUG_FILES // Write out a CSV file FString CurrentTime = FDateTime::Now().ToString(); FString Platform(FPlatformProperties::PlatformName()); FString BaseCSVName = ( FString(TEXT("ContentComparison/")) + FString::Printf(TEXT("ContentCompare-%s/"), *GEngineVersion.ToString()) + FString::Printf(TEXT("%s"), *InBaseClassName) ); // Handle file name length on consoles... FString EditedBaseClassName = InBaseClassName; FString TimeString = *FDateTime::Now().ToString(); FString CheckLenName = FString::Printf(TEXT("%s-%s.csv"),*InBaseClassName,*TimeString); if (CheckLenName.Len() > PLATFORM_MAX_FILEPATH_LENGTH) { while (CheckLenName.Len() > PLATFORM_MAX_FILEPATH_LENGTH) { EditedBaseClassName = EditedBaseClassName.Right(EditedBaseClassName.Len() - 1); CheckLenName = FString::Printf(TEXT("%s-%s.csv"),*EditedBaseClassName,*TimeString); } BaseCSVName = ( FString(TEXT("ContentComparison/")) + FString::Printf(TEXT("ContentCompare-%s/"), *GEngineVersion.ToString()) + FString::Printf(TEXT("%s"), *EditedBaseClassName) ); } FDiagnosticTableViewer* AssetTable = new FDiagnosticTableViewer( *FDiagnosticTableViewer::GetUniqueTemporaryFilePath(*BaseCSVName), true); if ((AssetTable != NULL) && (AssetTable->OutputStreamIsValid() == true)) { // Fill in the header row AssetTable->AddColumn(TEXT("Class")); AssetTable->AddColumn(TEXT("Asset")); AssetTable->AddColumn(TEXT("ResourceSize(kB)")); AssetTable->CycleRow(); // Fill it in for (TMap<FString,TArray<FContentComparisonAssetInfo> >::TIterator It(ClassToAssetsMap); It; ++It) { FString ClassName = It.Key(); TArray<FContentComparisonAssetInfo>& AssetList = It.Value(); AssetTable->AddColumn(*ClassName); AssetTable->CycleRow(); for (int32 AssetIdx = 0; AssetIdx < AssetList.Num(); AssetIdx++) { FContentComparisonAssetInfo& Info = AssetList[AssetIdx]; AssetTable->AddColumn(TEXT("")); AssetTable->AddColumn(*(Info.AssetName)); AssetTable->AddColumn(TEXT("%f"), Info.ResourceSize/1024.0f); AssetTable->CycleRow(); } } } else if (AssetTable != NULL) { // Created the class, but it failed to open the output stream. UE_LOG(LogEngineUtils, Warning, TEXT("Failed to open output stream in asset table!")); } if (AssetTable != NULL) { // Close it and kill it AssetTable->Close(); delete AssetTable; } #endif return true; }
UMaterial* T3DMaterialParser::ImportMaterial() { FString ClassName, Name, Value; UClass * Class; ensure(NextLine()); ensure(IsBeginObject(ClassName)); ensure(ClassName == TEXT("Material")); ensure(GetOneValueAfter(TEXT(" Name="), Name)); FString BasePackageName = FString::Printf(TEXT("/Game/UDK/%s/Materials"), *Package); FAssetToolsModule& AssetToolsModule = FModuleManager::LoadModuleChecked<FAssetToolsModule>("AssetTools"); UMaterialFactoryNew* MaterialFactory = ConstructObject<UMaterialFactoryNew>(UMaterialFactoryNew::StaticClass()); Material = (UMaterial*)AssetToolsModule.Get().CreateAsset(Name, BasePackageName, UMaterial::StaticClass(), MaterialFactory); if (Material == NULL) { return NULL; } Material->Modify(); while (NextLine() && !IsEndObject()) { if (IsBeginObject(ClassName)) { if (ClassName == TEXT("MaterialExpressionFlipBookSample")) { Class = UMaterialExpressionTextureSample::StaticClass(); } else { Class = (UClass*)StaticFindObject(UClass::StaticClass(), ANY_PACKAGE, *ClassName, true); } if (Class) { ensure(GetOneValueAfter(TEXT(" Name="), Name)); FRequirement TextureRequirement; UMaterialExpression* MaterialExpression = ImportMaterialExpression(Class, TextureRequirement); UMaterialExpressionComment * MaterialExpressionComment = Cast<UMaterialExpressionComment>(MaterialExpression); if (MaterialExpressionComment) { Material->EditorComments.Add(MaterialExpressionComment); MaterialExpressionComment->MaterialExpressionEditorX -= MaterialExpressionComment->SizeX; FixRequirement(FString::Printf(TEXT("%s'%s'"), *ClassName, *Name), MaterialExpression); } else if (MaterialExpression) { Material->Expressions.Add(MaterialExpression); FixRequirement(FString::Printf(TEXT("%s'%s'"), *ClassName, *Name), MaterialExpression); } if (ClassName == TEXT("MaterialExpressionFlipBookSample")) { ImportMaterialExpressionFlipBookSample((UMaterialExpressionTextureSample *)MaterialExpression, TextureRequirement); } } else { JumpToEnd(); } } else if (GetProperty(TEXT("DiffuseColor="), Value)) { ImportExpression(&Material->BaseColor); } else if (GetProperty(TEXT("SpecularColor="), Value)) { ImportExpression(&Material->Specular); } else if (GetProperty(TEXT("SpecularPower="), Value)) { // TODO } else if (GetProperty(TEXT("Normal="), Value)) { ImportExpression(&Material->Normal); } else if (GetProperty(TEXT("EmissiveColor="), Value)) { ImportExpression(&Material->EmissiveColor); } else if (GetProperty(TEXT("Opacity="), Value)) { ImportExpression(&Material->Opacity); } else if (GetProperty(TEXT("OpacityMask="), Value)) { ImportExpression(&Material->OpacityMask); } else if (IsProperty(Name, Value)) { UProperty* Property = FindField<UProperty>(UMaterial::StaticClass(), *Name); if (Property) { Property->ImportText(*Value, Property->ContainerPtrToValuePtr<uint8>(Material), 0, Material); } } } PrintMissingRequirements(); return Material; }
UObject* UObjectPropertyBase::FindImportedObject( const UProperty* Property, UObject* OwnerObject, UClass* ObjectClass, UClass* RequiredMetaClass, const TCHAR* Text, uint32 PortFlags/*=0*/ ) { UObject* Result = NULL; check( ObjectClass->IsChildOf(RequiredMetaClass) ); bool AttemptNonQualifiedSearch = (PortFlags & PPF_AttemptNonQualifiedSearch) != 0; // if we are importing default properties, first look for a matching subobject by // looking through the archetype chain at each outer and stop once the outer chain reaches the owning class's default object if (PortFlags & PPF_ParsingDefaultProperties) { for (UObject* SearchStart = OwnerObject; Result == NULL && SearchStart != NULL; SearchStart = SearchStart->GetOuter()) { UObject* ScopedSearchRoot = SearchStart; while (Result == NULL && ScopedSearchRoot != NULL) { Result = StaticFindObject(ObjectClass, ScopedSearchRoot, Text); // don't think it's possible to get a non-subobject here, but it doesn't hurt to check if (Result != NULL && !Result->IsTemplate(RF_ClassDefaultObject)) { Result = NULL; } ScopedSearchRoot = ScopedSearchRoot->GetArchetype(); } if (SearchStart->HasAnyFlags(RF_ClassDefaultObject)) { break; } } } // if we have a parent, look in the parent, then it's outer, then it's outer, ... // this is because exported object properties that point to objects in the level aren't // fully qualified, and this will step up the nested object chain to solve any name // collisions within a nested object tree UObject* ScopedSearchRoot = OwnerObject; while (Result == NULL && ScopedSearchRoot != NULL) { Result = StaticFindObject(ObjectClass, ScopedSearchRoot, Text); // disallow class default subobjects here while importing defaults // this prevents the use of a subobject name that doesn't exist in the scope of the default object being imported // from grabbing some other subobject with the same name and class in some other arbitrary default object if (Result != NULL && (PortFlags & PPF_ParsingDefaultProperties) && Result->IsTemplate(RF_ClassDefaultObject)) { Result = NULL; } ScopedSearchRoot = ScopedSearchRoot->GetOuter(); } if (Result == NULL) { // attempt to find a fully qualified object Result = StaticFindObject(ObjectClass, NULL, Text); if (Result == NULL) { // match any object of the correct class whose path contains the specified path Result = StaticFindObject(ObjectClass, ANY_PACKAGE, Text); // disallow class default subobjects here while importing defaults if (Result != NULL && (PortFlags & PPF_ParsingDefaultProperties) && Result->IsTemplate(RF_ClassDefaultObject)) { Result = NULL; } } } // if we haven;t found it yet, then try to find it without a qualified name if (!Result) { const TCHAR* Dot = FCString::Strrchr(Text, '.'); if (Dot && AttemptNonQualifiedSearch) { // search with just the object name Result = FindImportedObject(Property, OwnerObject, ObjectClass, RequiredMetaClass, Dot + 1); } FString NewText(Text); // if it didn't have a dot, then maybe they just gave a uasset package name if (!Dot && !Result) { int32 LastSlash = NewText.Find(TEXT("/"), ESearchCase::CaseSensitive, ESearchDir::FromEnd); if (LastSlash >= 0) { NewText += TEXT("."); NewText += (Text + LastSlash + 1); Dot = FCString::Strrchr(*NewText, '.'); } } // If we still can't find it, try to load it. (Only try to load fully qualified names) if(!Result && Dot) { #if USE_CIRCULAR_DEPENDENCY_LOAD_DEFERRING FLinkerLoad* Linker = (OwnerObject != nullptr) ? OwnerObject->GetClass()->GetLinker() : nullptr; const bool bDeferAssetImports = (Linker != nullptr) && (Linker->LoadFlags & LOAD_DeferDependencyLoads); if (bDeferAssetImports) { Result = Linker->RequestPlaceholderValue(ObjectClass, Text); } if (Result == nullptr) #endif // USE_CIRCULAR_DEPENDENCY_LOAD_DEFERRING { uint32 LoadFlags = LOAD_NoWarn | LOAD_FindIfFail; UE_LOG(LogProperty, Verbose, TEXT("FindImportedObject is attempting to import [%s] (class = %s) with StaticLoadObject"), Text, *GetFullNameSafe(ObjectClass)); Result = StaticLoadObject(ObjectClass, NULL, Text, NULL, LoadFlags, NULL); #if USE_DEFERRED_DEPENDENCY_CHECK_VERIFICATION_TESTS check(!bDeferAssetImports || !Result || !FBlueprintSupport::IsInBlueprintPackage(Result)); #endif // USE_DEFERRED_DEPENDENCY_CHECK_VERIFICATION_TESTS } } } // if we found an object, and we have a parent, make sure we are in the same package if the found object is private, unless it's a cross level property if (Result && !Result->HasAnyFlags(RF_Public) && OwnerObject && Result->GetOutermost() != OwnerObject->GetOutermost()) { const UObjectPropertyBase* ObjectProperty = dynamic_cast<const UObjectPropertyBase*>(Property); if ( !ObjectProperty || !ObjectProperty->AllowCrossLevel()) { UE_LOG(LogProperty, Warning, TEXT("Illegal TEXT reference to a private object in external package (%s) from referencer (%s). Import failed..."), *Result->GetFullName(), *OwnerObject->GetFullName()); Result = NULL; } } check(!Result || Result->IsA(RequiredMetaClass)); return Result; }