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


    无用的前言

    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();
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    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);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143

    基本上就是对上一篇代码的封装。只是在打印的时候还会通过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,就可以创建新的蓝图并重载过滤函数,然后将窗口中细节面板的对象设置为新蓝图。

  • 相关阅读:
    【学习总结】辐射、辐照等常见光学物理量的定义与关系
    ssm特殊病例查询系统的设计与实现毕业设计-附源码231832
    docker 部署prometheus+grafana
    CentOS6.6下安装git 2.6.2
    【Linux系统】第一篇:基础指令篇
    hadoop集群搭建
    【目标检测】one-stage------YOLO v2浅析-2016
    驱动开发代码研读
    failed to parse field [name] of type [text] in document with id ‘1‘
    【毕业季】角色转换
  • 原文地址:https://blog.csdn.net/u013412391/article/details/126896787