做个小工具按规则筛选当前Object并输出基础信息

128 篇文章 146 订阅

无用的前言

Object的观察工具之前已经有两篇了。但是第一篇的代码有些冗杂,很多方面都可以简化。最近的一篇的代码比较简洁优雅,但它是直接输出了所有Object的信息,而Object数目非常多,在两万多个Object中找到想要观察的目标是较为困难的。这让我想要做一个工具(或者说建立一个机制)能按照自定义的“规则”筛选出想要观察的Object,并且最好是能用蓝图表示出这个“规则”。

目标

上一篇输出Object基础信息的逻辑封装为一个Object(为了借用它的Detail面板界面)。并且包含“过滤函数”,而这个函数要暴露给蓝图实现。最后使用UMG界面用于显示这个Object的细节面板,以方便操控。

(1)编写基类UObject的Cpp代码

之所以要创建一个UObject类原因是:

  1. 借用它的细节面板作为界面,这样可以更方便操控。
  2. 想要创建蓝图啊子类,来实现自定义的过滤函数。

最终的代码如下:

ObjectPrinter.h:

#pragma once

#include "UObject/Object.h"

#include "ObjectPrinter.generated.h"

UCLASS(Blueprintable)
class UObjectPrinter : public UObject
{
	GENERATED_UCLASS_BODY()
public:
	//将符合条件的Object打印到输出窗口中!(会呈现在细节面板中成为一个按钮)
	UFUNCTION(CallInEditor)
	void PrintObjects();

	//判断这个对象是否应该被打印(此函数期望被子类蓝图重载而实现自定义的逻辑)
	UFUNCTION(BlueprintImplementableEvent)
	bool Filter(UObject* Obj);

	//强制执行一次GC(会呈现在细节面板中成为一个按钮。可以手动触发,来排除临时物体干扰观察)
	UFUNCTION(CallInEditor)
	void ForceGC();
};

ObjectPrinter.cpp:

#include"ObjectPrinter.h"

DEFINE_LOG_CATEGORY_STATIC(LogYKS, Log, All);

FString RecursiveGetOuterText(UObject* Object, FString Result)
{
	if (!Object->GetOuter())
		return Result;
	else
	{
		Result += "->(" + Object->GetOuter()->GetFName().ToString() + ")";
		return RecursiveGetOuterText(Object->GetOuter(), Result);
	}
}

FString GetFlagText(EObjectFlags Flag)
{
	FString Result;

	if (Flag & RF_NoFlags)
		Result += "+RF_NoFlags";

	if (Flag & RF_Public)
		Result += "+RF_Public";

	if (Flag & RF_Standalone)
		Result += "+RF_Standalone";

	if (Flag & RF_MarkAsNative)
		Result += "+RF_MarkAsNative";

	if (Flag & RF_Transactional)
		Result += "+RF_Transactional";

	if (Flag & RF_ClassDefaultObject)
		Result += "+RF_ClassDefaultObject";

	if (Flag & RF_ArchetypeObject)
		Result += "+RF_ArchetypeObject";

	if (Flag & RF_Transient)
		Result += "+RF_Transient";

	if (Flag & RF_MarkAsRootSet)
		Result += "+RF_MarkAsRootSet";

	if (Flag & RF_TagGarbageTemp)
		Result += "+RF_TagGarbageTemp";

	if (Flag & RF_NeedInitialization)
		Result += "+RF_NeedInitialization";

	if (Flag & RF_NeedLoad)
		Result += "+RF_NeedLoad";

	if (Flag & RF_KeepForCooker)
		Result += "+RF_KeepForCooker";

	if (Flag & RF_NeedPostLoad)
		Result += "+RF_NeedPostLoad";

	if (Flag & RF_NeedPostLoadSubobjects)
		Result += "+RF_NeedPostLoadSubobjects";

	if (Flag & RF_NewerVersionExists)
		Result += "+RF_NewerVersionExists";

	if (Flag & RF_BeginDestroyed)
		Result += "+RF_BeginDestroyed";

	if (Flag & RF_FinishDestroyed)
		Result += "+RF_FinishDestroyed";

	if (Flag & RF_BeingRegenerated)
		Result += "+RF_BeingRegenerated";

	if (Flag & RF_DefaultSubObject)
		Result += "+RF_DefaultSubObject";

	if (Flag & RF_WasLoaded)
		Result += "+RF_WasLoaded";

	if (Flag & RF_TextExportTransient)
		Result += "+RF_TextExportTransient";

	if (Flag & RF_LoadCompleted)
		Result += "+RF_LoadCompleted";

	if (Flag & RF_InheritableComponentTemplate)
		Result += "+RF_InheritableComponentTemplate";

	if (Flag & RF_DuplicateTransient)
		Result += "+RF_DuplicateTransient";

	if (Flag & RF_StrongRefOnFrame)
		Result += "+RF_StrongRefOnFrame";

	if (Flag & RF_NonPIEDuplicateTransient)
		Result += "+RF_NonPIEDuplicateTransient";

	if (Flag & RF_Dynamic)
		Result += "+RF_Dynamic";

	if (Flag & RF_WillBeLoaded)
		Result += "+RF_WillBeLoaded";

	if (Flag & RF_HasExternalPackage)
		Result += "+RF_HasExternalPackage";

	return Result;
}

