FString UInterfaceProperty::GetCPPTypeForwardDeclaration() const
{
	checkSlow(InterfaceClass);
	UClass* ExportClass = InterfaceClass;
	while (ExportClass && !ExportClass->HasAnyClassFlags(CLASS_Native))
	{
		ExportClass = ExportClass->GetSuperClass();
	}
	check(ExportClass);
	check(ExportClass->HasAnyClassFlags(CLASS_Interface));

	return FString::Printf(TEXT("class I%s;"), *ExportClass->GetName());
}
/**
 * Returns the text to use for exporting this property to header file.
 *
 * @param	ExtendedTypeText	for property types which use templates, will be filled in with the type
 * @param	CPPExportFlags		flags for modifying the behavior of the export
 */
FString UInterfaceProperty::GetCPPMacroType( FString& ExtendedTypeText ) const
{
	checkSlow(InterfaceClass);

	UClass* ExportClass = InterfaceClass;
	while ( ExportClass && !ExportClass->HasAnyClassFlags(CLASS_Native) )
	{
		ExportClass = ExportClass->GetSuperClass();
	}
	check(ExportClass);
	check(ExportClass->HasAnyClassFlags(CLASS_Interface));

	ExtendedTypeText = FString::Printf(TEXT("I%s"), *ExportClass->GetName());
	return TEXT("TINTERFACE");
}
FString FComponentEditorUtils::GenerateValidVariableNameFromAsset(UObject* Asset, AActor* ComponentOwner)
{
	int32 Counter = 1;
	FString AssetName = Asset->GetName();

	UClass* Class = Cast<UClass>(Asset);
	if (Class)
	{
		if (!Class->HasAnyClassFlags(CLASS_CompiledFromBlueprint))
		{
			AssetName.RemoveFromEnd(TEXT("Component"));
		}
		else
		{
			AssetName.RemoveFromEnd("_C");
		}
	}

	// Try to create a name without any numerical suffix first
	FString ComponentInstanceName = AssetName;

	if (ComponentOwner)
	{
		while (!IsComponentNameAvailable(ComponentInstanceName, ComponentOwner))
		{
			// Assign the lowest possible numerical suffix
			ComponentInstanceName = FString::Printf(TEXT("%s%d"), *AssetName, Counter++);
		}
	}

	return ComponentInstanceName;
}
UFunction* FindNetServiceFunctionById(int16 RPCId)
{
	UFunction** Function = RPCFunctionMap.Find(RPCId);
	if (!Function)
	{
		for (TObjectIterator<UClass> ClassIt; ClassIt; ++ClassIt)
		{
			UClass* Class = *ClassIt;
			if (Class->IsChildOf(AActor::StaticClass())
				&& !(Class->HasAnyClassFlags(CLASS_Abstract | CLASS_Deprecated)))
			{
				for (TFieldIterator<UFunction> FuncIt(Class); FuncIt; ++FuncIt) 
				{
					UFunction* CurFunc = *FuncIt;
					if (CurFunc->RPCId > 0)
					{
						RPCFunctionMap.Add(CurFunc->RPCId, CurFunc);
					}
				}
			}
		}
		
		Function = RPCFunctionMap.Find(RPCId);
	}

	return *Function;
}
示例#5
0
FPrimaryAssetId AAFCueActor::GetPrimaryAssetId() const
{
	FName dupa1 = FPackageName::GetShortFName(GetOutermost()->GetFName());
	
	const AAFCueActor* A = this;
	return FPrimaryAssetId(FPrimaryAssetType("ActorCue"), dupa1);
	//if (HasAnyFlags(RF_ClassDefaultObject))
	{
		UClass* SearchNativeClass = GetClass();

		while (SearchNativeClass && !SearchNativeClass->HasAnyClassFlags(CLASS_Native | CLASS_Intrinsic))
		{
			SearchNativeClass = SearchNativeClass->GetSuperClass();
		}

		if (SearchNativeClass && SearchNativeClass != GetClass())
		{
			// If blueprint, return native class and asset name

		}

		// Native CDO, return nothing
		return FPrimaryAssetId();
	}

	// Data assets use Class and ShortName by default, there's no inheritance so class works fine
	//return FPrimaryAssetId(GetClass()->GetFName(), GetFName());
}
void FBlueprintCompileReinstancer::UpdateBytecodeReferences()
{
	BP_SCOPED_COMPILER_EVENT_STAT(EKismetReinstancerStats_UpdateBytecodeReferences);

	if(ClassToReinstance != NULL)
	{
		TMap<UObject*, UObject*> FieldMappings;
		GenerateFieldMappings(FieldMappings);

		for( auto DependentBP = Dependencies.CreateIterator(); DependentBP; ++DependentBP )
		{
			UClass* BPClass = (*DependentBP)->GeneratedClass;

			// Skip cases where the class is junk, or haven't finished serializing in yet
			if( (BPClass == ClassToReinstance)
				|| (BPClass->GetOutermost() == GetTransientPackage()) 
				|| BPClass->HasAnyClassFlags(CLASS_NewerVersionExists)
				|| (BPClass->ClassGeneratedBy && BPClass->ClassGeneratedBy->HasAnyFlags(RF_NeedLoad|RF_BeingRegenerated)) )
			{
				continue;
			}

			// For each function defined in this blueprint, run through the bytecode, and update any refs from the old properties to the new
			for( TFieldIterator<UFunction> FuncIter(BPClass, EFieldIteratorFlags::ExcludeSuper); FuncIter; ++FuncIter )
			{
				UFunction* CurrentFunction = *FuncIter;
				if( CurrentFunction->Script.Num() > 0 )
				{
					FArchiveReplaceObjectRef<UObject> ReplaceAr(CurrentFunction, FieldMappings, /*bNullPrivateRefs=*/ false, /*bIgnoreOuterRef=*/ true, /*bIgnoreArchetypeRef=*/ true);
				}
			}
		}
	}
}
bool UOnlineHotfixManager::HotfixPakIniFile(const FString& FileName)
{
	FConfigFile* ConfigFile = GetConfigFile(FileName);
	ConfigFile->Combine(FileName);
	UE_LOG(LogHotfixManager, Log, TEXT("Hotfix merged INI (%s) found in a PAK file"), *FileName);

	FName IniFileName(*FileName, FNAME_Find);
	int32 NumObjectsReloaded = 0;
	const double StartTime = FPlatformTime::Seconds();
	// Now that we have a list of classes to update, we can iterate objects and
	// reload if they match the INI file that was changed
	for (FObjectIterator It; It; ++It)
	{
		UClass* Class = It->GetClass();
		if (Class->HasAnyClassFlags(CLASS_Config) &&
			Class->ClassConfigName == IniFileName)
		{
			// Force a reload of the config vars
			It->ReloadConfig();
			NumObjectsReloaded++;
		}
	}
	UE_LOG(LogHotfixManager, Log, TEXT("Updating config from %s took %f seconds reloading %d objects"),
		*FileName, FPlatformTime::Seconds() - StartTime, NumObjectsReloaded);
	return true;
}
void AActor::ResetPropertiesForConstruction()
{
	// Get class CDO
	AActor* Default = GetClass()->GetDefaultObject<AActor>();
	// RandomStream struct name to compare against
	const FName RandomStreamName(TEXT("RandomStream"));

	// We don't want to reset references to world object
	const bool bIsLevelScriptActor = IsA(ALevelScriptActor::StaticClass());

	// Iterate over properties
	for( TFieldIterator<UProperty> It(GetClass()) ; It ; ++It )
	{
		UProperty* Prop = *It;
		UStructProperty* StructProp = Cast<UStructProperty>(Prop);
		UClass* PropClass = CastChecked<UClass>(Prop->GetOuter()); // get the class that added this property

		// First see if it is a random stream, if so reset before running construction script
		if( (StructProp != NULL) && (StructProp->Struct != NULL) && (StructProp->Struct->GetFName() == RandomStreamName) )
		{
			FRandomStream* StreamPtr =  StructProp->ContainerPtrToValuePtr<FRandomStream>(this);
			StreamPtr->Reset();
		}
		// If it is a blueprint added variable that is not editable per-instance, reset to default before running construction script
		else if( !bIsLevelScriptActor 
				&& Prop->HasAnyPropertyFlags(CPF_DisableEditOnInstance)
				&& PropClass->HasAnyClassFlags(CLASS_CompiledFromBlueprint) 
				&& !Prop->IsA(UDelegateProperty::StaticClass()) 
				&& !Prop->IsA(UMulticastDelegateProperty::StaticClass()) )
		{
			Prop->CopyCompleteValue_InContainer(this, Default);
		}
	}
}
void UK2Node_AddComponent::ValidateNodeDuringCompilation(FCompilerResultsLog& MessageLog) const
{
	Super::ValidateNodeDuringCompilation(MessageLog);

	UActorComponent* Template = GetTemplateFromNode();
	if (Template)
	{
		UClass* TemplateClass = Template->GetClass();
		if (!TemplateClass->IsChildOf(UActorComponent::StaticClass()) || TemplateClass->HasAnyClassFlags(CLASS_Abstract) || !TemplateClass->HasMetaData(FBlueprintMetadata::MD_BlueprintSpawnableComponent) )
		{
			FFormatNamedArguments Args;
			Args.Add(TEXT("TemplateClass"), FText::FromString(TemplateClass->GetName()));
			Args.Add(TEXT("NodeTitle"), GetNodeTitle(ENodeTitleType::FullTitle));
			MessageLog.Error(*FText::Format(NSLOCTEXT("KismetCompiler", "InvalidComponentTemplate_Error", "Invalid class '{TemplateClass}' used as template by '{NodeTitle}' for @@"), Args).ToString(), this);
		}

		if (UChildActorComponent const* ChildActorComponent = Cast<UChildActorComponent const>(Template))
		{
			UBlueprint const* Blueprint = GetBlueprint();

			UClass const* ChildActorClass = ChildActorComponent->GetChildActorClass();
			if (ChildActorClass == Blueprint->GeneratedClass)
			{
				UEdGraph const* ParentGraph = GetGraph();
				UEdGraphSchema_K2 const* K2Schema = GetDefault<UEdGraphSchema_K2>();

				if (K2Schema->IsConstructionScript(ParentGraph))
				{
					FFormatNamedArguments Args;
					Args.Add(TEXT("ChildActorClass"), FText::FromString(ChildActorClass->GetName()));
					MessageLog.Error(*FText::Format(NSLOCTEXT("KismetCompiler", "AddSelfComponent_Error", "@@ cannot add a '{ChildActorClass}' component in the construction script (could cause infinite recursion)."), Args).ToString(), this);
				}
			}
			else if (ChildActorClass != nullptr)
			{
				AActor const* ChildActor = Cast<AActor>(ChildActorClass->ClassDefaultObject);
				check(ChildActor != nullptr);
				USceneComponent* RootComponent = ChildActor->GetRootComponent();

				if ((RootComponent != nullptr) && (RootComponent->Mobility == EComponentMobility::Static) && (ChildActorComponent->Mobility != EComponentMobility::Static))
				{
					FFormatNamedArguments Args;
					Args.Add(TEXT("ChildActorClass"), FText::FromString(ChildActorClass->GetName()));
					MessageLog.Error(*FText::Format(NSLOCTEXT("KismetCompiler", "AddStaticChildActorComponent_Error", "@@ cannot add a '{ChildActorClass}' component as it has static mobility, and the ChildActorComponent does not."), Args).ToString(), this);
				}
			}
		}
	}
	else
	{
		FFormatNamedArguments Args;
		Args.Add(TEXT("NodeTitle"), GetNodeTitle(ENodeTitleType::FullTitle));
		MessageLog.Error(*FText::Format(NSLOCTEXT("KismetCompiler", "MissingComponentTemplate_Error", "Unknown template referenced by '{NodeTitle}' for @@"), Args).ToString(), this);
	}
}
UClass* FClassArchiveProxy::CreateClass(const FUHTMakefile& UHTMakefile) const
{
    UObject* Outer = UHTMakefile.GetObjectByIndex(OuterIndex);
    FName ClassName = Name.CreateName(UHTMakefile);
    UClass* Class = FindObject<UClass>(Outer, *ClassName.ToString());
    if (Class == nullptr || !Class->HasAnyClassFlags(CLASS_Native))
    {
        Class = new(EC_InternalUseOnlyConstructor, Outer, ClassName, (EObjectFlags)ObjectFlagsUint32) UClass(FObjectInitializer(), nullptr);
    }
    PostConstruct(Class);

    return Class;
}
示例#11
0
/**
 * Returns the text to use for exporting this property to header file.
 *
 * @param	ExtendedTypeText	for property types which use templates, will be filled in with the type
 * @param	CPPExportFlags		flags for modifying the behavior of the export
 */
