void UBlueprint::GetAssetRegistryTags(TArray<FAssetRegistryTag>& OutTags) const { UClass* GenClass = Cast<UClass>(GeneratedClass); if ( GenClass && GenClass->GetDefaultObject() ) { GenClass->GetDefaultObject()->GetAssetRegistryTags(OutTags); } Super::GetAssetRegistryTags(OutTags); FString ParentClassPackageName; if ( ParentClass ) { ParentClassPackageName = ParentClass->GetOutermost()->GetName(); } else { ParentClassPackageName = TEXT("None"); } //NumReplicatedProperties int32 NumReplicatedProperties = 0; UBlueprintGeneratedClass* BlueprintClass = Cast<UBlueprintGeneratedClass>(GenClass); if (BlueprintClass) { NumReplicatedProperties = BlueprintClass->NumReplicatedProperties; } OutTags.Add(FAssetRegistryTag("NumReplicatedProperties", FString::FromInt(NumReplicatedProperties), FAssetRegistryTag::TT_Numerical)); OutTags.Add(FAssetRegistryTag("ParentClassPackage", ParentClassPackageName, FAssetRegistryTag::TT_Hidden)); OutTags.Add(FAssetRegistryTag(GET_MEMBER_NAME_CHECKED(UBlueprint, BlueprintDescription), BlueprintDescription, FAssetRegistryTag::TT_Hidden)); uint32 ClassFlagsTagged = 0; if (BlueprintClass) { ClassFlagsTagged = BlueprintClass->GetClassFlags(); } else { ClassFlagsTagged = GetClass()->GetClassFlags(); } OutTags.Add( FAssetRegistryTag("ClassFlags", FString::FromInt(ClassFlagsTagged), FAssetRegistryTag::TT_Hidden) ); FKismetEditorUtilities::GetAssetRegistryTagsForBlueprint(this, OutTags); OutTags.Add( FAssetRegistryTag( "IsDataOnly", FBlueprintEditorUtils::IsDataOnlyBlueprint(this) ? TEXT("True") : TEXT("False"), FAssetRegistryTag::TT_Alphabetical ) ); }
int32 UFixupNeedsLoadForEditorGameCommandlet::InitializeResaveParameters(const TArray<FString>& Tokens, TArray<FString>& MapPathNames) { int32 Result = Super::InitializeResaveParameters(Tokens, MapPathNames); // We need ResaveClasses to be specified, otherwise we won't know what to update if (Result == 0 && !ResaveClasses.Num()) { UE_LOG(LogContentCommandlet, Error, TEXT("FixupNeedsLoadForEditorGame commandlet requires at least one resave class name. Use -RESAVECLASS=ClassA,ClassB,ClassC to specify resave classes.")); Result = 1; } else { for (FName& ClassName : ResaveClasses) { if (!ResaveClassNeedsLoadForEditorGameValues.Contains(ClassName)) { UClass* ResaveClass = FindObject<UClass>(ANY_PACKAGE, *ClassName.ToString()); if (ResaveClass) { UObject* DefaultObject = ResaveClass->GetDefaultObject(); ResaveClassNeedsLoadForEditorGameValues.Add(ClassName, DefaultObject->NeedsLoadForEditorGame()); } } else if (Verbosity != UResavePackagesCommandlet::ONLY_ERRORS) { UE_LOG(LogContentCommandlet, Warning, TEXT("Resave Class \"%s\" could not be found. Make sure the class name is valid and that it's a native class."), *ClassName.ToString()); } } if (ResaveClassNeedsLoadForEditorGameValues.Num() == 0) { UE_LOG(LogContentCommandlet, Error, TEXT("Got %d classes to resave but none of the exist."), ResaveClasses.Num()); Result = 1; } } return Result; }
/** * Calculates the memory address for the data associated with this item's property. This is typically the value of a UProperty or a UObject address. * * @param StartAddress the location to use as the starting point for the calculation; typically the address of the object that contains this property. * * @return a pointer to a UProperty value or UObject. (For dynamic arrays, you'd cast this value to an FArray*) */ uint8* FObjectPropertyNode::GetValueBaseAddress( uint8* StartAddress ) { uint8* Result = StartAddress; UClass* ClassObject; if ( (ClassObject=Cast<UClass>((UObject*)Result)) != NULL ) { Result = (uint8*)ClassObject->GetDefaultObject(); } return Result; }
TOptional<ECurrentState> FAutoReimportManager::ProcessAdditions(const FTimeLimit& TimeLimit) { // Override the global feedback context while we do this to avoid popping up dialogs TGuardValue<FFeedbackContext*> ScopedContextOverride(GWarn, FeedbackContextOverride.Get()); TGuardValue<bool> ScopedAssetChangesGuard(bGuardAssetChanges, true); FeedbackContextOverride->GetContent()->SetMainText(GetProgressText()); TMap<FString, TArray<UFactory*>> Factories; TArray<FString> FactoryExtensions; FactoryExtensions.Reserve(16); // Get the list of valid factories for (TObjectIterator<UClass> It ; It ; ++It) { UClass* CurrentClass = (*It); if (CurrentClass->IsChildOf(UFactory::StaticClass()) && !(CurrentClass->HasAnyClassFlags(CLASS_Abstract))) { UFactory* Factory = Cast<UFactory>(CurrentClass->GetDefaultObject()); if (Factory->bEditorImport && Factory->ImportPriority >= 0) { FactoryExtensions.Reset(); Factory->GetSupportedFileExtensions(FactoryExtensions); for (const auto& Ext : FactoryExtensions) { auto& Array = Factories.FindOrAdd(Ext); Array.Add(Factory); } } } } for (auto& Pair : Factories) { Pair.Value.Sort([](const UFactory& A, const UFactory& B) { return A.ImportPriority > B.ImportPriority; }); } const IAssetRegistry& Registry = FModuleManager::LoadModuleChecked<FAssetRegistryModule>("AssetRegistry").Get(); for (auto& Monitor : DirectoryMonitors) { Monitor.ProcessAdditions(Registry, TimeLimit, PackagesToSave, Factories, *FeedbackContextOverride); yield TOptional<ECurrentState>(); } return ECurrentState::ProcessModifications; }
bool FComponentEditorUtils::CanEditNativeComponent(const UActorComponent* NativeComponent) { // A native component can be edited if it is bound to a member variable and that variable is marked as visible in the editor // Note: We aren't concerned with whether the component is marked editable - the component itself is responsible for determining which of its properties are editable bool bCanEdit = false; UClass* OwnerClass = (NativeComponent && NativeComponent->GetOwner()) ? NativeComponent->GetOwner()->GetClass() : nullptr; if (OwnerClass != nullptr) { // If the owner is a blueprint generated class, use the BP parent class UBlueprint* Blueprint = UBlueprint::GetBlueprintFromClass(OwnerClass); if (Blueprint != nullptr && Blueprint->ParentClass != nullptr) { OwnerClass = Blueprint->ParentClass; } for (TFieldIterator<UProperty> It(OwnerClass); It; ++It) { UProperty* Property = *It; if (UObjectProperty* ObjectProp = Cast<UObjectProperty>(Property)) { // Must be visible - note CPF_Edit is set for all properties that should be visible, not just those that are editable if (( Property->PropertyFlags & ( CPF_Edit ) ) == 0) { continue; } UObject* ParentCDO = OwnerClass->GetDefaultObject(); if (!NativeComponent->GetClass()->IsChildOf(ObjectProp->PropertyClass)) { continue; } UObject* Object = ObjectProp->GetObjectPropertyValue(ObjectProp->ContainerPtrToValuePtr<void>(ParentCDO)); bCanEdit = Object != nullptr && Object->GetFName() == NativeComponent->GetFName(); if (bCanEdit) { break; } } } } return bCanEdit; }
void USimpleConstructionScript::GenerateListOfExistingNames(TArray<FName>& CurrentNames) const { TArray<const USCS_Node*> ChildrenNodes = GetAllNodesConst(); const UBlueprintGeneratedClass* OwnerClass = Cast<const UBlueprintGeneratedClass>(GetOuter()); const UBlueprint* Blueprint = Cast<const UBlueprint>(OwnerClass ? OwnerClass->ClassGeneratedBy : NULL); // >>> Backwards Compatibility: VER_UE4_EDITORONLY_BLUEPRINTS if (!Blueprint) { Blueprint = Cast<UBlueprint>(GetOuter()); } // <<< End Backwards Compatibility check(Blueprint); TArray<UObject*> NativeCDOChildren; UClass* FirstNativeClass = FBlueprintEditorUtils::FindFirstNativeClass(Blueprint->ParentClass); GetObjectsWithOuter(FirstNativeClass->GetDefaultObject(), NativeCDOChildren, false); for (UObject* NativeCDOChild : NativeCDOChildren) { CurrentNames.Add(NativeCDOChild->GetFName()); } if (Blueprint->SkeletonGeneratedClass) { // First add the class variables. FBlueprintEditorUtils::GetClassVariableList(Blueprint, CurrentNames, true); // Then the function names. FBlueprintEditorUtils::GetFunctionNameList(Blueprint, CurrentNames); } // And add their names for (int32 NodeIndex = 0; NodeIndex < ChildrenNodes.Num(); ++NodeIndex) { const USCS_Node* ChildNode = ChildrenNodes[NodeIndex]; if (ChildNode) { if (ChildNode->VariableName != NAME_None) { CurrentNames.Add(ChildNode->VariableName); } } } if (GetDefaultSceneRootNode()) { CurrentNames.AddUnique(GetDefaultSceneRootNode()->GetVariableName()); } }
/** Callback for creating a new level sequence asset in the level. */ static void OnCreateActorInLevel() { // Create a new level sequence IAssetTools& AssetTools = FModuleManager::GetModuleChecked<FAssetToolsModule>("AssetTools").Get(); UObject* NewAsset = nullptr; // Attempt to create a new asset for (TObjectIterator<UClass> It ; It ; ++It) { UClass* CurrentClass = *It; if (CurrentClass->IsChildOf(UFactory::StaticClass()) && !(CurrentClass->HasAnyClassFlags(CLASS_Abstract))) { UFactory* Factory = Cast<UFactory>(CurrentClass->GetDefaultObject()); if (Factory->CanCreateNew() && Factory->ImportPriority >= 0 && Factory->SupportedClass == ULevelSequence::StaticClass()) { NewAsset = AssetTools.CreateAsset(ULevelSequence::StaticClass(), Factory); break; } } } if (!NewAsset) { return; } // Spawn an actor at the origin, and either move infront of the camera or focus camera on it (depending on the viewport) and open for edit UActorFactory* ActorFactory = GEditor->FindActorFactoryForActorClass(ALevelSequenceActor::StaticClass()); if (!ensure(ActorFactory)) { return; } ALevelSequenceActor* NewActor = CastChecked<ALevelSequenceActor>(GEditor->UseActorFactory(ActorFactory, FAssetData(NewAsset), &FTransform::Identity)); if (GCurrentLevelEditingViewportClient != nullptr && GCurrentLevelEditingViewportClient->IsPerspective()) { GEditor->MoveActorInFrontOfCamera(*NewActor, GCurrentLevelEditingViewportClient->GetViewLocation(), GCurrentLevelEditingViewportClient->GetViewRotation().Vector()); } else { GEditor->MoveViewportCamerasToActor(*NewActor, false); } FAssetEditorManager::Get().OpenEditorForAsset(NewAsset); }
void FHotReloadClassReinstancer::ReconstructClassDefaultObject(UClass* InClass, UObject* InOuter, FName InName, EObjectFlags InFlags) { // Get the parent CDO UClass* ParentClass = InClass->GetSuperClass(); UObject* ParentDefaultObject = NULL; if (ParentClass != NULL) { ParentDefaultObject = ParentClass->GetDefaultObject(); // Force the default object to be constructed if it isn't already } // Re-create InClass->ClassDefaultObject = StaticAllocateObject(InClass, InOuter, InName, InFlags, false); check(InClass->ClassDefaultObject); const bool bShouldInitilizeProperties = false; const bool bCopyTransientsFromClassDefaults = false; (*InClass->ClassConstructor)(FObjectInitializer(InClass->ClassDefaultObject, ParentDefaultObject, bCopyTransientsFromClassDefaults, bShouldInitilizeProperties)); }
FName FComponentEditorUtils::FindVariableNameGivenComponentInstance(UActorComponent* ComponentInstance) { check(ComponentInstance != nullptr); // First see if the name just works if (AActor* OwnerActor = ComponentInstance->GetOwner()) { UClass* OwnerActorClass = OwnerActor->GetClass(); if (UObjectProperty* TestProperty = FindField<UObjectProperty>(OwnerActorClass, ComponentInstance->GetFName())) { if (ComponentInstance->GetClass()->IsChildOf(TestProperty->PropertyClass)) { return TestProperty->GetFName(); } } } // Name mismatch, try finding a differently named variable pointing to the the component (the mismatch should only be possible for native components) if (UActorComponent* Archetype = Cast<UActorComponent>(ComponentInstance->GetArchetype())) { if (AActor* OwnerActor = Archetype->GetOwner()) { UClass* OwnerClass = OwnerActor->GetClass(); AActor* OwnerCDO = CastChecked<AActor>(OwnerClass->GetDefaultObject()); check(OwnerCDO->HasAnyFlags(RF_ClassDefaultObject)); for (TFieldIterator<UObjectProperty> PropIt(OwnerClass, EFieldIteratorFlags::IncludeSuper); PropIt; ++PropIt) { UObjectProperty* TestProperty = *PropIt; if (Archetype->GetClass()->IsChildOf(TestProperty->PropertyClass)) { void* TestPropertyInstanceAddress = TestProperty->ContainerPtrToValuePtr<void>(OwnerCDO); UObject* ObjectPointedToByProperty = TestProperty->GetObjectPropertyValue(TestPropertyInstanceAddress); if (ObjectPointedToByProperty == Archetype) { // This property points to the component archetype, so it's an anchor even if it was named wrong return TestProperty->GetFName(); } } } } } return NAME_None; }
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); } } } }
bool UK2Node_Event::IsCosmeticTickEvent() const { // Special case for EventTick/ReceiveTick that is conditionally executed by a separate bool rather than function flag. static const FName EventTickName(TEXT("ReceiveTick")); if (EventSignatureName == EventTickName) { const UBlueprint* Blueprint = GetBlueprint(); if (Blueprint) { UClass* BPClass = Blueprint->GeneratedClass; const AActor* DefaultActor = BPClass ? Cast<const AActor>(BPClass->GetDefaultObject()) : NULL; if (DefaultActor && !DefaultActor->AllowReceiveTickEventOnDedicatedServer()) { return true; } } } return false; }
void FSequencerActorBindingManager::PropagatePuppetActorChanges( const TSharedRef< FPuppetActorInfo > PuppetActorInfo ) { AActor* PuppetActor = PuppetActorInfo->PuppetActor.Get(); AActor* TargetActor = NULL; { // Find the spawnable for this puppet actor FMovieSceneSpawnable* FoundSpawnable = NULL; TArray< UMovieScene* > MovieScenesBeingEdited = Sequencer.Pin()->GetMovieScenesBeingEdited(); for( auto CurMovieSceneIt( MovieScenesBeingEdited.CreateIterator() ); CurMovieSceneIt; ++CurMovieSceneIt ) { auto CurMovieScene = *CurMovieSceneIt; FoundSpawnable = CurMovieScene->FindSpawnable( PuppetActorInfo->SpawnableGuid ); if( FoundSpawnable != NULL ) { break; } } if (ensure( FoundSpawnable != NULL && PuppetActor != NULL )) { UClass* ActorClass = FoundSpawnable->GetClass(); // The puppet actor's class should always be the blueprint that it was spawned from! UClass* SpawnedActorClass = PuppetActor->GetClass(); check( ActorClass == SpawnedActorClass ); // We'll be copying properties into the class default object of the Blueprint's generated class TargetActor = CastChecked<AActor>( ActorClass->GetDefaultObject() ); } } if( PuppetActor != NULL && TargetActor != NULL ) { Sequencer.Pin()->CopyActorProperties( PuppetActor, TargetActor ); } }
bool NUTNet::IsSteamNetDriverAvailable() { bool bReturnVal = false; UGameEngine* GameEngine = Cast<UGameEngine>(GEngine); if (GameEngine != NULL) { bool bFoundSteamDriver = false; const TCHAR* SteamDriverClassName = TEXT("OnlineSubsystemSteam.SteamNetDriver"); for (int i=0; i<GameEngine->NetDriverDefinitions.Num(); i++) { if (GameEngine->NetDriverDefinitions[i].DefName == NAME_GameNetDriver) { if (GameEngine->NetDriverDefinitions[i].DriverClassName == SteamDriverClassName) { bFoundSteamDriver = true; } break; } } if (bFoundSteamDriver) { UClass* SteamNetDriverClass = StaticLoadClass(UNetDriver::StaticClass(), NULL, SteamDriverClassName, NULL, LOAD_Quiet); if (SteamDriverClassName != NULL) { UNetDriver* SteamNetDriverDef = Cast<UNetDriver>(SteamNetDriverClass->GetDefaultObject()); bReturnVal = SteamNetDriverDef != NULL && SteamNetDriverDef->IsAvailable(); } } } return bReturnVal; }
FString FAutoReimportManager::GetAllFactoryExtensions() { FString AllExtensions; // Use a scratch buffer to avoid unnecessary re-allocation FString Scratch; Scratch.Reserve(32); for (TObjectIterator<UClass> ClassIt; ClassIt; ++ClassIt) { UClass* Class = *ClassIt; if (Class->IsChildOf(UFactory::StaticClass()) && !Class->HasAnyClassFlags(CLASS_Abstract)) { UFactory* Factory = Cast<UFactory>(Class->GetDefaultObject()); if (Factory->bEditorImport) { for (const FString& Format : Factory->Formats) { int32 Index = INDEX_NONE; if (Format.FindChar(';', Index) && Index > 0) { Scratch.GetCharArray().Reset(); // Include the ; Scratch.AppendChars(*Format, Index + 1); if (AllExtensions.Find(Scratch) == INDEX_NONE) { AllExtensions += Scratch; } } } } } } return AllExtensions; }
void UK2Node_Switch::CreateFunctionPin() { // Set properties on the function pin const UEdGraphSchema_K2* K2Schema = GetDefault<UEdGraphSchema_K2>(); UEdGraphPin* FunctionPin = CreatePin(EGPD_Input, K2Schema->PC_Object, TEXT(""), FunctionClass, false, false, FunctionName.ToString()); FunctionPin->bDefaultValueIsReadOnly = true; FunctionPin->bNotConnectable = true; FunctionPin->bHidden = true; UFunction* Function = FindField<UFunction>(FunctionClass, FunctionName); const bool bIsStaticFunc = Function->HasAllFunctionFlags(FUNC_Static); if (bIsStaticFunc) { // Wire up the self to the CDO of the class if it's not us if (UBlueprint* BP = GetBlueprint()) { UClass* FunctionOwnerClass = Function->GetOuterUClass(); if (!BP->SkeletonGeneratedClass->IsChildOf(FunctionOwnerClass)) { FunctionPin->DefaultObject = FunctionOwnerClass->GetDefaultObject(); } } } }
void MaterialExpressionClasses::InitMaterialExpressionClasses() { if( !bInitialized ) { UMaterialEditorOptions* TempEditorOptions = NewObject<UMaterialEditorOptions>(); UClass* BaseType = UMaterialExpression::StaticClass(); if( BaseType ) { TArray<UStructProperty*> ExpressionInputs; const UStruct* ExpressionInputStruct = GetExpressionInputStruct(); for( TObjectIterator<UClass> It ; It ; ++It ) { UClass* Class = *It; if( !Class->HasAnyClassFlags(CLASS_Abstract | CLASS_Deprecated) ) { if( Class->IsChildOf(UMaterialExpression::StaticClass()) ) { ExpressionInputs.Empty(); // Exclude comments from the expression list, as well as the base parameter expression, as it should not be used directly if ( Class != UMaterialExpressionComment::StaticClass() && Class != UMaterialExpressionParameter::StaticClass() ) { FMaterialExpression MaterialExpression; // Trim the material expression name and add it to the list used for filtering. static const FString ExpressionPrefix = TEXT("MaterialExpression"); FString ClassName = *Class->GetName(); if (ClassName.StartsWith(ExpressionPrefix, ESearchCase::CaseSensitive)) { ClassName = ClassName.Mid(ExpressionPrefix.Len()); } MaterialExpression.Name = ClassName; MaterialExpression.MaterialClass = Class; AllExpressionClasses.Add(MaterialExpression); // Initialize the expression class input map. for( TFieldIterator<UStructProperty> InputIt(Class) ; InputIt ; ++InputIt ) { UStructProperty* StructProp = *InputIt; if( StructProp->Struct == ExpressionInputStruct ) { ExpressionInputs.Add( StructProp ); } } // See if it is in the favorites array... for (int32 FavoriteIndex = 0; FavoriteIndex < TempEditorOptions->FavoriteExpressions.Num(); FavoriteIndex++) { if (Class->GetName() == TempEditorOptions->FavoriteExpressions[FavoriteIndex]) { FavoriteExpressionClasses.AddUnique(MaterialExpression); } } // Category fill... UMaterialExpression* TempObject = Cast<UMaterialExpression>(Class->GetDefaultObject()); if (TempObject) { if (TempObject->MenuCategories.Num() == 0) { UnassignedExpressionClasses.Add(MaterialExpression); } else { for (int32 CategoryIndex = 0; CategoryIndex < TempObject->MenuCategories.Num(); CategoryIndex++) { FCategorizedMaterialExpressionNode* CategoryNode = GetCategoryNode(TempObject->MenuCategories[CategoryIndex], true); check(CategoryNode); CategoryNode->MaterialExpressions.AddUnique(MaterialExpression); } } } } } } } } struct FCompareFMaterialExpression { FORCEINLINE bool operator()( const FMaterialExpression& A, const FMaterialExpression& B ) const { return A.Name < B.Name; } }; AllExpressionClasses.Sort(FCompareFMaterialExpression()); struct FCompareFCategorizedMaterialExpressionNode { FORCEINLINE bool operator()( const FCategorizedMaterialExpressionNode& A, const FCategorizedMaterialExpressionNode& B ) const { return A.CategoryName.CompareTo(B.CategoryName) < 0; } }; CategorizedExpressionClasses.Sort( FCompareFCategorizedMaterialExpressionNode() ); bInitialized = true; } }
FString FEmitDefaultValueHelper::HandleNonNativeComponent(FEmitterLocalContext& Context, const USCS_Node* Node, TSet<const UProperty*>& OutHandledProperties, TArray<FString>& NativeCreatedComponentProperties, const USCS_Node* ParentNode, TArray<FNonativeComponentData>& ComponenntsToInit) { check(Node); check(Context.CurrentCodeType == FEmitterLocalContext::EGeneratedCodeType::CommonConstructor); FString NativeVariablePropertyName; UBlueprintGeneratedClass* BPGC = CastChecked<UBlueprintGeneratedClass>(Context.GetCurrentlyGeneratedClass()); if (UActorComponent* ComponentTemplate = Node->GetActualComponentTemplate(BPGC)) { const FString VariableCleanName = Node->VariableName.ToString(); const UObjectProperty* VariableProperty = FindField<UObjectProperty>(BPGC, *VariableCleanName); if (VariableProperty) { NativeVariablePropertyName = FEmitHelper::GetCppName(VariableProperty); OutHandledProperties.Add(VariableProperty); } else { NativeVariablePropertyName = VariableCleanName; } Context.AddCommonSubObject_InConstructor(ComponentTemplate, NativeVariablePropertyName); if (ComponentTemplate->GetOuter() == BPGC) { FNonativeComponentData NonativeComponentData; NonativeComponentData.NativeVariablePropertyName = NativeVariablePropertyName; NonativeComponentData.ComponentTemplate = ComponentTemplate; UClass* ComponentClass = ComponentTemplate->GetClass(); check(ComponentClass != nullptr); UObject* ObjectToCompare = ComponentClass->GetDefaultObject(false); if (ComponentTemplate->HasAnyFlags(RF_InheritableComponentTemplate)) { ObjectToCompare = Node->GetActualComponentTemplate(Cast<UBlueprintGeneratedClass>(BPGC->GetSuperClass())); } else { Context.AddLine(FString::Printf(TEXT("%s%s = CreateDefaultSubobject<%s>(TEXT(\"%s\"));") , (VariableProperty == nullptr) ? TEXT("auto ") : TEXT("") , *NativeVariablePropertyName , *FEmitHelper::GetCppName(ComponentClass) , *VariableCleanName)); NonativeComponentData.bSetNativeCreationMethod = true; NativeCreatedComponentProperties.Add(NativeVariablePropertyName); FString ParentVariableName; if (ParentNode) { const FString CleanParentVariableName = ParentNode->VariableName.ToString(); const UObjectProperty* ParentVariableProperty = FindField<UObjectProperty>(BPGC, *CleanParentVariableName); ParentVariableName = ParentVariableProperty ? FEmitHelper::GetCppName(ParentVariableProperty) : CleanParentVariableName; } else if (USceneComponent* ParentComponentTemplate = Node->GetParentComponentTemplate(CastChecked<UBlueprint>(BPGC->ClassGeneratedBy))) { ParentVariableName = Context.FindGloballyMappedObject(ParentComponentTemplate, USceneComponent::StaticClass()); } NonativeComponentData.ParentVariableName = ParentVariableName; NonativeComponentData.AttachToName = Node->AttachToName; } NonativeComponentData.ObjectToCompare = ObjectToCompare; ComponenntsToInit.Add(NonativeComponentData); } } // Recursively handle child nodes. for (auto ChildNode : Node->ChildNodes) { HandleNonNativeComponent(Context, ChildNode, OutHandledProperties, NativeCreatedComponentProperties, Node, ComponenntsToInit); } return NativeVariablePropertyName; }
void FBlueprintSpawnNodeCommands::RegisterCommands() { const FString ConfigSection = TEXT("BlueprintSpawnNodes"); const FString SettingName = TEXT("Node"); TArray< FString > NodeSpawns; GConfig->GetArray(*ConfigSection, *SettingName, NodeSpawns, GEditorPerProjectIni); for(int32 x = 0; x < NodeSpawns.Num(); ++x) { FString ClassName; if(!FParse::Value(*NodeSpawns[x], TEXT("Class="), ClassName)) { // Could not find a class name, cannot continue with this line continue; } FString CommandLabel; UClass* FoundClass = FindObject<UClass>(ANY_PACKAGE, *ClassName, true); TSharedPtr< FNodeSpawnInfo > InfoPtr; if(FoundClass && FoundClass->IsChildOf(UEdGraphNode::StaticClass())) { // The class name matches that of a UEdGraphNode, so setup a spawn info that can generate UEdGraphNode graph actions UEdGraphNode* GraphNode = Cast<UEdGraphNode>(FoundClass->GetDefaultObject()); CommandLabel = GraphNode->GetNodeTitle(ENodeTitleType::ListView).ToString(); if(CommandLabel.Len() == 0) { CommandLabel = FoundClass->GetName(); } InfoPtr = MakeShareable( new FEdGraphNodeSpawnInfo( FoundClass ) ); } else if(UFunction* FoundFunction = FindObject<UFunction>(ANY_PACKAGE, *ClassName, true)) { // The class name matches that of a function, so setup a spawn info that can generate function graph actions InfoPtr = MakeShareable( new FFunctionNodeSpawnInfo((UFunction*)FoundFunction)); CommandLabel = FoundFunction->GetName(); } else { // Check for a macro graph that matches the passed in class name for (TObjectIterator<UBlueprint> BlueprintIt; BlueprintIt; ++BlueprintIt) { UBlueprint* MacroBP = *BlueprintIt; if(MacroBP->BlueprintType == BPTYPE_MacroLibrary) { // getting 'top-level' of the macros for (TArray<UEdGraph*>::TIterator GraphIt(MacroBP->MacroGraphs); GraphIt; ++GraphIt) { UEdGraph* MacroGraph = *GraphIt; // The class name matches that of a macro, so setup a spawn info that can generate macro graph actions if(MacroGraph->GetName() == ClassName) { CommandLabel = MacroGraph->GetName(); InfoPtr = MakeShareable( new FMacroNodeSpawnInfo(MacroGraph)); } } } } } // If spawn info was created, setup a UI Command for keybinding. if(InfoPtr.IsValid()) { TSharedPtr< FUICommandInfo > CommandInfo; FKey Key; bool bShift = false; bool bCtrl = false; bool bAlt = false; bool bCmd = false; // Parse the keybinding information FString KeyString; if( FParse::Value(*NodeSpawns[x], TEXT("Key="), KeyString) ) { Key = *KeyString; } if( Key.IsValid() ) { FParse::Bool(*NodeSpawns[x], TEXT("Shift="), bShift); FParse::Bool(*NodeSpawns[x], TEXT("Alt="), bAlt); FParse::Bool(*NodeSpawns[x], TEXT("Ctrl="), bCtrl); FParse::Bool(*NodeSpawns[x], TEXT("Cmd="), bCmd); } FInputChord Chord(Key, EModifierKey::FromBools(bCtrl, bAlt, bShift, bCmd)); FText CommandLabelText = FText::FromString( CommandLabel ); FText Description = FText::Format( NSLOCTEXT("BlueprintEditor", "NodeSpawnDescription", "Hold down the bound keys and left click in the graph panel to spawn a {0} node."), CommandLabelText ); FUICommandInfo::MakeCommandInfo( this->AsShared(), CommandInfo, FName(*NodeSpawns[x]), CommandLabelText, Description, FSlateIcon(FEditorStyle::GetStyleSetName(), *FString::Printf(TEXT("%s.%s"), *this->GetContextName().ToString(), *NodeSpawns[x])), EUserInterfaceActionType::Button, Chord ); InfoPtr->CommandInfo = CommandInfo; NodeCommands.Add(InfoPtr); } } TSharedPtr<FNodeSpawnInfo> AddActorRefAction = MakeShareable(new FActorRefSpawnInfo); UI_COMMAND(AddActorRefAction->CommandInfo, "Add Selected Actor Reference(s)", "Spawns node(s) which reference the currently selected actor(s) in the level.", EUserInterfaceActionType::Button, FInputChord(EKeys::R)); NodeCommands.Add(AddActorRefAction); }
void USimpleConstructionScript::PostLoad() { Super::PostLoad(); #if WITH_EDITOR // Get the Blueprint that owns the SCS UBlueprint* Blueprint = GetBlueprint(); if (!Blueprint) { // sometimes the PostLoad can be called, after the object was trashed, we dont want this UE_LOG(LogBlueprint, Warning, TEXT("USimpleConstructionScript::PostLoad() '%s' cannot find its owner blueprint"), *GetPathName()); return; } for (USCS_Node* Node : GetAllNodes()) { // Fix up any uninitialized category names if(Node->CategoryName.IsEmpty()) { Node->CategoryName = NSLOCTEXT("SCS", "Default", "Default"); } // Fix up components that may have switched from scene to non-scene type and vice-versa if(Node->ComponentTemplate != nullptr) { // Fix up any component template objects whose name doesn't match the current variable name; this ensures that there is always one unique template per node. FString VariableName = Node->GetVariableName().ToString(); FString ComponentTemplateName = Node->ComponentTemplate->GetName(); if(ComponentTemplateName.EndsWith(UActorComponent::ComponentTemplateNameSuffix) && !ComponentTemplateName.StartsWith(VariableName) && !GIsDuplicatingClassForReinstancing) { Node->ComponentTemplate->ConditionalPostLoad(); Node->ComponentTemplate = static_cast<UActorComponent*>(StaticDuplicateObject(Node->ComponentTemplate, Node->ComponentTemplate->GetOuter(), *(VariableName + UActorComponent::ComponentTemplateNameSuffix))); } // Check to see if switched from scene to a non-scene component type if (!Node->ComponentTemplate->IsA<USceneComponent>()) { // Otherwise, check to see if switched from scene to non-scene component type int32 RootNodeIndex = INDEX_NONE; if(!RootNodes.Find(Node, RootNodeIndex)) { // Move the node into the root set if it's currently in the scene hierarchy USCS_Node* ParentNode = FindParentNode(Node); if(ParentNode != nullptr) { ParentNode->RemoveChildNode(Node); } RootNodes.Add(Node); } else { // Otherwise, if it's a root node, promote one of its children (if any) to take its place int32 PromoteIndex = FindPromotableChildNodeIndex(Node); if(PromoteIndex != INDEX_NONE) { // Remove it as a child node USCS_Node* ChildToPromote = Node->GetChildNodes()[PromoteIndex]; Node->RemoveChildNodeAt(PromoteIndex, false); // Insert it as a root node just before its prior parent node; this way if it switches back to a scene type it won't supplant the new root we've just created RootNodes.Insert(ChildToPromote, RootNodeIndex); // Append previous root node's children to the new root ChildToPromote->MoveChildNodes(Node); // Copy any previous external attachment info from the previous root node ChildToPromote->bIsParentComponentNative = Node->bIsParentComponentNative; ChildToPromote->ParentComponentOrVariableName = Node->ParentComponentOrVariableName; ChildToPromote->ParentComponentOwnerClassName = Node->ParentComponentOwnerClassName; } // Clear info for any previous external attachment if set if(Node->ParentComponentOrVariableName != NAME_None) { Node->bIsParentComponentNative = false; Node->ParentComponentOrVariableName = NAME_None; Node->ParentComponentOwnerClassName = NAME_None; } } } } } #endif // WITH_EDITOR // Fix up native/inherited parent attachments, in case anything has changed FixupRootNodeParentReferences(); // Ensure that we have a valid scene root ValidateSceneRootNodes(); // Reset non-native "root" scene component scale values, prior to the change in which // we began applying custom scale values to root components at construction time. This // way older, existing Blueprint actor instances won't start unexpectedly getting scaled. if(GetLinkerUE4Version() < VER_UE4_BLUEPRINT_USE_SCS_ROOTCOMPONENT_SCALE) { // Get the BlueprintGeneratedClass that owns the SCS UClass* BPGeneratedClass = GetOwnerClass(); if(BPGeneratedClass != nullptr) { // Get the Blueprint class default object AActor* CDO = Cast<AActor>(BPGeneratedClass->GetDefaultObject(false)); if(CDO != NULL) { // Check for a native root component USceneComponent* NativeRootComponent = CDO->GetRootComponent(); if(NativeRootComponent == nullptr) { // If no native root component exists, find the first non-native, non-parented SCS node with a // scene component template. This will be designated as the root component at construction time. for (USCS_Node* Node : RootNodes) { if(Node->ParentComponentOrVariableName == NAME_None) { // Note that we have to check for nullptr here, because it may be an ActorComponent type USceneComponent* SceneComponentTemplate = Cast<USceneComponent>(Node->ComponentTemplate); if(SceneComponentTemplate != nullptr && SceneComponentTemplate->RelativeScale3D != FVector(1.0f, 1.0f, 1.0f)) { UE_LOG(LogBlueprint, Warning, TEXT("%s: Found non-native root component custom scale for %s (%s) saved prior to being usable; reverting to default scale."), *BPGeneratedClass->GetName(), *Node->GetVariableName().ToString(), *SceneComponentTemplate->RelativeScale3D.ToString()); SceneComponentTemplate->RelativeScale3D = FVector(1.0f, 1.0f, 1.0f); } // Done - no need to fix up any other nodes. break; } } } } } } if (GetLinkerUE4Version() < VER_UE4_SCS_STORES_ALLNODES_ARRAY) { // Fill out AllNodes if this is an older object if (RootNodes.Num() > 0) { AllNodes.Reset(); for (USCS_Node* RootNode : RootNodes) { if (RootNode != nullptr) { AllNodes.Append(RootNode->GetAllNodes()); } } } } }
void USimpleConstructionScript::FixupRootNodeParentReferences() { // Get the BlueprintGeneratedClass that owns the SCS UClass* BPGeneratedClass = GetOwnerClass(); if(BPGeneratedClass == NULL) { UE_LOG(LogBlueprint, Warning, TEXT("USimpleConstructionScript::FixupRootNodeParentReferences() - owner class is NULL; skipping.")); // cannot do the rest of fixup without a BPGC return; } for (int32 NodeIndex=0; NodeIndex < RootNodes.Num(); ++NodeIndex) { // If this root node is parented to a native/inherited component template USCS_Node* RootNode = RootNodes[NodeIndex]; if(RootNode->ParentComponentOrVariableName != NAME_None) { bool bWasFound = false; // If the node is parented to a native component if(RootNode->bIsParentComponentNative) { // Get the Blueprint class default object AActor* CDO = Cast<AActor>(BPGeneratedClass->GetDefaultObject(false)); if(CDO != NULL) { // Look for the parent component in the CDO's components array TInlineComponentArray<UActorComponent*> Components; CDO->GetComponents(Components); for (auto CompIter = Components.CreateConstIterator(); CompIter && !bWasFound; ++CompIter) { UActorComponent* ComponentTemplate = *CompIter; bWasFound = ComponentTemplate->GetFName() == RootNode->ParentComponentOrVariableName; } } else { // SCS and BGClass depends on each other (while their construction). // Class is not ready, so one have to break the dependency circle. continue; } } // Otherwise the node is parented to an inherited SCS node from a parent Blueprint else { // Get the Blueprint hierarchy TArray<const UBlueprintGeneratedClass*> ParentBPClassStack; const bool bErrorFree = UBlueprintGeneratedClass::GetGeneratedClassesHierarchy(BPGeneratedClass, ParentBPClassStack); // Find the parent Blueprint in the hierarchy for(int32 StackIndex = ParentBPClassStack.Num() - 1; StackIndex > 0; --StackIndex) { const UBlueprintGeneratedClass* ParentClass = ParentBPClassStack[StackIndex]; if( ParentClass != NULL && ParentClass->SimpleConstructionScript != NULL && ParentClass->GetFName() == RootNode->ParentComponentOwnerClassName) { // Attempt to locate a match by searching all the nodes that belong to the parent Blueprint's SCS for (USCS_Node* ParentNode : ParentClass->SimpleConstructionScript->GetAllNodes()) { if (ParentNode != nullptr && ParentNode->VariableName == RootNode->ParentComponentOrVariableName) { bWasFound = true; break; } } // We found a match; no need to continue searching the hierarchy break; } } } // Clear parent info if we couldn't find the parent component instance if(!bWasFound) { UE_LOG(LogBlueprint, Warning, TEXT("USimpleConstructionScript::FixupRootNodeParentReferences() - Couldn't find %s parent component '%s' for '%s' in BlueprintGeneratedClass '%s' (it may have been removed)"), RootNode->bIsParentComponentNative ? TEXT("native") : TEXT("inherited"), *RootNode->ParentComponentOrVariableName.ToString(), *RootNode->GetVariableName().ToString(), *BPGeneratedClass->GetName()); RootNode->bIsParentComponentNative = false; RootNode->ParentComponentOrVariableName = NAME_None; RootNode->ParentComponentOwnerClassName = NAME_None; } } } // call this after we do the above ParentComponentOrVariableName fixup, // because this operates differently for root nodes that have their // ParentComponentOrVariableName field cleared // // repairs invalid scene hierarchies (like when this Blueprint has been // reparented and there is no longer an inherited scene root... meaning one // of the scene component nodes here needs to be promoted) FixupSceneNodeHierarchy(); }
/** * 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; }
USceneComponent* USimpleConstructionScript::GetSceneRootComponentTemplate(USCS_Node** OutSCSNode) const { UBlueprint* Blueprint = GetBlueprint(); UClass* GeneratedClass = GetOwnerClass(); if(OutSCSNode) { *OutSCSNode = nullptr; } // Get the Blueprint class default object AActor* CDO = nullptr; if(GeneratedClass != nullptr) { CDO = Cast<AActor>(GeneratedClass->GetDefaultObject(false)); } // If the generated class does not yet have a CDO, defer to the parent class if(CDO == nullptr && Blueprint->ParentClass != nullptr) { CDO = Cast<AActor>(Blueprint->ParentClass->GetDefaultObject(false)); } // Check to see if we already have a native root component template USceneComponent* RootComponentTemplate = nullptr; if(CDO != nullptr) { // If the root component property is not set, the first available scene component will be used as the root. This matches what's done in the SCS editor. RootComponentTemplate = CDO->GetRootComponent(); if(!RootComponentTemplate) { TInlineComponentArray<USceneComponent*> SceneComponents; CDO->GetComponents(SceneComponents); if(SceneComponents.Num() > 0) { RootComponentTemplate = SceneComponents[0]; } } } // Don't add the default scene root if we already have a native scene root component if(!RootComponentTemplate) { // Get the Blueprint hierarchy TArray<UBlueprint*> BPStack; if(Blueprint->GeneratedClass != nullptr) { UBlueprint::GetBlueprintHierarchyFromClass(Blueprint->GeneratedClass, BPStack); } else if(Blueprint->ParentClass != nullptr) { UBlueprint::GetBlueprintHierarchyFromClass(Blueprint->ParentClass, BPStack); } // Note: Normally if the Blueprint has a parent, we can assume that the parent already has a scene root component set, // ...but we'll run through the hierarchy just in case there are legacy BPs out there that might not adhere to this assumption. TArray<const USimpleConstructionScript*> SCSStack; SCSStack.Add(this); for(int32 StackIndex = 0; StackIndex < BPStack.Num(); ++StackIndex) { if(BPStack[StackIndex] && BPStack[StackIndex]->SimpleConstructionScript && !SCSStack.Contains(BPStack[StackIndex]->SimpleConstructionScript)) { // UBlueprint::GetBlueprintHierarchyFromClass returns first children then parents. So we need to revert the order. SCSStack.Insert(BPStack[StackIndex]->SimpleConstructionScript, 0); } } for(int32 StackIndex = 0; StackIndex < SCSStack.Num() && !RootComponentTemplate; ++StackIndex) { // Check for any scene component nodes in the root set that are not the default scene root const TArray<USCS_Node*>& SCSRootNodes = SCSStack[StackIndex]->GetRootNodes(); for(int32 RootNodeIndex = 0; RootNodeIndex < SCSRootNodes.Num() && RootComponentTemplate == nullptr; ++RootNodeIndex) { USCS_Node* RootNode = SCSRootNodes[RootNodeIndex]; if(RootNode != nullptr && RootNode != DefaultSceneRootNode && RootNode->ComponentTemplate != nullptr && RootNode->ComponentTemplate->IsA<USceneComponent>()) { if(OutSCSNode) { *OutSCSNode = RootNode; } RootComponentTemplate = Cast<USceneComponent>(RootNode->ComponentTemplate); } } } } return RootComponentTemplate; }
bool UGatherTextFromAssetsCommandlet::ProcessTextProperty(UTextProperty* InTextProp, UObject* Object, const FString& ObjectPath, bool bInFixBroken, bool& OutFixed) { bool TextPropertyWasValid = true; OutFixed = false; FText* Data = InTextProp->ContainerPtrToValuePtr<FText>(Object); // Transient check. if( Data->Flags & ETextFlag::Transient ) { UE_LOG(LogGatherTextFromAssetsCommandlet, Warning, TEXT("Transient text found set to %s in %s - %s."), *InTextProp->GetName(), *Object->GetPathName(), *Object->GetName()); TextPropertyWasValid = false; } else { FConflictTracker::FEntry NewEntry; NewEntry.ObjectPath = ObjectPath; NewEntry.SourceString = Data->SourceString; NewEntry.Status = EAssetTextGatherStatus::None; // Fix missing key if broken and allowed. if( !( Data->Key.IsValid() ) || Data->Key->IsEmpty() ) { // Key fix. if (bInFixBroken) { // Create key if needed. if( !( Data->Key.IsValid() ) ) { Data->Key = MakeShareable( new FString() ); } // Generate new GUID for key. *(Data->Key) = FGuid::NewGuid().ToString(); // Fixed. NewEntry.Status = EAssetTextGatherStatus::MissingKey_Resolved; } else { NewEntry.Status = EAssetTextGatherStatus::MissingKey; TextPropertyWasValid = false; } } // Must have valid key. if( Data->Key.IsValid() && !( Data->Key->IsEmpty() ) ) { FContext SearchContext; SearchContext.Key = Data->Key.IsValid() ? *Data->Key : TEXT(""); // Find existing entry from manifest or manifest dependencies. TSharedPtr< FManifestEntry > ExistingEntry = ManifestInfo->GetManifest()->FindEntryByContext( Data->Namespace.IsValid() ? *(Data->Namespace) : TEXT(""), SearchContext ); if( !ExistingEntry.IsValid() ) { FString FileInfo; ExistingEntry = ManifestInfo->FindDependencyEntrybyContext( Data->Namespace.IsValid() ? *(Data->Namespace) : TEXT(""), SearchContext, FileInfo ); } // Entry already exists, check for conflict. if( ExistingEntry.IsValid() ) { // Fix conflict if present and allowed. if( ExistingEntry->Source.Text != ( Data->SourceString.IsValid() ? **(Data->SourceString) : TEXT("") ) ) { if (bInFixBroken) { // Generate new GUID for key. *(Data->Key) = FGuid::NewGuid().ToString(); // Fixed. NewEntry.Status = EAssetTextGatherStatus::IdentityConflict_Resolved; // Conflict resolved, no existing entry. ExistingEntry.Reset(); } else { NewEntry.Status = EAssetTextGatherStatus::IdentityConflict; TextPropertyWasValid = false; } } } // Only add an entry to the manifest if no existing entry exists. if( !( ExistingEntry.IsValid() ) ) { // Check for valid string. if( Data->SourceString.IsValid() && !( Data->SourceString->IsEmpty() ) ) { FString SrcLocation = ObjectPath + TEXT(".") + InTextProp->GetName(); // Adjust the source location if needed. { UClass* Class = Object->GetClass(); UObject* CDO = Class ? Class->GetDefaultObject() : NULL; if( CDO && CDO != Object ) { for( TFieldIterator<UTextProperty> PropIt(CDO->GetClass(), EFieldIteratorFlags::IncludeSuper); PropIt; ++PropIt ) { UTextProperty* TextProp = Cast<UTextProperty>( *(PropIt) ); FText* DataCDO = TextProp->ContainerPtrToValuePtr<FText>( CDO ); if( DataCDO->Key == Data->Key || ( DataCDO->Key.Get() && Data->Key.Get() && ( *(DataCDO->Key) == *(Data->Key) ) ) ) { SrcLocation = CDO->GetPathName() + TEXT(".") + TextProp->GetName(); break; } } } } FContext Context; Context.Key = Data->Key.IsValid() ? *Data->Key : TEXT(""); Context.SourceLocation = SrcLocation; FString EntryDescription = FString::Printf( TEXT("In %s"), *Object->GetFullName()); ManifestInfo->AddEntry(EntryDescription, Data->Namespace.Get() ? *Data->Namespace : TEXT(""), Data->SourceString.Get() ? *(Data->SourceString) : TEXT(""), Context ); } } } // Add to conflict tracker. FConflictTracker::FKeyTable& KeyTable = ConflictTracker.Namespaces.FindOrAdd( Data->Namespace.IsValid() ? *(Data->Namespace) : TEXT("") ); FConflictTracker::FEntryArray& EntryArray = KeyTable.FindOrAdd( Data->Key.IsValid() ? *(Data->Key) : TEXT("") ); EntryArray.Add(NewEntry); OutFixed = (NewEntry.Status == EAssetTextGatherStatus::MissingKey_Resolved || NewEntry.Status == EAssetTextGatherStatus::IdentityConflict_Resolved); } return TextPropertyWasValid; }
static void FindInvalidScalableFloats(const TArray<FString>& Args, bool ShowCoeffecients) { GCurrentBadScalableFloatList.Empty(); TArray<UClass*> ClassesWithScalableFloats; for (TObjectIterator<UClass> ClassIt; ClassIt; ++ClassIt) { UClass* ThisClass = *ClassIt; if (FindClassesWithScalableFloat_r(Args, ThisClass, ThisClass)) { ClassesWithScalableFloats.Add(ThisClass); ABILITY_LOG(Warning, TEXT("Class has scalable float: %s"), *ThisClass->GetName()); } } for (UClass* ThisClass : ClassesWithScalableFloats) { UObjectLibrary* ObjLibrary = nullptr; TArray<FAssetData> AssetDataList; TArray<FString> Paths; Paths.Add(TEXT("/Game/")); { FString PerfMessage = FString::Printf(TEXT("Loading %s via ObjectLibrary"), *ThisClass->GetName() ); SCOPE_LOG_TIME_IN_SECONDS(*PerfMessage, nullptr) ObjLibrary = UObjectLibrary::CreateLibrary(ThisClass, true, true); ObjLibrary->LoadBlueprintAssetDataFromPaths(Paths, true); ObjLibrary->LoadAssetsFromAssetData(); ObjLibrary->GetAssetDataList(AssetDataList); ABILITY_LOG( Warning, TEXT("Found: %d %s assets."), AssetDataList.Num(), *ThisClass->GetName()); } for (FAssetData Data: AssetDataList) { UPackage* ThisPackage = Data.GetPackage(); UBlueprint* ThisBlueprint = CastChecked<UBlueprint>(Data.GetAsset()); UClass* AssetClass = ThisBlueprint->GeneratedClass; UObject* ThisCDO = AssetClass->GetDefaultObject(); FString PathName = ThisCDO->GetName(); PathName.RemoveFromStart(TEXT("Default__")); GCurrentBadScalableFloat.Asset = ThisCDO; //ABILITY_LOG( Warning, TEXT("Asset: %s "), *PathName ); CheckForBadScalableFloats_r(ThisCDO, AssetClass, AssetClass); } } ABILITY_LOG( Error, TEXT("")); ABILITY_LOG( Error, TEXT("")); if (ShowCoeffecients == false) { for ( FBadScalableFloat& BadFoo : GCurrentBadScalableFloatList) { ABILITY_LOG( Error, TEXT(", %s, %s, %s,"), *BadFoo.Asset->GetFullName(), *BadFoo.Property->GetFullName(), *BadFoo.String ); } ABILITY_LOG( Error, TEXT("")); ABILITY_LOG( Error, TEXT("%d Errors total"), GCurrentBadScalableFloatList.Num() ); } else { ABILITY_LOG( Error, TEXT("Non 1 coefficients: ")); for ( FBadScalableFloat& BadFoo : GCurrentNaughtyScalableFloatList) { ABILITY_LOG( Error, TEXT(", %s, %s, %s"), *BadFoo.Asset->GetFullName(), *BadFoo.Property->GetFullName(), *BadFoo.String ); } } }
void FEditorUtilityInstanceDetails::CustomizeDetails(IDetailLayoutBuilder& DetailLayoutBuilder) { SelectedObjectsList = DetailLayoutBuilder.GetDetailsView().GetSelectedObjects(); // Hide some useless categories //@TODO: How to hide Actors, Layers, etc...? // Build a list of unique selected blutilities TArray<UClass*> UniqueBlutilityClasses; bool bFoundAnyCDOs = false; for (auto SelectedObjectIt = SelectedObjectsList.CreateConstIterator(); SelectedObjectIt; ++SelectedObjectIt) { UObject* Object = (*SelectedObjectIt).Get(); if (!Object->HasAnyFlags(RF_ClassDefaultObject)) { UClass* ObjectClass = Object->GetClass(); if (UEditorUtilityBlueprint* Blutility = Cast<UEditorUtilityBlueprint>(ObjectClass->ClassGeneratedBy)) { UniqueBlutilityClasses.Add(ObjectClass); } } else { bFoundAnyCDOs = true; } } // Run thru each one UniqueBlutilityClasses.Sort(FCompareClassNames()); for (auto ClassIt = UniqueBlutilityClasses.CreateIterator(); ClassIt; ++ClassIt) { UClass* Class = *ClassIt; FString CategoryName = FString::Printf(TEXT("%sActions"), *Class->ClassGeneratedBy->GetName()); IDetailCategoryBuilder& ActionsCategory = DetailLayoutBuilder.EditCategory(*CategoryName); const APlacedEditorUtilityBase* PlacedActorCDO = Cast<const APlacedEditorUtilityBase>(Class->GetDefaultObject()); if (PlacedActorCDO) { ActionsCategory.AddCustomRow( PlacedActorCDO->HelpText ) [ SNew(STextBlock) .Text(PlacedActorCDO->HelpText) ]; } const UGlobalEditorUtilityBase* GlobalBlutilityCDO = Cast<const UGlobalEditorUtilityBase>(Class->GetDefaultObject()); if (GlobalBlutilityCDO) { ActionsCategory.AddCustomRow( GlobalBlutilityCDO->HelpText ) [ SNew(STextBlock) .Text(GlobalBlutilityCDO->HelpText) ]; } TSharedRef<SWrapBox> WrapBox = SNew(SWrapBox).UseAllottedWidth(true); int32 NumButtons = 0; for (TFieldIterator<UFunction> FuncIt(Class, EFieldIteratorFlags::IncludeSuper); FuncIt; ++FuncIt) { UFunction* Function = *FuncIt; const bool bCanExecute = (Function->NumParms == 0) && Function->HasAllFunctionFlags(FUNC_Exec); if (bCanExecute) { ++NumButtons; const FString ButtonCaption = FName::NameToDisplayString(*Function->GetName(), false); //@TODO: Expose the code in UK2Node_CallFunction::GetUserFacingFunctionName / etc... FString Tooltip = Function->GetToolTipText().ToString(); if (Tooltip.IsEmpty()) { Tooltip = Function->GetName(); } TWeakObjectPtr<UFunction> WeakFunctionPtr(Function); WrapBox->AddSlot() [ SNew(SButton) .Text(ButtonCaption) .OnClicked( FOnClicked::CreateSP(this, &FEditorUtilityInstanceDetails::OnExecuteAction, WeakFunctionPtr) ) .ToolTipText(Tooltip) ]; } } if (NumButtons > 0) { ActionsCategory.AddCustomRow(TEXT("")) [ WrapBox ]; } } // Hide the hint property if (!bFoundAnyCDOs) { DetailLayoutBuilder.HideProperty(TEXT("HelpText")); } }
void FAssetViewSortManager::SortList(TArray<TSharedPtr<FAssetViewItem>>& AssetItems, const FName& MajorityAssetType) const { //double SortListStartTime = FPlatformTime::Seconds(); TArray<TUniquePtr<FCompareFAssetItemBase>> SortMethod; for (int32 PriorityIdx = 0; PriorityIdx < EColumnSortPriority::Max; PriorityIdx++) { const bool bAscending(SortMode[PriorityIdx] == EColumnSortMode::Ascending); const FName& Tag(SortColumnId[PriorityIdx]); if (Tag == NAME_None) { break; } if (Tag == NameColumnId) { SortMethod.Add(MakeUnique<FCompareFAssetItemByName>(bAscending, Tag)); } else if (Tag == ClassColumnId) { SortMethod.Add(MakeUnique<FCompareFAssetItemByClass>(bAscending, Tag)); } else if (Tag == PathColumnId) { SortMethod.Add(MakeUnique<FCompareFAssetItemByPath>(bAscending, Tag)); } else { // Since this SortData.Tag is not one of preset columns, sort by asset registry tag UObject::FAssetRegistryTag::ETagType TagType = UObject::FAssetRegistryTag::TT_Alphabetical; if (MajorityAssetType != NAME_None) { UClass* Class = FindObject<UClass>(ANY_PACKAGE, *MajorityAssetType.ToString()); if (Class) { UObject* CDO = Class->GetDefaultObject(); if (CDO) { TArray<UObject::FAssetRegistryTag> TagList; CDO->GetAssetRegistryTags(TagList); for (auto TagIt = TagList.CreateConstIterator(); TagIt; ++TagIt) { if (TagIt->Name == Tag) { TagType = TagIt->Type; break; } } } } } if (TagType == UObject::FAssetRegistryTag::TT_Numerical) { // The property is a Num2er, compare using atof SortMethod.Add(MakeUnique<FCompareFAssetItemByTagNumerical>(bAscending, Tag)); } else if (TagType == UObject::FAssetRegistryTag::TT_Dimensional) { // The property is a series of Num2ers representing dimensions, compare by using atof for each Num2er, delimited by an "x" SortMethod.Add(MakeUnique<FCompareFAssetItemByTagDimensional>(bAscending, Tag)); } else { // Unknown or alphabetical, sort alphabetically either way SortMethod.Add(MakeUnique<FCompareFAssetItemByTag>(bAscending, Tag)); } } } // Sort the list... if (SortMethod.Num() > 0) { TUniquePtr<FCompareFAssetItemBase> PrimarySortMethod = MoveTemp(SortMethod[EColumnSortPriority::Primary]); check(PrimarySortMethod); SortMethod.RemoveAt(0); // Move all the comparisons to the primary sort method PrimarySortMethod->SetNextComparisons(SortMethod); AssetItems.Sort(*(PrimarySortMethod.Get())); // Move the comparisons back for ease of cleanup SortMethod = MoveTemp(PrimarySortMethod->GetNextComparisons()); SortMethod.Insert(MoveTemp(PrimarySortMethod), 0); } // Cleanup the methods we no longer need. for (int32 PriorityIdx = 0; PriorityIdx < SortMethod.Num(); PriorityIdx++) { SortMethod[PriorityIdx].Reset(); } SortMethod.Empty(); //UE_LOG(LogContentBrowser, Warning/*VeryVerbose*/, TEXT("FAssetViewSortManager Sort Time: %0.4f seconds."), FPlatformTime::Seconds() - SortListStartTime); }
virtual void HandleObjectReference(UObject*& InObject, const UObject* InReferencingObject, const UProperty* InReferencingProperty) override { UObject* Object = InObject; if (!Object || Object->IsA<UBlueprint>()) { return; } UClass* ActualClass = Cast<UClass>(Dependencies.GetActualStruct()); UStruct* CurrentlyConvertedStruct = ActualClass ? Dependencies.FindOriginalClass(ActualClass) : Dependencies.GetActualStruct(); ensure(CurrentlyConvertedStruct); if (Object == CurrentlyConvertedStruct) { return; } { auto ObjAsField = Cast<UField>(Object); if (!ObjAsField) { const bool bTransientObject = (Object->HasAnyFlags(RF_Transient) && !Object->IsIn(CurrentlyConvertedStruct)) || Object->IsIn(GetTransientPackage()); if (bTransientObject) { return; } ObjAsField = Object->GetClass(); } if (ObjAsField && !ObjAsField->HasAnyFlags(RF_ClassDefaultObject)) { if (ObjAsField->IsA<UProperty>()) { ObjAsField = ObjAsField->GetOwnerStruct(); } if (ObjAsField->IsA<UFunction>()) { ObjAsField = ObjAsField->GetOwnerClass(); } IncludeTheHeaderInBody(ObjAsField); } } if ((Object->IsAsset() || Object->IsA<UBlueprintGeneratedClass>()) && !Object->IsIn(CurrentlyConvertedStruct)) { return; } auto OwnedByAnythingInHierarchy = [&]()->bool { for (UStruct* IterStruct = CurrentlyConvertedStruct; IterStruct; IterStruct = IterStruct->GetSuperStruct()) { if (Object->IsIn(IterStruct)) { return true; } UClass* IterClass = Cast<UClass>(IterStruct); UObject* CDO = IterClass ? IterClass->GetDefaultObject(false) : nullptr; if (CDO && Object->IsIn(CDO)) { return true; } } return false; }; if (!Object->IsA<UField>() && !Object->HasAnyFlags(RF_ClassDefaultObject) && !OwnedByAnythingInHierarchy()) { Object = Object->GetClass(); } FindReferencesForNewObject(Object); }
/** * Exec handler, parsing the passed in command * * @param InWorld World Context * @param Cmd Command to parse * @param Ar output device used for logging */ bool FDebugToolExec::Exec( UWorld* InWorld, const TCHAR* Cmd, FOutputDevice& Ar ) { // these commands are only allowed in standalone games #if UE_BUILD_SHIPPING || UE_BUILD_TEST if (GEngine->GetNetMode(InWorld) != NM_Standalone || (GEngine->GetWorldContextFromWorldChecked(InWorld).PendingNetGame != NULL)) { return 0; } // Edits the class defaults. else #endif if( FParse::Command(&Cmd,TEXT("EDITDEFAULT")) ) { // not allowed in the editor as this command can have far reaching effects such as impacting serialization if (!GIsEditor) { UClass* Class = NULL; if( ParseObject<UClass>( Cmd, TEXT("CLASS="), Class, ANY_PACKAGE ) == false ) { TCHAR ClassName[256]; if ( FParse::Token(Cmd,ClassName,ARRAY_COUNT(ClassName), 1) ) { Class = FindObject<UClass>( ANY_PACKAGE, ClassName); } } if (Class) { EditObject(Class->GetDefaultObject(), true); } else { Ar.Logf( TEXT("Missing class") ); } } return 1; } else if (FParse::Command(&Cmd,TEXT("EDITOBJECT"))) { UClass* searchClass = NULL; UObject* foundObj = NULL; // Search by class. if (ParseObject<UClass>(Cmd, TEXT("CLASS="), searchClass, ANY_PACKAGE)) { // pick the first valid object for (FObjectIterator It(searchClass); It && foundObj == NULL; ++It) { if (!It->IsPendingKill() && !It->IsTemplate()) { foundObj = *It; } } } // Search by name. else { FName searchName; FString SearchPathName; if ( FParse::Value(Cmd, TEXT("NAME="), searchName) ) { // Look for actor by name. for( TObjectIterator<UObject> It; It && foundObj == NULL; ++It ) { if (It->GetFName() == searchName) { foundObj = *It; } } } else if ( FParse::Token(Cmd,SearchPathName, true) ) { foundObj = FindObject<UObject>(ANY_PACKAGE,*SearchPathName); } } // Bring up an property editing window for the found object. if (foundObj != NULL) { // not allowed in the editor unless it is a PIE object as this command can have far reaching effects such as impacting serialization if (!GIsEditor || ((!foundObj->IsTemplate() && (foundObj->GetOutermost()->PackageFlags & PKG_PlayInEditor)))) { EditObject(foundObj, true); } } else { Ar.Logf(TEXT("Target not found")); } return 1; } else if (FParse::Command(&Cmd,TEXT("EDITARCHETYPE"))) { UObject* foundObj = NULL; // require fully qualified path name FString SearchPathName; if (FParse::Token(Cmd, SearchPathName, true)) { foundObj = FindObject<UObject>(ANY_PACKAGE,*SearchPathName); } // Bring up an property editing window for the found object. if (foundObj != NULL) { // not allowed in the editor unless it is a PIE object as this command can have far reaching effects such as impacting serialization if (!GIsEditor || ((!foundObj->IsTemplate() && (foundObj->GetOutermost()->PackageFlags & PKG_PlayInEditor)))) { EditObject(foundObj, false); } } else { Ar.Logf(TEXT("Target not found")); } return 1; } // Edits an objects properties or copies them to the clipboard. else if( FParse::Command(&Cmd,TEXT("EDITACTOR")) ) { UClass* Class = NULL; AActor* Found = NULL; if (FParse::Command(&Cmd, TEXT("TRACE"))) { APlayerController* PlayerController = InWorld->GetFirstPlayerController(); if (PlayerController != NULL) { // Do a trace in the player's facing direction and edit anything that's hit. FVector PlayerLocation; FRotator PlayerRotation; PlayerController->GetPlayerViewPoint(PlayerLocation, PlayerRotation); FHitResult Hit(1.0f); PlayerController->GetWorld()->LineTraceSingle(Hit, PlayerLocation, PlayerLocation + PlayerRotation.Vector() * 10000.f, ECC_Pawn, FCollisionQueryParams(NAME_None, true, PlayerController->GetPawn())); Found = Hit.GetActor(); } } // Search by class. else if( ParseObject<UClass>( Cmd, TEXT("CLASS="), Class, ANY_PACKAGE ) && Class->IsChildOf(AActor::StaticClass()) ) { UGameEngine* GameEngine = Cast<UGameEngine>(GEngine); // Look for the closest actor of this class to the player. FVector PlayerLocation(0.0f); APlayerController* PlayerController = InWorld->GetFirstPlayerController(); if (PlayerController != NULL) { FRotator DummyRotation; PlayerController->GetPlayerViewPoint(PlayerLocation, DummyRotation); } float MinDist = FLT_MAX; for( TActorIterator<AActor> It(InWorld, Class); It; ++It ) { if ( !It->IsPendingKill() ) { float const Dist = (PlayerController && It->GetRootComponent()) ? FVector::Dist(It->GetActorLocation(), PlayerLocation) : 0.f; if (Dist < MinDist) { MinDist = Dist; Found = *It; } } } } // Search by name. else { FName ActorName; if( FParse::Value( Cmd, TEXT("NAME="), ActorName ) ) { // Look for actor by name. for( FActorIterator It(InWorld); It; ++It ) { if( It->GetFName() == ActorName ) { Found = *It; break; } } } } // Bring up an property editing window for the found object. if( Found ) { // not allowed in the editor unless it is a PIE object as this command can have far reaching effects such as impacting serialization if (!GIsEditor || ((!Found->IsTemplate() && (Found->GetOutermost()->PackageFlags & PKG_PlayInEditor)))) { EditObject(Found, true); } } else { Ar.Logf( TEXT("Target not found") ); } return 1; } else { return 0; } }