// Copyright Epic Games, Inc. All Rights Reserved. #include "EditorValidator_Blueprints.h" #include "AssetRegistry/AssetData.h" #include "AssetRegistry/AssetRegistryModule.h" #include "AssetRegistry/IAssetRegistry.h" #include "Blueprint/BlueprintSupport.h" #include "Containers/Set.h" #include "Containers/UnrealString.h" #include "Engine/Blueprint.h" #include "HAL/Platform.h" #include "Internationalization/Text.h" #include "Kismet2/BlueprintEditorUtils.h" #include "Logging/LogCategory.h" #include "Logging/LogMacros.h" #include "LyraEditor.h" #include "Misc/AssertionMacros.h" #include "Misc/AssetRegistryInterface.h" #include "Modules/ModuleManager.h" #include "Templates/Casts.h" #include "Templates/UnrealTemplate.h" #include "Trace/Detail/Channel.h" #include "UObject/NameTypes.h" #include "UObject/Object.h" #include "UObject/Package.h" #include "Validation/EditorValidator.h" #include "Validation/EditorValidator_Load.h" #define LOCTEXT_NAMESPACE "EditorValidator" UEditorValidator_Blueprints::UEditorValidator_Blueprints() : Super() { } bool UEditorValidator_Blueprints::CanValidateAsset_Implementation(UObject* InAsset) const { return Super::CanValidateAsset_Implementation(InAsset) && (InAsset ? InAsset->IsA(UBlueprint::StaticClass()) : false); } EDataValidationResult UEditorValidator_Blueprints::ValidateLoadedAsset_Implementation(UObject* InAsset, TArray& ValidationErrors) { UBlueprint* Blueprint = Cast(InAsset); check(Blueprint); if (UEditorValidator::ShouldAllowFullValidation()) { // For non-dataonly blueprints, also load and check all directly referencing non-data-only blueprints, as changes may have caused them to fail to compile if (!FBlueprintEditorUtils::IsDataOnlyBlueprint(Blueprint)) { FAssetRegistryModule& AssetRegistryModule = FModuleManager::LoadModuleChecked(TEXT("AssetRegistry")); IAssetRegistry& AssetRegistry = AssetRegistryModule.Get(); TSet AllHardReferencers; TArray PackagesToProcess; PackagesToProcess.Add(Blueprint->GetOutermost()->GetFName()); do { TArray NextPackagesToProcess; for (FName PackageToProcess : PackagesToProcess) { TArray HardReferencers; AssetRegistry.GetReferencers(PackageToProcess, HardReferencers, UE::AssetRegistry::EDependencyCategory::Package, UE::AssetRegistry::EDependencyQuery::Hard); for (FName HardReferencer : HardReferencers) { if (!AllHardReferencers.Contains(HardReferencer)) { AllHardReferencers.Add(HardReferencer); TArray RefAssets; AssetRegistry.GetAssetsByPackageName(HardReferencer, RefAssets, true); for (const FAssetData& RefData : RefAssets) { if (RefData.IsRedirector()) { NextPackagesToProcess.Add(RefData.PackageName); break; } } } } } PackagesToProcess = MoveTemp(NextPackagesToProcess); } while (PackagesToProcess.Num() > 0); for (FName HardReferencer : AllHardReferencers) { FString HardReferencerStr = HardReferencer.ToString(); if (!IsInUncookedFolder(HardReferencerStr)) { TArray ReferencerAssets; AssetRegistry.GetAssetsByPackageName(HardReferencer, ReferencerAssets, true); for (const FAssetData& ReferencerAssetData : ReferencerAssets) { // Skip levelscript BPs... for now if ((ReferencerAssetData.PackageFlags & PKG_ContainsMap) == 0) { bool bIsDataOnlyBP = false; if (ReferencerAssetData.GetTagValue(FBlueprintTags::IsDataOnly, bIsDataOnlyBP)) { if (!bIsDataOnlyBP) { UE_LOG(LogLyraEditor, Display, TEXT(" Loading referencing non-dataonly blueprint %s"), *HardReferencerStr); TArray WarningsAndErrors; if (UEditorValidator_Load::GetLoadWarningsAndErrorsForPackage(HardReferencerStr, WarningsAndErrors)) { for (const FString& WarningOrError : WarningsAndErrors) { AssetFails(InAsset, FText::FromString(WarningOrError), ValidationErrors); } } break; } } } } } } } } if (GetValidationResult() != EDataValidationResult::Invalid) { AssetPasses(InAsset); } return GetValidationResult(); } #undef LOCTEXT_NAMESPACE