FString UInterfaceProperty::GetCPPType( FString* ExtendedTypeText/*=NULL*/, uint32 CPPExportFlags/*=0*/ ) const
{
	checkSlow(InterfaceClass);

	if ( ExtendedTypeText != NULL )
	{
		UClass* ExportClass = InterfaceClass;
		if (0 == (CPPF_BlueprintCppBackend & CPPExportFlags))
		{
			while (ExportClass && !ExportClass->HasAnyClassFlags(CLASS_Native))
			{
				ExportClass = ExportClass->GetSuperClass();
			}
		}
		check(ExportClass);
		check(ExportClass->HasAnyClassFlags(CLASS_Interface) || 0 != (CPPF_BlueprintCppBackend & CPPExportFlags));

		*ExtendedTypeText = FString::Printf(TEXT("<I%s>"), *ExportClass->GetName());
	}

	return TEXT("TScriptInterface");
}
void FGameplayCueTranslationManager::RefreshNameSwaps()
{
	AllNameSwaps.Reset();
	TArray<UGameplayCueTranslator*> CDOList;

	// Gather CDOs
	for( TObjectIterator<UClass> It ; It ; ++It )
	{
		UClass* Class = *It;
		if( !Class->HasAnyClassFlags(CLASS_Abstract | CLASS_Deprecated) )
		{
			if( Class->IsChildOf(UGameplayCueTranslator::StaticClass()) )
			{
				UGameplayCueTranslator* CDO = Class->GetDefaultObject<UGameplayCueTranslator>();
				if (CDO->IsEnabled())
				{
					CDOList.Add(CDO);
				}
			}
		}
	}

	// Sort and get translated names
	CDOList.Sort([](const UGameplayCueTranslator& A, const UGameplayCueTranslator& B) { return (A.GetPriority() > B.GetPriority()); });

	for (UGameplayCueTranslator* CDO : CDOList)
	{
		FNameSwapData& Data = AllNameSwaps[AllNameSwaps.AddDefaulted()];
		CDO->GetTranslationNameSpawns(Data.NameSwaps);
		if (Data.NameSwaps.Num() > 0)
		{
			Data.ClassCDO = CDO;
		}
		else
		{
			AllNameSwaps.Pop(false);
		}
	}

#if WITH_EDITOR
	// Give UniqueID to each rule
	int32 ID=1;
	for (FNameSwapData& GroupData : AllNameSwaps)
	{
		for (FGameplayCueTranslationNameSwap& SwapData : GroupData.NameSwaps)
		{
			SwapData.EditorData.UniqueID = ID++;
		}
	}
#endif
}
示例#13
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;
}
	/** 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 FClassBrowseHelper::BuildClassGraph()
{
	UClass* RootNodeClass = UBTNode::StaticClass();

	TArray<TSharedPtr<FClassDataNode> > NodeList;
	RootNode.Reset();

	// gather all native classes
	for (TObjectIterator<UClass> It; It; ++It)
	{
		UClass* TestClass = *It;
		if (TestClass->HasAnyClassFlags(CLASS_Native) && TestClass->IsChildOf(RootNodeClass))
		{
			TSharedPtr<FClassDataNode> NewNode = MakeShareable(new FClassDataNode);
			NewNode->ParentClassName = TestClass->GetSuperClass()->GetName();
			
			FClassData NewData(TestClass);
			NewNode->Data = NewData;

			if (TestClass == RootNodeClass)
			{
				RootNode = NewNode;
			}

			NodeList.Add(NewNode);
		}
	}

	// gather all blueprints
	FAssetRegistryModule& AssetRegistryModule = FModuleManager::LoadModuleChecked<FAssetRegistryModule>(TEXT("AssetRegistry"));
	TArray<FAssetData> BlueprintList;

	FARFilter Filter;
	Filter.ClassNames.Add(UBlueprint::StaticClass()->GetFName());
	AssetRegistryModule.Get().GetAssets(Filter, BlueprintList);

	for (int32 i = 0; i < BlueprintList.Num(); i++)
	{
		TSharedPtr<FClassDataNode> NewNode = CreateClassDataNode(BlueprintList[i]);
		NodeList.Add(NewNode);
	}

	// build class tree
	AddClassGraphChildren(RootNode, NodeList);
}
	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 FBlueprintNodeSpawnerUtils::IsStaleFieldAction(UBlueprintNodeSpawner const* BlueprintAction)
{
	bool bHasStaleAssociatedField= false;

	const UField* AssociatedField = GetAssociatedField(BlueprintAction);
	if (AssociatedField != nullptr)
	{
		UClass* ClassOwner = AssociatedField->GetOwnerClass();
		if (ClassOwner != nullptr)
		{
			// check to see if this field belongs to a TRASH or REINST class,
			// maybe to a class that was thrown out because of a hot-reload?
			bHasStaleAssociatedField = ClassOwner->HasAnyClassFlags(CLASS_NewerVersionExists) || (ClassOwner->GetOutermost() == GetTransientPackage());
		}
	}

	return bHasStaleAssociatedField;
}
示例#18
0
void UEdGraphSchema::GetGraphContextActions(FGraphContextMenuBuilder& ContextMenuBuilder) const
{
#if WITH_EDITOR
	// Run thru all nodes and add any menu items they want to add
	for (TObjectIterator<UClass> ClassIt; ClassIt; ++ClassIt)
	{
		UClass* Class = *ClassIt;
		if (Class->IsChildOf(UEdGraphNode::StaticClass()) && !Class->HasAnyClassFlags(CLASS_Abstract | CLASS_Deprecated))
		{
			const UEdGraphNode* ClassCDO = Class->GetDefaultObject<UEdGraphNode>();

			if (ClassCDO->CanCreateUnderSpecifiedSchema(this))
			{
				ClassCDO->GetMenuEntries(ContextMenuBuilder);
			}
		}
	}
#endif
}
UClass* FGatherConvertedClassDependencies::GetFirstNativeOrConvertedClass(UClass* InClass, bool bExcludeBPDataOnly) const
{
	check(InClass);
	for (UClass* ItClass = InClass; ItClass; ItClass = ItClass->GetSuperClass())
	{
		UBlueprintGeneratedClass* BPGC = Cast<UBlueprintGeneratedClass>(ItClass);
		if (ItClass->HasAnyClassFlags(CLASS_Native) || WillClassBeConverted(BPGC))
		{
			if (bExcludeBPDataOnly)
			{
				UBlueprint* BP = BPGC ? Cast<UBlueprint>(BPGC->ClassGeneratedBy) : nullptr;
				if (BP && FBlueprintEditorUtils::IsDataOnlyBlueprint(BP))
				{
					continue;
				}
			}
			return ItClass;
		}
	}
	check(false);
	return nullptr;
};
void AActor::PostEditUndo(TSharedPtr<ITransactionObjectAnnotation> TransactionAnnotation)
{
	CurrentTransactionAnnotation = StaticCastSharedPtr<FActorTransactionAnnotation>(TransactionAnnotation);

	// Check if this Actor needs to be re-instanced
	UClass* OldClass = GetClass();
	if (OldClass->HasAnyClassFlags(CLASS_NewerVersionExists))
	{
		UClass* NewClass = OldClass->GetAuthoritativeClass();
		if (!ensure(NewClass != OldClass))
		{
			UE_LOG(LogActor, Warning, TEXT("WARNING: %s is out of date and is the same as its AuthoritativeClass during PostEditUndo!"), *OldClass->GetName());
		};

		// Early exit, letting anything more occur would be invalid due to the REINST_ class
		return;
	}


	// Notify LevelBounds actor that level bounding box might be changed
	if (!IsTemplate())
	{
		GetLevel()->MarkLevelBoundsDirty();
	}

	// Restore OwnedComponents array
	if (!IsPendingKill())
	{
		ResetOwnedComponents();
		// notify navigation system
		UNavigationSystem::UpdateActorAndComponentsInNavOctree(*this);
	}
	else
	{
		UNavigationSystem::ClearNavOctreeAll(this);
	}

	Super::PostEditUndo(TransactionAnnotation);
}
TArray<FFactoryItem> FindFactoriesInCategory(EAssetTypeCategories::Type AssetTypeCategory)
{
	TArray<FFactoryItem> FactoriesInThisCategory;
	for (TObjectIterator<UClass> It; It; ++It)
	{
		UClass* Class = *It;
		if (Class->IsChildOf(UFactory::StaticClass()) && !Class->HasAnyClassFlags(CLASS_Abstract))
		{
			UFactory* Factory = Class->GetDefaultObject<UFactory>();
			if (Factory->ShouldShowInNewMenu() && ensure(!Factory->GetDisplayName().IsEmpty()))
			{
				uint32 FactoryCategories = Factory->GetMenuCategories();

				if (FactoryCategories & AssetTypeCategory)
				{
					new(FactoriesInThisCategory)FFactoryItem(Factory, Factory->GetDisplayName());
				}
			}
		}
	}

	return FactoriesInThisCategory;
}
FString FClassData::ToString() const
{
	UClass* MyClass = Class.Get();
	if (MyClass)
	{
		FString ClassDesc = MyClass->GetName();

		if (MyClass->HasAnyClassFlags(CLASS_CompiledFromBlueprint))
		{
			return ClassDesc.LeftChop(2);
		}

		const int32 ShortNameIdx = ClassDesc.Find(TEXT("_"));
		if (ShortNameIdx != INDEX_NONE)
		{
			ClassDesc = ClassDesc.Mid(ShortNameIdx + 1);
		}

		return ClassDesc;
	}

	return AssetName;
}
void UGameplayTagsManager::ConstructGameplayTagTree()
{
	if (!GameplayRootTag.IsValid())
	{
		GameplayRootTag = MakeShareable(new FGameplayTagNode());
		
		for (auto It(GameplayTagTables.CreateIterator()); It; It++)
		{
			PopulateTreeFromDataTable(*It);
		}

		if (ShouldImportTagsFromINI())
		{
			// Load any GameplayTagSettings from config (their default object)
			for (TObjectIterator<UClass> ClassIt; ClassIt; ++ClassIt)
			{
				UClass* Class = *ClassIt;
				if (!Class->IsChildOf<UGameplayTagsSettings>() || Class->HasAnyClassFlags(CLASS_Abstract))
				{
					continue;
				}

				for (FString TagStr : Class->GetDefaultObject<UGameplayTagsSettings>()->GameplayTags)
				{
					FGameplayTagTableRow TableRow;
					TableRow.Tag = TagStr;
					AddTagTableRow(TableRow);
				}

		
			}
			GameplayRootTag->GetChildTagNodes().Sort(FCompareFGameplayTagNodeByTag());
		}

		GameplayTagTreeChangedEvent.Broadcast();
	}
}
示例#24
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;
}
bool FComponentEditorUtils::CanCopyComponents(const TArray<UActorComponent*>& ComponentsToCopy)
{
	bool bCanCopy = ComponentsToCopy.Num() > 0;
	if (bCanCopy)
	{
		for (int32 i = 0; i < ComponentsToCopy.Num() && bCanCopy; ++i)
		{
			// Check for the default scene root; that cannot be copied/duplicated
			UActorComponent* Component = ComponentsToCopy[i];
			bCanCopy = Component != nullptr && Component->GetFName() != USceneComponent::GetDefaultSceneRootVariableName();
			if (bCanCopy)
			{
				UClass* ComponentClass = Component->GetClass();
				check(ComponentClass != nullptr);

				// Component class cannot be abstract and must also be tagged as BlueprintSpawnable
				bCanCopy = !ComponentClass->HasAnyClassFlags(CLASS_Abstract)
					&& ComponentClass->HasMetaData(FBlueprintMetadata::MD_BlueprintSpawnableComponent);
			}
		}
	}

	return bCanCopy;
}
示例#26
0
void UK2Node_LatentAbilityCall::GetMenuActions(FBlueprintActionDatabaseRegistrar& ActionRegistrar) const
{
	// these nested loops are combing over the same classes/functions the
	// FBlueprintActionDatabase does; ideally we save on perf and fold this in
	// with FBlueprintActionDatabase, but we want to keep the modules separate
	for (TObjectIterator<UClass> ClassIt; ClassIt; ++ClassIt)
	{
		UClass* Class = *ClassIt;
		if (!Class->IsChildOf<UAbilityTask>() || Class->HasAnyClassFlags(CLASS_Abstract))
		{
			continue;
		}
		
		for (TFieldIterator<UFunction> FuncIt(Class, EFieldIteratorFlags::ExcludeSuper); FuncIt; ++FuncIt)
		{
			UFunction* Function = *FuncIt;
			if (!Function->HasAnyFunctionFlags(FUNC_Static))
			{
				continue;
			}

			// to keep from needlessly instantiating a UBlueprintNodeSpawner, first   
			// check to make sure that the registrar is looking for actions of this type
			// (could be regenerating actions for a specific asset, and therefore the 
			// registrar would only accept actions corresponding to that asset)
			if (!ActionRegistrar.IsOpenForRegistration(Function))
			{
				continue;
			}

			UObjectProperty* ReturnProperty = Cast<UObjectProperty>(Function->GetReturnProperty());
			// see if the function is a static factory method for online proxies
			bool const bIsProxyFactoryMethod = (ReturnProperty != nullptr) && ReturnProperty->PropertyClass->IsChildOf<UAbilityTask>();
			
			if (bIsProxyFactoryMethod)
			{
				UBlueprintNodeSpawner* NodeSpawner = UBlueprintFunctionNodeSpawner::Create(Function);
				check(NodeSpawner != nullptr);
				NodeSpawner->NodeClass = GetClass();
				
				auto CustomizeAcyncNodeLambda = [](UEdGraphNode* NewNode, bool bIsTemplateNode, TWeakObjectPtr<UFunction> FunctionPtr)
				{
					UK2Node_LatentAbilityCall* AsyncTaskNode = CastChecked<UK2Node_LatentAbilityCall>(NewNode);
					if (FunctionPtr.IsValid())
					{
						UFunction* Func = FunctionPtr.Get();
						UObjectProperty* ReturnProp = CastChecked<UObjectProperty>(Func->GetReturnProperty());
						
						AsyncTaskNode->ProxyFactoryFunctionName = Func->GetFName();
						AsyncTaskNode->ProxyFactoryClass        = Func->GetOuterUClass();
						AsyncTaskNode->ProxyClass               = ReturnProp->PropertyClass;
					}
				};
				
				TWeakObjectPtr<UFunction> FunctionPtr = Function;
				NodeSpawner->CustomizeNodeDelegate = UBlueprintNodeSpawner::FCustomizeNodeDelegate::CreateStatic(CustomizeAcyncNodeLambda, FunctionPtr);
				
				// @TODO: since this can't be folded into FBlueprintActionDatabase, we
				//        need a way to associate these spawners with a certain class
				ActionRegistrar.AddBlueprintAction(Function, NodeSpawner);
			}
		}
	}
}
void FBlueprintCompileReinstancer::ReplaceInstancesOfClass(UClass* OldClass, UClass* NewClass, UObject*	OriginalCDO, TSet<UObject*>* ObjectsThatShouldUseOldStuff)
{
	USelection* SelectedActors;
	bool bSelectionChanged = false;
	TArray<UObject*> ObjectsToReplace;
	const bool bLogConversions = false; // for debugging

	// Map of old objects to new objects
	TMap<UObject*, UObject*> OldToNewInstanceMap;
	TMap<UClass*, UClass*>   OldToNewClassMap;
	OldToNewClassMap.Add(OldClass, NewClass);

	TMap<FStringAssetReference, UObject*> ReinstancedObjectsWeakReferenceMap;

	// actors being replace
	TArray<FActorReplacementHelper> ReplacementActors;

	// A list of objects (e.g. Blueprints) that potentially have editors open that we need to refresh
	TArray<UObject*> PotentialEditorsForRefreshing;

	// A list of component owners that need their construction scripts re-ran (because a component of theirs has been reinstanced)
	TSet<AActor*> OwnersToReconstruct;

	// Set global flag to let system know we are reconstructing blueprint instances
	TGuardValue<bool> GuardTemplateNameFlag(GIsReconstructingBlueprintInstances, true);

	struct FObjectRemappingHelper
	{
		void OnObjectsReplaced(const TMap<UObject*, UObject*>& InReplacedObjects)
		{
			ReplacedObjects.Append(InReplacedObjects);
		}

		TMap<UObject*, UObject*> ReplacedObjects;
	} ObjectRemappingHelper;

	FDelegateHandle OnObjectsReplacedHandle = GEditor->OnObjectsReplaced().AddRaw(&ObjectRemappingHelper,&FObjectRemappingHelper::OnObjectsReplaced);

	{ BP_SCOPED_COMPILER_EVENT_STAT(EKismetReinstancerStats_ReplaceInstancesOfClass);


		const bool bIncludeDerivedClasses = false;
		GetObjectsOfClass(OldClass, ObjectsToReplace, bIncludeDerivedClasses);
	
		SelectedActors = GEditor->GetSelectedActors();
		SelectedActors->BeginBatchSelectOperation();
		SelectedActors->Modify();
		
		// Then fix 'real' (non archetype) instances of the class
		for (UObject* OldObject : ObjectsToReplace)
		{
			// Skip non-archetype instances, EXCEPT for component templates
			const bool bIsComponent = NewClass->IsChildOf(UActorComponent::StaticClass());
			if ((!bIsComponent && OldObject->IsTemplate()) || OldObject->IsPendingKill())
			{
				continue;
			}

			UBlueprint* CorrespondingBlueprint  = Cast<UBlueprint>(OldObject->GetClass()->ClassGeneratedBy);
			UObject*    OldBlueprintDebugObject = nullptr;
			// If this object is being debugged, cache it off so we can preserve the 'object being debugged' association
			if ((CorrespondingBlueprint != nullptr) && (CorrespondingBlueprint->GetObjectBeingDebugged() == OldObject))
			{
				OldBlueprintDebugObject = OldObject;
			}

			AActor*  OldActor = Cast<AActor>(OldObject);
			UObject* NewUObject = nullptr;
			// if the object to replace is an actor...
			if (OldActor != nullptr)
			{
				FVector  Location = FVector::ZeroVector;
				FRotator Rotation = FRotator::ZeroRotator;
				if (USceneComponent* OldRootComponent = OldActor->GetRootComponent())
				{
					Location = OldActor->GetActorLocation();
					Rotation = OldActor->GetActorRotation();
				}

				// If this actor was spawned from an Archetype, we spawn the new actor from the new version of that archetype
				UObject* OldArchetype = OldActor->GetArchetype();
				UWorld*  World        = OldActor->GetWorld();
				AActor*  NewArchetype = Cast<AActor>(OldToNewInstanceMap.FindRef(OldArchetype));
				// Check that either this was an instance of the class directly, or we found a new archetype for it
				check(OldArchetype == OldClass->GetDefaultObject() || NewArchetype);

				// Spawn the new actor instance, in the same level as the original, but deferring running the construction script until we have transferred modified properties
				ULevel*  ActorLevel  = OldActor->GetLevel();
				UClass** MappedClass = OldToNewClassMap.Find(OldActor->GetClass());
				UClass*  SpawnClass  = MappedClass ? *MappedClass : NewClass;

				FActorSpawnParameters SpawnInfo;
				SpawnInfo.OverrideLevel      = ActorLevel;
				SpawnInfo.Template           = NewArchetype;
				SpawnInfo.bNoCollisionFail   = true;
				SpawnInfo.bDeferConstruction = true;

				// Temporarily remove the deprecated flag so we can respawn the Blueprint in the level
				const bool bIsClassDeprecated = SpawnClass->HasAnyClassFlags(CLASS_Deprecated);
				SpawnClass->ClassFlags &= ~CLASS_Deprecated;

				AActor* NewActor = World->SpawnActor(SpawnClass, &Location, &Rotation, SpawnInfo);
				// Reassign the deprecated flag if it was previously assigned
				if (bIsClassDeprecated)
				{
					SpawnClass->ClassFlags |= CLASS_Deprecated;
				}

				check(NewActor != nullptr);
				NewUObject = NewActor;
				// store the new actor for the second pass (NOTE: this detaches 
				// OldActor from all child/parent attachments)
				//
				// running the NewActor's construction-script is saved for that 
				// second pass (because the construction-script may reference 
				// another instance that hasn't been replaced yet).
				ReplacementActors.Add(FActorReplacementHelper(NewActor, OldActor));

				ReinstancedObjectsWeakReferenceMap.Add(OldObject, NewUObject);

				OldActor->DestroyConstructedComponents(); // don't want to serialize components from the old actor
				// Unregister native components so we don't copy any sub-components they generate for themselves (like UCameraComponent does)
				OldActor->UnregisterAllComponents();

				// Unregister any native components, might have cached state based on properties we are going to overwrite
				NewActor->UnregisterAllComponents(); 

				UEditorEngine::CopyPropertiesForUnrelatedObjects(OldActor, NewActor);
				// reset properties/streams
				NewActor->ResetPropertiesForConstruction(); 
				// register native components
				NewActor->RegisterAllComponents(); 

				// 
				// clean up the old actor (unselect it, remove it from the world, etc.)...

				if (OldActor->IsSelected())
				{
					GEditor->SelectActor(OldActor, /*bInSelected =*/false, /*bNotify =*/false);
					bSelectionChanged = true;
				}
				if (GEditor->Layers.IsValid()) // ensure(NULL != GEditor->Layers) ?? While cooking the Layers is NULL.
				{
					GEditor->Layers->DisassociateActorFromLayers(OldActor);
				}

 				World->EditorDestroyActor(OldActor, /*bShouldModifyLevel =*/true);
 				OldToNewInstanceMap.Add(OldActor, NewActor);
			}
			else
			{
				FName OldName(OldObject->GetFName());
				OldObject->Rename(NULL, OldObject->GetOuter(), REN_DoNotDirty | REN_DontCreateRedirectors);
				NewUObject = NewObject<UObject>(OldObject->GetOuter(), NewClass, OldName);
				check(NewUObject != nullptr);

				UEditorEngine::CopyPropertiesForUnrelatedObjects(OldObject, NewUObject);

				if (UAnimInstance* AnimTree = Cast<UAnimInstance>(NewUObject))
				{
					// Initialising the anim instance isn't enough to correctly set up the skeletal mesh again in a
					// paused world, need to initialise the skeletal mesh component that contains the anim instance.
					if (USkeletalMeshComponent* SkelComponent = Cast<USkeletalMeshComponent>(AnimTree->GetOuter()))
					{
						SkelComponent->InitAnim(true);
					}
				}

				OldObject->RemoveFromRoot();
				OldObject->MarkPendingKill();

				OldToNewInstanceMap.Add(OldObject, NewUObject);

				if (bIsComponent)
				{
					UActorComponent* Component = Cast<UActorComponent>(NewUObject);
					AActor* OwningActor = Component->GetOwner();
					if (OwningActor)
					{
						OwningActor->ResetOwnedComponents();

						// Check to see if they have an editor that potentially needs to be refreshed
						if (OwningActor->GetClass()->ClassGeneratedBy)
						{
							PotentialEditorsForRefreshing.AddUnique(OwningActor->GetClass()->ClassGeneratedBy);
						}

						// we need to keep track of actor instances that need 
						// their construction scripts re-ran (since we've just 
						// replaced a component they own)
						OwnersToReconstruct.Add(OwningActor);
					}
				}
			}

			// If this original object came from a blueprint and it was in the selected debug set, change the debugging to the new object.
			if ((CorrespondingBlueprint) && (OldBlueprintDebugObject) && (NewUObject))
			{
				CorrespondingBlueprint->SetObjectBeingDebugged(NewUObject);
			}

			if (bLogConversions)
			{
				UE_LOG(LogBlueprint, Log, TEXT("Converted instance '%s' to '%s'"), *OldObject->GetPathName(), *NewUObject->GetPathName());
			}
		}
	}

	GEditor->OnObjectsReplaced().Remove(OnObjectsReplacedHandle);

	// Now replace any pointers to the old archetypes/instances with pointers to the new one
	TArray<UObject*> SourceObjects;
	TArray<UObject*> DstObjects;

	OldToNewInstanceMap.GenerateKeyArray(SourceObjects);
	OldToNewInstanceMap.GenerateValueArray(DstObjects); // Also look for references in new spawned objects.

	SourceObjects.Append(DstObjects);

	FReplaceReferenceHelper::IncludeCDO(OldClass, NewClass, OldToNewInstanceMap, SourceObjects, OriginalCDO);
	FReplaceReferenceHelper::FindAndReplaceReferences(SourceObjects, ObjectsThatShouldUseOldStuff, ObjectsToReplace, OldToNewInstanceMap, ReinstancedObjectsWeakReferenceMap);

	{ BP_SCOPED_COMPILER_EVENT_STAT(EKismetReinstancerStats_ReplacementConstruction);

		// the process of setting up new replacement actors is split into two 
		// steps (this here, is the second)...
		// 
		// the "finalization" here runs the replacement actor's construction-
		// script and is left until late to account for a scenario where the 
		// construction-script attempts to modify another instance of the 
		// same class... if this were to happen above, in the ObjectsToReplace 
		// loop, then accessing that other instance would cause an assert in 
		// UProperty::ContainerPtrToValuePtrInternal() (which appropriatly 
		// complains that the other instance's type doesn't match because it 
		// hasn't been replaced yet... that's why we wait until after 
		// FArchiveReplaceObjectRef to run construction-scripts).
		for (FActorReplacementHelper& ReplacementActor : ReplacementActors)
		{
			ReplacementActor.Finalize(ObjectRemappingHelper.ReplacedObjects);
		}
	}

	SelectedActors->EndBatchSelectOperation();
	if (bSelectionChanged)
	{
		GEditor->NoteSelectionChange();
	}

	if (GEditor)
	{
		// Refresh any editors for objects that we've updated components for
		for (auto BlueprintAsset : PotentialEditorsForRefreshing)
		{
			FBlueprintEditor* BlueprintEditor = static_cast<FBlueprintEditor*>(FAssetEditorManager::Get().FindEditorForAsset(BlueprintAsset, /*bFocusIfOpen =*/false));
			if (BlueprintEditor)
			{
				BlueprintEditor->RefreshEditors();
			}
		}
	}

	// in the case where we're replacing component instances, we need to make 
	// sure to re-run their owner's construction scripts
	for (AActor* ActorInstance : OwnersToReconstruct)
	{
		ActorInstance->RerunConstructionScripts();
	}
}
void SAnimationCompressionPanel::Construct(const FArguments& InArgs)
{
	AnimSequences = InArgs._AnimSequences;
	CurrentCompressionChoice = 0;

	for ( TObjectIterator<UClass> It ; It ; ++It )
	{
		UClass* Class = *It;
		if( !Class->HasAnyClassFlags(CLASS_Abstract | CLASS_Deprecated) )
		{
			if ( Class->IsChildOf(UAnimCompress::StaticClass()) )
			{
				UAnimCompress* NewAlgorithm = ConstructObject<UAnimCompress>( Class );
				AnimationCompressionAlgorithms.Add( NewAlgorithm );
			}
		}
	}

	TSharedRef<SVerticalBox> Box =
		SNew(SVerticalBox)
		+SVerticalBox::Slot()
		.AutoHeight()
		.Padding(8.0f, 4.0f, 8.0f, 4.0f)
		[
			SNew( STextBlock )
			.Text( LOCTEXT("AnimCompressionLabel", "Compression Algorithms") )
		]
		+SVerticalBox::Slot()
		.AutoHeight()
		.Padding(8.0f, 4.0f, 8.0f, 4.0f)
		[
			SNew(SSeparator)
		];

	for( int32 i = 0 ; i < AnimationCompressionAlgorithms.Num() ; ++i )
	{
		UAnimCompress* Alg = AnimationCompressionAlgorithms[i];
		(*Box).AddSlot()
		.Padding(8.0f, 4.0f, 8.0f, 4.0f)
		[
			CreateRadioButton( FText::FromString( Alg->Description ), i)
		];
	}

	(*Box)	.AddSlot()
			.AutoHeight()
			.Padding(8.0f, 4.0f, 4.0f, 8.0f)
			[
				SNew(SSeparator)
			];
	(*Box)	.AddSlot()
			.Padding(4.0f)
			.HAlign(HAlign_Right)
			.VAlign(VAlign_Bottom)
			.AutoHeight()
			[
				SNew(SUniformGridPanel)
				.SlotPadding(FEditorStyle::GetMargin("StandardDialog.SlotPadding"))
				.MinDesiredSlotWidth(FEditorStyle::GetFloat("StandardDialog.MinDesiredSlotWidth"))
				.MinDesiredSlotHeight(FEditorStyle::GetFloat("StandardDialog.MinDesiredSlotHeight"))
				+SUniformGridPanel::Slot(0,0)
				[
					SNew(SButton)
					.Text(LOCTEXT("AnimCompressionApply", "Apply").ToString())
					.HAlign(HAlign_Center)
					.ContentPadding(FEditorStyle::GetMargin("StandardDialog.ContentPadding"))
					.OnClicked(this, &SAnimationCompressionPanel::ApplyClicked)
				]
			];
	
	this->ChildSlot[Box];
}
void SPropertyEditorAsset::Construct( const FArguments& InArgs, const TSharedPtr<FPropertyEditor>& InPropertyEditor )
{
	PropertyEditor = InPropertyEditor;
	PropertyHandle = InArgs._PropertyHandle;
	OnSetObject = InArgs._OnSetObject;
	OnShouldFilterAsset = InArgs._OnShouldFilterAsset;

	UProperty* Property = nullptr;
	if(PropertyEditor.IsValid())
	{
		Property = PropertyEditor->GetPropertyNode()->GetProperty();
		UObjectPropertyBase* ObjectProperty = Cast<UObjectPropertyBase>(Property);
		check(ObjectProperty);

		bAllowClear = !(Property->PropertyFlags & CPF_NoClear);
		ObjectClass = ObjectProperty->PropertyClass;
		bIsActor = ObjectProperty->PropertyClass->IsChildOf( AActor::StaticClass() );
	}
	else
	{
		bAllowClear = InArgs._AllowClear;
		ObjectPath = InArgs._ObjectPath;
		ObjectClass = InArgs._Class;
		bIsActor = ObjectClass->IsChildOf( AActor::StaticClass() );

		if (PropertyHandle.IsValid() && PropertyHandle->IsValidHandle())
		{
			Property = PropertyHandle->GetProperty();
		}
		else
		{
			CustomClassFilters.Add(ObjectClass);
		}
	}

	// Account for the allowed classes specified in the property metadata
	if (Property)
	{
		FString ClassFilterString;
		if (UArrayProperty* ArrayParent = Cast<UArrayProperty>(Property->GetOuter()))
		{
			ClassFilterString = ArrayParent->GetMetaData("AllowedClasses");
		}
		else
		{
			ClassFilterString = Property->GetMetaData("AllowedClasses");
		}

		if (ClassFilterString.IsEmpty())
		{
			CustomClassFilters.Add(ObjectClass);
		}
		else
		{
			TArray<FString> CustomClassFilterNames;
			ClassFilterString.ParseIntoArray(CustomClassFilterNames, TEXT(","), true);

			for (auto It = CustomClassFilterNames.CreateConstIterator(); It; ++It)
			{
				const FString& ClassName = *It;

				UClass* Class = FindObject<UClass>(ANY_PACKAGE, *ClassName);

				if (!Class)
				{
					Class = LoadObject<UClass>(nullptr, *ClassName);
				}

				if (Class)
				{
					// If the class is an interface, expand it to be all classes in memory that implement the class.
					if (Class->HasAnyClassFlags(CLASS_Interface))
					{
						for (TObjectIterator<UClass> ClassIt; ClassIt; ++ClassIt)
						{
							UClass* const ClassWithInterface = (*ClassIt);
							if (ClassWithInterface->ImplementsInterface(Class))
							{
								CustomClassFilters.Add(ClassWithInterface);
							}
						}
					}
					else
					{
						CustomClassFilters.Add(Class);
					}
				}
			}
		}
	}

	if (InArgs._NewAssetFactories.IsSet())
	{
		NewAssetFactories = InArgs._NewAssetFactories.GetValue();
	}
	else if (CustomClassFilters.Num() > 1 || !CustomClassFilters.Contains(UObject::StaticClass()))
	{
		NewAssetFactories = PropertyCustomizationHelpers::GetNewAssetFactoriesForClasses(CustomClassFilters);
	}
	
	TSharedPtr<SHorizontalBox> ValueContentBox = NULL;
	ChildSlot
	[
		SNew( SAssetDropTarget )
		.OnIsAssetAcceptableForDrop( this, &SPropertyEditorAsset::OnAssetDraggedOver )
		.OnAssetDropped( this, &SPropertyEditorAsset::OnAssetDropped )
		[
			SAssignNew( ValueContentBox, SHorizontalBox )	
		]
	];

	TAttribute<bool> IsEnabledAttribute(this, &SPropertyEditorAsset::CanEdit);
	TAttribute<FText> TooltipAttribute(this, &SPropertyEditorAsset::OnGetToolTip);

	if (Property && Property->HasAllPropertyFlags(CPF_DisableEditOnTemplate))
	{
		// There are some cases where editing an Actor Property is not allowed, such as when it is contained within a struct or a CDO
		TArray<UObject*> ObjectList;
		PropertyEditor->GetPropertyHandle()->GetOuterObjects(ObjectList);

		// If there is no objects, that means we must have a struct asset managing this property
		if (ObjectList.Num() == 0)
		{
			IsEnabledAttribute.Set(false);
			TooltipAttribute.Set(LOCTEXT("VariableHasDisableEditOnTemplate", "Editing this value in structure's defaults is not allowed"));
		}
		else
		{
			// Go through all the found objects and see if any are a CDO, we can't set an actor in a CDO default.
			for (UObject* Obj : ObjectList)
			{
				if (Obj->HasAllFlags(RF_ClassDefaultObject))
				{
					IsEnabledAttribute.Set(false);
					TooltipAttribute.Set(LOCTEXT("VariableHasDisableEditOnTemplateTooltip", "Editing this value in a Class Default Object is not allowed"));
					break;
				}

			}
		}
	}

	AssetComboButton = SNew(SComboButton)
		.ToolTipText(TooltipAttribute)
		.ButtonStyle( FEditorStyle::Get(), "PropertyEditor.AssetComboStyle" )
		.ForegroundColor(FEditorStyle::GetColor("PropertyEditor.AssetName.ColorAndOpacity"))
		.OnGetMenuContent( this, &SPropertyEditorAsset::OnGetMenuContent )
		.OnMenuOpenChanged( this, &SPropertyEditorAsset::OnMenuOpenChanged )
		.IsEnabled( IsEnabledAttribute )
		.ContentPadding(2.0f)
		.ButtonContent()
		[
			// Show the name of the asset or actor
			SNew(STextBlock)
			.TextStyle( FEditorStyle::Get(), "PropertyEditor.AssetClass" )
			.Font( FEditorStyle::GetFontStyle( PropertyEditorConstants::PropertyFontStyle ) )
			.Text(this,&SPropertyEditorAsset::OnGetAssetName)
		];

	
	TSharedRef<SHorizontalBox> ButtonBox = SNew( SHorizontalBox );
	
	TSharedPtr<SVerticalBox> CustomContentBox;

	if( ShouldDisplayThumbnail(InArgs) )
	{
		FObjectOrAssetData Value; 
		GetValue( Value );

		AssetThumbnail = MakeShareable( new FAssetThumbnail( Value.AssetData, InArgs._ThumbnailSize.X, InArgs._ThumbnailSize.Y, InArgs._ThumbnailPool ) );

		ValueContentBox->AddSlot()
		.Padding( 0.0f, 0.0f, 2.0f, 0.0f )
		.AutoWidth()
		[
			SAssignNew( ThumbnailBorder, SBorder )
			.Padding( 5.0f )
			.BorderImage( this, &SPropertyEditorAsset::GetThumbnailBorder )
			.OnMouseDoubleClick( this, &SPropertyEditorAsset::OnAssetThumbnailDoubleClick )
			[
				SNew( SBox )
				.ToolTipText(TooltipAttribute)
				.WidthOverride( InArgs._ThumbnailSize.X ) 
				.HeightOverride( InArgs._ThumbnailSize.Y )
				[
					AssetThumbnail->MakeThumbnailWidget()
				]
			]
		];


		ValueContentBox->AddSlot()
		[
			SNew( SBox )
			.VAlign( VAlign_Center )
			[
				SAssignNew( CustomContentBox, SVerticalBox )
				+ SVerticalBox::Slot()
				[
					AssetComboButton.ToSharedRef()
				]
				+ SVerticalBox::Slot()
				.AutoHeight()
				.Padding( 0.0f, 2.0f, 4.0f, 2.0f )
				[
					ButtonBox
				]
			]
		];
	}
	else
	{
		ValueContentBox->AddSlot()
		[
			SAssignNew( CustomContentBox, SVerticalBox )
			+SVerticalBox::Slot()
			.VAlign( VAlign_Center )
			[
				SNew( SHorizontalBox )
				+ SHorizontalBox::Slot()
				[
					AssetComboButton.ToSharedRef()
				]
				+ SHorizontalBox::Slot()
				.AutoWidth()
				.Padding( 4.f, 0.f )
				[
					ButtonBox
				]
			]
		];
	}

	if( InArgs._CustomContentSlot.Widget != SNullWidget::NullWidget )
	{
		CustomContentBox->AddSlot()
		.VAlign( VAlign_Center )
		.Padding( FMargin( 0.0f, 2.0f ) )
		[
			InArgs._CustomContentSlot.Widget
		];
	}

	if( !bIsActor && InArgs._DisplayUseSelected )
	{
		ButtonBox->AddSlot()
		.VAlign(VAlign_Center)
		.AutoWidth()
		.Padding( 2.0f, 0.0f )
		[
			PropertyCustomizationHelpers::MakeUseSelectedButton( FSimpleDelegate::CreateSP( this, &SPropertyEditorAsset::OnUse ), FText(), IsEnabledAttribute )
		];
	}

	if( InArgs._DisplayBrowse )
	{
		ButtonBox->AddSlot()
		.Padding( 2.0f, 0.0f )
		.AutoWidth()
		.VAlign(VAlign_Center)
		[
			PropertyCustomizationHelpers::MakeBrowseButton(
				FSimpleDelegate::CreateSP( this, &SPropertyEditorAsset::OnBrowse ),
				TAttribute<FText>( this, &SPropertyEditorAsset::GetOnBrowseToolTip )
				)
		];
	}

	if( bIsActor )
	{
		TSharedRef<SWidget> ActorPicker = PropertyCustomizationHelpers::MakeInteractiveActorPicker( FOnGetAllowedClasses::CreateSP(this, &SPropertyEditorAsset::OnGetAllowedClasses), FOnShouldFilterActor(), FOnActorSelected::CreateSP( this, &SPropertyEditorAsset::OnActorSelected ) );
		ActorPicker->SetEnabled( IsEnabledAttribute );

		ButtonBox->AddSlot()
		.Padding( 2.0f, 0.0f )
		.AutoWidth()
		.VAlign(VAlign_Center)
		[
			ActorPicker
		];
	}

	if( InArgs._ResetToDefaultSlot.Widget != SNullWidget::NullWidget )
	{
		TSharedRef<SWidget> ResetToDefaultWidget  = InArgs._ResetToDefaultSlot.Widget;
		ResetToDefaultWidget->SetEnabled( IsEnabledAttribute );

		ButtonBox->AddSlot()
		.Padding( 4.0f, 0.0f )
		.AutoWidth()
		.VAlign(VAlign_Center)
		[
			ResetToDefaultWidget
		];
	}
}
void UGameplayTagsManager::ConstructGameplayTagTree()
{
	if (!GameplayRootTag.IsValid())
	{
		GameplayRootTag = MakeShareable(new FGameplayTagNode());
		{
#if STATS
			FString PerfMessage = FString::Printf(TEXT("UGameplayTagsManager::ConstructGameplayTagTree: Construct from data asset"));
			SCOPE_LOG_TIME_IN_SECONDS(*PerfMessage, nullptr)
#endif
		
			for (auto It(GameplayTagTables.CreateIterator()); It; It++)
			{
				if (*It)
				{
					PopulateTreeFromDataTable(*It);
				}
			}
		}

		if (ShouldImportTagsFromINI())
		{
#if STATS
			FString PerfMessage = FString::Printf(TEXT("UGameplayTagsManager::ConstructGameplayTagTree: ImportINI"));
			SCOPE_LOG_TIME_IN_SECONDS(*PerfMessage, nullptr)
#endif

			// Update path: Check for old tags in DefaultEngine.ini (we'll push them to the UGameplayTagSettings class).
			TArray<FString> EngineConfigTags;
			GConfig->GetArray(TEXT("/Script/GameplayTags.GameplayTagsSettings"), TEXT("GameplayTags"), EngineConfigTags, GEngineIni);
			if (EngineConfigTags.Num() > 0)
			{
				UGameplayTagsSettings* MutableDefault = GetMutableDefault<UGameplayTagsSettings>();
				if (MutableDefault->GameplayTags.Num() == 0)
				{
					MutableDefault->GameplayTags.Append(EngineConfigTags);
				}
			}

			// Load any GameplayTagSettings from config (their default object)
			for (TObjectIterator<UClass> ClassIt; ClassIt; ++ClassIt)
			{
				UClass* Class = *ClassIt;
				if (!Class->IsChildOf<UGameplayTagsSettings>() || Class->HasAnyClassFlags(CLASS_Abstract))
				{
					continue;
				}

#if WITH_EDITOR
				Class->GetDefaultObject<UGameplayTagsSettings>()->SortTags();
#endif
				
				for (FString TagStr : Class->GetDefaultObject<UGameplayTagsSettings>()->GameplayTags)
				{
					FGameplayTagTableRow TableRow;
					TableRow.Tag = TagStr;
					AddTagTableRow(TableRow);
				}
			}
			GameplayRootTag->GetChildTagNodes().Sort(FCompareFGameplayTagNodeByTag());
		}

		if (ShouldUseFastReplication())
		{
#if STATS
			FString PerfMessage = FString::Printf(TEXT("UGameplayTagsManager::ConstructGameplayTagTree: Reconstruct NetIndex"));
			SCOPE_LOG_TIME_IN_SECONDS(*PerfMessage, nullptr)
#endif
			ConstructNetIndex();
		}

		{
#if STATS
			FString PerfMessage = FString::Printf(TEXT("UGameplayTagsManager::ConstructGameplayTagTree: GameplayTagTreeChangedEvent.Broadcast"));
			SCOPE_LOG_TIME_IN_SECONDS(*PerfMessage, nullptr)
#endif
			GameplayTagTreeChangedEvent.Broadcast();
		}

		// Update the TagRedirects map
		TagRedirects.Empty();
		FConfigSection* PackageRedirects = GConfig->GetSectionPrivate(TEXT("/Script/Engine.Engine"), false, true, GEngineIni);
		for (FConfigSection::TIterator It(*PackageRedirects); It; ++It)
		{
			if (It.Key() == TEXT("GameplayTagRedirects"))
			{
				FName OldTagName = NAME_None;
				FName NewTagName;

				if (FParse::Value(*It.Value(), TEXT("OldTagName="), OldTagName))
				{
					if (FParse::Value(*It.Value(), TEXT("NewTagName="), NewTagName))
					{
						if (ensureMsgf(!TagRedirects.Contains(OldTagName), TEXT("Old tag %s is being redirected to more than one tag. Please remove all the redirections except for one."), *OldTagName.ToString()))
						{
							FGameplayTag OldTag = RequestGameplayTag(OldTagName, false); //< This only succeeds if OldTag is in the Table!
							if (OldTag.IsValid())
							{
								UE_LOG(LogGameplayTags, Warning,
									TEXT("Old tag (%s) which is being redirected still exists in the table!  Generally you should "
									TEXT("remove the old tags from the table when you are redirecting to new tags, or else users will ")
									TEXT("still be able to add the old tags to containers.")), *OldTagName.ToString()
									);
							}

							FGameplayTag NewTag = (NewTagName != NAME_None) ? RequestGameplayTag(NewTagName, false) : FGameplayTag();
							if (!NewTag.IsValid() && NewTagName != NAME_None)
							{
								UE_LOG(LogGameplayTags, Warning, TEXT("Invalid new tag %s!  Cannot replace old tag %s."),
									*NewTagName.ToString(), *OldTagName.ToString());
							}
							else
							{
								// Populate the map
								TagRedirects.Add(OldTagName, NewTag);
							}
						}
					}
				}
			}
		}
	}