UObjectPrinter::UObjectPrinter(const FObjectInitializer& ObjectInitializer)
	: Super(ObjectInitializer)
{}

void UObjectPrinter::PrintObjects()
{
	for (int i = 0; i < GUObjectArray.GetObjectArrayNum(); i++)
	{
		FUObjectItem* ObjectElement = GUObjectArray.IndexToObject(i);
		if (ObjectElement->Object)
		{
			UObject* Object = (UObject*)ObjectElement->Object;

			if (!Filter(Object))//过滤
				continue;

			UE_LOG(LogYKS, Warning, TEXT("[%d], <%s>, %s, %s, %s")
				, Object->GetUniqueID()							//InternalIndex
				, *(Object->GetClass()->GetFName().ToString())	//类
				, *(Object->GetFName().ToString())				//名字
				, *RecursiveGetOuterText(Object, "")			//Outer链
				, *GetFlagText(Object->GetFlags())				//具有的Flag
			);
		}
	}
}

void UObjectPrinter::ForceGC()
{
	CollectGarbage(EObjectFlags::RF_NoFlags);
}

基本上就是对上一篇代码的封装。只是在打印的时候还会通过Filter函数过滤一下。(另外还加了一个强制GC的函数,可以随时调用,用于排除一些临时的Object干扰观察)

(2)继承蓝图并自定义筛选逻辑

进入编辑器,以刚才在Cpp中定义的ObjectPrinter为基类创建蓝图:
在这里插入图片描述
作为测试,我将以 “Object类型” 作为过滤条件,因此我将蓝图命名为ObjectPrinter_ClassType

打开这个蓝图,创建一个变量名为ClassType。将它类型设置为 Soft Class Path用于表示用哪个类型过滤:
在这里插入图片描述
然后,就可以重载Filter函数了:
在这里插入图片描述
Filter函数连接如下:
在这里插入图片描述

连接节点需要注意的是,Soft Class Path 并不能直接转换为Class,需要两次装换:
在这里插入图片描述

(3)显示detail界面

为了能显示细节面板,我选择创建一个 Editor Utility Widget:
在这里插入图片描述
打开这个蓝图,创建一个细节面板(DetailsView)控件:(勾选 “Size To Content” 以便界面可以显示完全)
在这里插入图片描述
然后,在构造函数中,以自己为Outer创建一个ObjectPrinter_ClassType(上一步用蓝图定义的对象),并将细节面板显示的对象设置为它:
在这里插入图片描述
编译保存后,就可以右键它来显示界面了:
在这里插入图片描述

使用

测试使用:
在这里插入图片描述


后续如果想要用其他自定义的逻辑来筛选Object,就可以创建新的蓝图并重载过滤函数,然后将窗口中细节面板的对象设置为新蓝图。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值