Files
ProjectEleri/Plugins/DirectiveUtilities/Source/DirectiveUtilitiesEditor/Private/Libraries/DirectiveUtilEditorAssetLibrary.cpp

291 lines
8.1 KiB
C++
Raw Normal View History

2026-07-15 19:17:47 +02:00
// Copyright (c) 2026 Unreal Directive. Licensed under the MIT License.
#include "Libraries/DirectiveUtilEditorAssetLibrary.h"
#include "Subsystems/EditorAssetSubsystem.h"
#include "Algo/Transform.h"
#include "AssetRegistry/IAssetRegistry.h"
#include "AssetRegistry/ARFilter.h"
#include "AssetToolsModule.h"
#include "IAssetTools.h"
#include "Misc/AssetRegistryInterface.h"
#include "Modules/ModuleManager.h"
#include "UObject/ObjectRedirector.h"
namespace
{
void WaitForAssetRegistry()
{
if (IAssetRegistry* AssetRegistry = IAssetRegistry::Get())
{
if (AssetRegistry->IsLoadingAssets())
{
AssetRegistry->WaitForCompletion();
}
}
}
}
TArray<FAssetData> UDirectiveUtilEditorAssetLibrary::GetAssetDataListFromDirectory(
const FString& DirectoryPath,
const bool bRecursive)
{
WaitForAssetRegistry();
TArray<FAssetData> AssetDataList;
UEditorAssetSubsystem* EditorAssetSubsystem = GEditor ? GEditor->GetEditorSubsystem<UEditorAssetSubsystem>() : nullptr;
if (!EditorAssetSubsystem)
{
return AssetDataList;
}
const TArray<FString> AssetPaths = EditorAssetSubsystem->ListAssets(DirectoryPath, bRecursive, false);
Algo::Transform(AssetPaths, AssetDataList, [EditorAssetSubsystem](const FString& AssetPath) {
return EditorAssetSubsystem->FindAssetData(AssetPath);
});
AssetDataList.RemoveAll([](const FAssetData& AssetData) {
return !AssetData.IsValid();
});
return AssetDataList;
}
TMap<FDirectiveUtilAssetKey, FDirectiveUtilDuplicateAssetData> UDirectiveUtilEditorAssetLibrary::FindDuplicateAssets(
const TArray<FString>& DirectoryPaths,
const bool bRecursive)
{
TArray<FAssetData> CombinedAssetDataList;
for (const FString& DirectoryPath : DirectoryPaths)
{
const TArray<FAssetData> AssetDataList = GetAssetDataListFromDirectory(DirectoryPath, bRecursive);
CombinedAssetDataList.Append(AssetDataList);
}
TMap<FDirectiveUtilAssetKey, FDirectiveUtilDuplicateAssetData> DuplicateAssetsMap;
for (const FAssetData& AssetData : CombinedAssetDataList)
{
if (!AssetData.IsValid()) { continue; }
const FString AssetName = AssetData.AssetName.ToString();
const FString AssetClass = AssetData.AssetClassPath.ToString();
const FString AssetPath = AssetData.GetSoftObjectPath().ToString();
const FDirectiveUtilAssetKey AssetKey(AssetName, AssetClass);
if (FDirectiveUtilDuplicateAssetData* ExistingData = DuplicateAssetsMap.Find(AssetKey))
{
ExistingData->DuplicateAssetPaths.AddUnique(AssetPath);
}
else
{
FDirectiveUtilDuplicateAssetData DuplicateAssetData;
DuplicateAssetData.AssetName = AssetName;
DuplicateAssetData.AssetClass = AssetClass;
DuplicateAssetData.DuplicateAssetPaths.Add(AssetPath);
DuplicateAssetsMap.Emplace(AssetKey, MoveTemp(DuplicateAssetData));
}
}
TArray<FDirectiveUtilAssetKey> KeysToRemove;
for (const auto& Pair : DuplicateAssetsMap)
{
if (Pair.Value.DuplicateAssetPaths.Num() <= 1)
{
KeysToRemove.Add(Pair.Key);
}
}
for (const FDirectiveUtilAssetKey& Key : KeysToRemove)
{
DuplicateAssetsMap.Remove(Key);
}
return DuplicateAssetsMap;
}
EDirectiveUtilSuccessStatus UDirectiveUtilEditorAssetLibrary::FixUpRedirectorsInPaths(const TArray<FString>& DirectoryPaths, int32& OutRedirectorsProcessed)
{
OutRedirectorsProcessed = 0;
IAssetRegistry* AssetRegistry = IAssetRegistry::Get();
if (!AssetRegistry)
{
return EDirectiveUtilSuccessStatus::Failure;
}
if (AssetRegistry->IsLoadingAssets())
{
AssetRegistry->WaitForCompletion();
}
FAssetToolsModule& AssetToolsModule = FModuleManager::LoadModuleChecked<FAssetToolsModule>("AssetTools");
IAssetTools& AssetTools = AssetToolsModule.Get();
if (AssetTools.IsFixupReferencersInProgress())
{
return EDirectiveUtilSuccessStatus::Failure;
}
FARFilter Filter;
Filter.bRecursiveClasses = false;
Filter.ClassPaths.Add(UObjectRedirector::StaticClass()->GetClassPathName());
if (DirectoryPaths.Num() > 0)
{
Filter.bRecursivePaths = true;
for (const FString& DirectoryPath : DirectoryPaths)
{
Filter.PackagePaths.Add(FName(*DirectoryPath));
}
}
TArray<FAssetData> RedirectorAssets;
if (!AssetRegistry->GetAssets(Filter, RedirectorAssets))
{
return EDirectiveUtilSuccessStatus::Failure;
}
TArray<UObjectRedirector*> Redirectors;
Redirectors.Reserve(RedirectorAssets.Num());
for (const FAssetData& RedirectorData : RedirectorAssets)
{
if (UObjectRedirector* Redirector = Cast<UObjectRedirector>(RedirectorData.GetAsset()))
{
Redirectors.Add(Redirector);
}
}
if (Redirectors.Num() == 0)
{
return EDirectiveUtilSuccessStatus::Success;
}
AssetTools.FixupReferencers(Redirectors, false, ERedirectFixupMode::DeleteFixedUpRedirectors);
OutRedirectorsProcessed = Redirectors.Num();
return EDirectiveUtilSuccessStatus::Success;
}
TArray<FAssetData> UDirectiveUtilEditorAssetLibrary::GetAssetsByClass(
UClass* AssetClass,
const FString& PackagePath,
const bool bRecursiveClasses,
const bool bRecursivePaths,
EDirectiveUtilSuccessStatus& OutStatus)
{
WaitForAssetRegistry();
TArray<FAssetData> Result;
OutStatus = EDirectiveUtilSuccessStatus::Failure;
if (!IsValid(AssetClass))
{
return Result;
}
IAssetRegistry* AssetRegistry = IAssetRegistry::Get();
if (!AssetRegistry)
{
return Result;
}
FARFilter Filter;
Filter.ClassPaths.Add(AssetClass->GetClassPathName());
Filter.bRecursiveClasses = bRecursiveClasses;
if (!PackagePath.IsEmpty())
{
Filter.PackagePaths.Add(FName(*PackagePath));
Filter.bRecursivePaths = bRecursivePaths;
}
if (AssetRegistry->GetAssets(Filter, Result))
{
OutStatus = EDirectiveUtilSuccessStatus::Success;
}
return Result;
}
TArray<FString> UDirectiveUtilEditorAssetLibrary::GetAssetDependencies(const FAssetData& Asset, const bool bHardDependenciesOnly, EDirectiveUtilSuccessStatus& OutStatus)
{
using namespace UE::AssetRegistry;
WaitForAssetRegistry();
TArray<FString> Result;
OutStatus = EDirectiveUtilSuccessStatus::Failure;
IAssetRegistry* AssetRegistry = IAssetRegistry::Get();
if (!AssetRegistry || !Asset.IsValid())
{
return Result;
}
TArray<FName> Dependencies;
const FDependencyQuery Query = bHardDependenciesOnly ? FDependencyQuery(EDependencyQuery::Hard) : FDependencyQuery();
if (AssetRegistry->GetDependencies(Asset.PackageName, Dependencies, EDependencyCategory::Package, Query))
{
Result.Reserve(Dependencies.Num());
for (const FName& Dependency : Dependencies)
{
Result.Add(Dependency.ToString());
}
OutStatus = EDirectiveUtilSuccessStatus::Success;
}
return Result;
}
TArray<FString> UDirectiveUtilEditorAssetLibrary::GetAssetReferencers(const FAssetData& Asset, const bool bHardReferencesOnly, EDirectiveUtilSuccessStatus& OutStatus)
{
using namespace UE::AssetRegistry;
WaitForAssetRegistry();
TArray<FString> Result;
OutStatus = EDirectiveUtilSuccessStatus::Failure;
IAssetRegistry* AssetRegistry = IAssetRegistry::Get();
if (!AssetRegistry || !Asset.IsValid())
{
return Result;
}
TArray<FName> Referencers;
const FDependencyQuery Query = bHardReferencesOnly ? FDependencyQuery(EDependencyQuery::Hard) : FDependencyQuery();
if (AssetRegistry->GetReferencers(Asset.PackageName, Referencers, EDependencyCategory::Package, Query))
{
Result.Reserve(Referencers.Num());
for (const FName& Referencer : Referencers)
{
Result.Add(Referencer.ToString());
}
OutStatus = EDirectiveUtilSuccessStatus::Success;
}
return Result;
}
FString UDirectiveUtilEditorAssetLibrary::GetDefaultAssetNameForClass(UClass* AssetClass, EDirectiveUtilSuccessStatus& OutStatus)
{
OutStatus = EDirectiveUtilSuccessStatus::Failure;
if (!IsValid(AssetClass))
{
return FString();
}
FAssetToolsModule& AssetToolsModule = FModuleManager::LoadModuleChecked<FAssetToolsModule>("AssetTools");
IAssetTools& AssetTools = AssetToolsModule.Get();
#if ENGINE_MAJOR_VERSION == 5 && ENGINE_MINOR_VERSION >= 8
const TOptional<FString> ResolvedName = AssetTools.GetDefaultAssetNameForClass(AssetClass, nullptr, nullptr);
#else
const TOptional<FString> ResolvedName = AssetTools.GetDefaultAssetNameForClass(AssetClass);
#endif
if (ResolvedName.IsSet() && !ResolvedName.GetValue().IsEmpty())
{
OutStatus = EDirectiveUtilSuccessStatus::Success;
return ResolvedName.GetValue();
}
return FString();
}