一些小方法

获取关卡中一个 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/

Licensed under CC BY-NC-SA 4.0