获取关卡中一个 Actor 的被引用情况
背景:做合批的时候剔除被引用的 Actor
例如:

这里的蓝图类就有一个Level中某Actor的硬引用和一个软引用,对于这两个被引用的Actor我们不应该让他被合批。
最开始使用的是 IsReferenced 这个接口,
但是发现对于软引用无法获取到。
但是注意到,对于这种情况,我们直接在 Outliner 面板里删除物体,也会弹出被引用的提示警告。
这个功能位于 UUnrealEdEngine::DeleteActors (Engine\Source\Editor\UnrealEd\Private\EditorActor.cpp)
分别是两个接口:
FBlueprintEditorUtils::GetActorReferenceMap
AssetToolsModule.Get().FindSoftReferencesToObjects
这里特别留意到 ALODActor,之前使用 IsReferenced 接口的时候也发现了被其引用的情况:

具体是为什么会被 ALODActor 引用还不清楚。
资产
获取特定类型的所有资产
在 Content/Arts 目录中获取所有 Texture:
1
2
3
4
5
6
7
| FARFilter Filter;
Filter.PackagePaths.Add("/Game/Arts");
Filter.ClassPaths.Add(UTexture::StaticClass()->GetClassPathName());
Filter.bRecursivePaths = true;
Filter.bRecursiveClasses = true;
TArray<FAssetData> TextureAssets;
AssetRegistry.GetAssets(Filter, TextureAssets);
|
这里注意,我们在 5.1 之后使用的是 ClassPaths 而不是 ClassNames:

获取资产的引用关系
例如获取当前关卡的引用关系:
获取是谁引用了当前关卡:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
| auto World = GEditor->GetEditorWorldContext().World();
FName Name = World->GetPackage()->GetFName();
FAssetRegistryModule& AssetRegistryModule = FModuleManager::GetModuleChecked<FAssetRegistryModule>("AssetRegistry");
TArray<FName> AssetReferencers;
AssetRegistryModule.Get().GetReferencers(Name, AssetReferencers, UE::AssetRegistry::EDependencyCategory::All);
for (int32 i = 0; i < AssetReferencers.Num(); ++i)
{
TArray<FAssetData> OutAssetData;
AssetRegistryModule.Get().GetAssetsByPackageName(AssetReferencers[i], OutAssetData);
if (!OutAssetData.IsEmpty())
{
UObject* AssetInPackage = OutAssetData[0].GetAsset();
}
}
|
获取当前关卡引用了谁:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
| auto World = GEditor->GetEditorWorldContext().World();
FName Name = World->GetPackage()->GetFName();
FAssetRegistryModule& AssetRegistryModule = FModuleManager::GetModuleChecked<FAssetRegistryModule>("AssetRegistry");
TArray<FName> DependentAssets;
AssetRegistryModule.Get().GetDependencies(Name, DependentAssets, UE::AssetRegistry::EDependencyCategory::All);
for (int32 i = 0; i < DependentAssets.Num(); ++i)
{
TArray<FAssetData> OutAssetData;
AssetRegistryModule.Get().GetAssetsByPackageName(DependentAssets[i], OutAssetData);
if (!OutAssetData.IsEmpty())
{
UObject* AssetInPackage = OutAssetData[0].GetAsset();
}
}
|
这里特别要注意,commandlet 下获取引用关系可能会有问题,需要手动全部加载一次:
1
2
3
4
| UE_LOG(LogTemp, Display, TEXT("Start Load All Assets!"))
FAssetRegistryModule& AssetRegistryModule = FModuleManager::GetModuleChecked<FAssetRegistryModule>("AssetRegistry");
AssetRegistryModule.Get().SearchAllAssets(/*bSynchronousSearch =*/true);
UE_LOG(LogTemp, Display, TEXT("Finish Load All Assets!"))
|
关于 AssetRegistry,可以参考:
https://zhuanlan.zhihu.com/p/76964514
保存资产
https://zhuanlan.zhihu.com/p/427163748
http://www.bimant.com/blog/ue5-save-upackage/
xml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
| FString OutputFilePath = FPaths::ProjectIntermediateDir() + "xxx/" + "xxx.xml";
const FString XmlTemplate = "<?xml version=\"1.0\" encoding=\"UTF - 8\"?>\n<root>\n</root>";
FXmlFile* XmlFile = new FXmlFile(XmlTemplate, EConstructMethod::ConstructFromBuffer);
if (!XmlFile->IsValid())
return 0;
FXmlNode* XmlRoot = XmlFile->GetRootNode();
if (XmlRoot == nullptr)
return 0;
XmlRoot->AppendChildNode("Test1", "test2", {{"test3", "test4"}});
XmlFile->Save(OutputFilePath);
delete XmlFile;
|
结果:

统计
统计代码耗时
函数每帧监控
在一些函数是每帧都要执行的时候,那就可以用UE的统计系统来显示,这样更方便。
先在CPP定义一个自定义监听组
1
| DECLARE_STATS_GROUP(TEXT("DTActor"), STATGROUP_DTActor, STATCAT_Test);
|
这样启动程序的时候, 就可以看到自己定义的组

然后需要定义函数监听模块
1
2
| DECLARE_CYCLE_STAT(TEXT("DTActor Tick"), STAT_Tick, STATGROUP_DTActor);
DECLARE_CYCLE_STAT(TEXT("DTActor Call"), STAT_Call, STATGROUP_DTActor);
|
并在相应的函数中启动相应模块
1
2
3
4
5
6
7
8
9
| void ADTActor::Tick(float DeltaTime)
{
SCOPE_CYCLE_COUNTER(STAT_Tick);
Super::Tick(DeltaTime);
}
void ADTActor::Call()
{
SCOPE_CYCLE_COUNTER(STAT_Call);
}
|
这样在运行关卡的时候就会显示函数的具体执行时间

参考:
https://blog.csdn.net/wmy19890322/article/details/131944569
编辑器
启用 Log 时间
在 Editor Preferences > General > Apppearance > Log Timestamp 打开。

保证纹理流送完成
1
2
3
| #if WITH_EDITOR
FTextureCompilingManager::Get().FinishCompilation({NewTexture});
#endif
|
参考:
https://forums.unrealengine.com/t/tsoftobjectptr-texture2d-loads-wrong-size-values/734522/5
Tricks
ON_SCOPE_EXIT
https://ue5wiki.com/wiki/38318/