Beispiel #1
0
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;
}
Beispiel #4
0
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);
				}
			}
		}
	}
Beispiel #11
0
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 );
	}
}
Beispiel #13
0
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;
}
Beispiel #14
0
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();
}
Beispiel #21
0
/**
 * 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);
	}
Beispiel #28
0
/**
 * 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;
	}
}