【UE4源代码观察】观察GUID

疑问

GUID (全局唯一标识符) 这个概念,直接使用UE4编辑器的话应该是接触不到的,甚至说只写游戏逻辑代码的话大概也是不需要接触的。但如果需要的一些代码是对UE4原有的设计有冲击的话,可能会碰到需要处理GUID的情况。之前在项目中有遇到过需要处理的情况,当时并不理解GUID,而现在我想给予它更多的关注,并尝试解答下之前的疑问:

  1. 它是怎么生成的?这样生成真的能保证“全局唯一”吗?而这里的“全局”又指什么?一个项目?一台机器?
  2. 谁存了GUID?他们为何要存?
  3. 何时,又被谁触发生成新的GUID?
  4. 那么,GUID在UE4究竟有什么用?

1.生成

首先看下GUID的定义:

/**
 * Implements a globally unique identifier.
 */
struct FGuid
{
public:
	/** Holds the first component. */
	uint32 A;
	/** Holds the second component. */
	uint32 B;
	/** Holds the third component. */
	uint32 C;
	/** Holds the fourth component. */
	uint32 D;

它由4个uint32组成,这样算来一共有2^128个值,这是个很大的值了。(IPv6也是这么多的数目,其数量号称可以为全世界的每一粒沙子编上一个地址)。

观察GUID生成函数:

/**Returns a new GUID.
 * @return A new GUID.
 */
FGuid FGuid::NewGuid()
{
	FGuid Result(0, 0, 0, 0);
	FPlatformMisc::CreateGuid(Result);
	return Result;
}

其中调用了FPlatformMisc::CreateGuidFPlatformMisc是平台抽象层,在Windows上这个函数的实现是:

void FWindowsPlatformMisc::CreateGuid(FGuid& Result)
{
	verify( CoCreateGuid( (GUID*)&Result )==S_OK );
}

它最终调用了CoCreateGuid函数,而这个函数并不是UE4的函数,是微软的函数。这么看来,UE4中的GUID的概念和一般GUID的概念是一致的,而网上大多数关于GUID的讨论也都适用于UE4中的GUID。

这样,我的第一个问题有了答案:
GUID是全局唯一的,它有CoCreateGuid函数保证。而这里的“全局”,不单单指一个项目,一台机器这样小的范围,我想在我有生之年,任何机器上,任何项目上都不可能创造出两个完全一样的GUID。

2.谁存了GUID变量

"UPROPERTY()\n FGuid"为关键字,在\Engine\Source\Runtime范围内进行搜索,可以得到大量的结果:
在这里插入图片描述
图中显示搜索到104个,实际上应该会更多(出于格式原因或者没有UPROPERTY宏的原因)。
也就是说,它的使用是非常的通用的,而且在各个方面都有出现。

例如:ULevel中的:

/** Identifies map build data specific to this level, eg lighting volume samples. */
UPROPERTY()
FGuid LevelBuildDataId;

UMaterialInterface中的:

/** Unique ID for this material, used for caching during distributed lighting */
UPROPERTY()
FGuid LightingGuid;

从他们两个的注释看起来和Build关照有关。

而例如FGraphReference中的:

// The graph GUID so we can refind it if it has been renamed
UPROPERTY()
FGuid GraphGuid;

显然和Build光照没关系,看注释是说想要在重命名后能再次找到。

目前我对代码的研究还比较少,上面GUID的意义我还并不能有更深入的分析或实践。
不过,有一处GUID的使用我有过实践,是ALandscapeProxy的:

/** Guid for LandscapeEditorInfo **/
UPROPERTY()
FGuid LandscapeGuid;

ALandscapeStreamingProxy(继承自ALandscapeProxy)代表了一个完整的大地形被分割成的易于被单个Level动态加载的“小地形”。一个“小地形”可以被单独加载出来,但是当他和它相邻的被分割的“小地形”一起被编辑器加载出来时,笔刷期望对他们一起编辑(即笔触应该能从一个小地形划过到另一个小地形中)。这时,LandscapeGuid就用上了:被同一个大地形分割出来的“小地形”,都拥有和大地形相同的GUID,这样编辑器通过看LandscapeGuid就可以知道要把哪几个“小地形”放在一起编辑了。(详情见LandscapeEditor模块)

3.生成新的GUID的时机

我加了一个断点在FGuid::NewGuid()中:
在这里插入图片描述
期待能明白我做哪些操作能生成新GUID。可结果是——生成得太频繁了,一个操作甚至会导致数个GUID的生成。于是,我将断点设置成输出调用者的名字,期待观察一个操作后都会导致多少个GUID生成:
在这里插入图片描述

之后,我得到了如下的结果:
光是启动编辑器,这个断点就触发了2000+次

创建新材质时,触发了1次:

GUID生成了,调用者是[内联框架] UMaterialInterface::SetLightingGuid

然后保存它时,触发了两次:

GUID生成了,调用者是TextNamespaceUtilImpl::FindOrAddPackageNamespace
GUID生成了,调用者是UPackage::Save

创建新的关卡时,触发了6次

GUID生成了,调用者是UModel::Modify
GUID生成了,调用者是ULevel::PostInitProperties
GUID生成了,调用者是[内联框架] UMaterialInterface::SetLightingGuid
GUID生成了,调用者是UModel::Modify
GUID生成了,调用者是UBodySetup::PostInitProperties
GUID生成了,调用者是[内联框架] UMaterialInterface::SetLightingGuid

创建地形时,更是触发了600次左右,前几个大概是:

GUID生成了,调用者是FTransaction::FTransaction
GUID生成了,调用者是FTransaction::BeginOperation
GUID生成了,调用者是UModel::Modify
GUID生成了,调用者是FLandscapeEditorDetailCustomization_NewLandscape::OnCreateButtonClicked
GUID生成了,调用者是ULandscapeComponent::PostInitProperties
GUID生成了,调用者是ULandscapeComponent::PostInitProperties
。。。

而且首次执行这些操作时,也触发了很多次。
我想,面对如此多的数目,试图做出“在XXX情况下生成GUID”的结论是很困难的。

4.暂时的结论

通过对UE4的GUID的生成函数的观察让我明白,UE4的GUID其实和普通的网上讨论的GUID并无本质区别,因此关于他们的生成的具体算法,还有“何时会重复”这种问题,网上都有很多讨论可以参阅。

而对UE4中GUID的使用情况的观察,让我明白,GUID在UE4中并不是专门服务于“某个问题”,而是服务于“多个问题,而且他们各自并没关联”。因此与其从GUID出发去问“GUID在UE4有什么用?”不如从UE4中具体的问题出发去问 “UE4中的某个问题中GUID发挥了怎样的作用” 更有意义

  • 10
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值