欢迎光临散文网 会员登陆 & 注册

UE4 反射机制使用(进阶文章)

2018-11-25 13:54 作者:AICDG  | 我要投稿

反射机制

       反射(Reflection)是一种编程语言的能力,可以在运行时识别对象和类的信息(属性,方法,继承关系等)。如果使用过一些ORM库的同学应该也比较了解这个机制。UE4中大量使用了反射,比如序列化,垃圾回收,蓝图/C++通信。UE4 的反射系统名为 Unreal Property System,实质上还是一个MetaData System。最近有个哥们想要使用 UE 4.20 版本开始提供了python插件做一些事,但是对于如何在python中调用C++代码还有疑惑,所以我稍微研究了一下UE4 PythonScriptPlugin。本文的主要内容就是PythonScriptPlugin中python调用C++代码的分析。

python调用C++代码

       正常将C++代码导出到python,就是编写wrapper。比如我们要导出函数char * hello(char * what)

然后把wrapper添加到module中

再编写一个setup.py在python中声明此module

当然也有一些库,比如SWIG,pybind11,Boost.Python可以简化上面的过程

       对于UE4的PythonScriptPlugin,封装了 PyCFunctionCast 和 PyCStrCast 宏,用来向python导出方法和属性。实际上确实有一些模块,比如数学库,是通过该方法导出的。但是我在PythonScriptPlugin并没有发现导出StaticMesh之类UObject的方法,但是在C++中确实可以调用。说明这些和Gameplay相关的代码导出,必定另有玄妙。

Unreal Property System

       也不卖关子,导出到python的玄妙,就是这个Unreal Property System。这个东西大家应该是非常熟悉的,UENUM()UCLASS()USTRUCT()UFUNCTION(), UPROPERTY() 宏可以将C++代码导出给蓝图使用,而PythonScriptPlugin文档中有这样的话

The unreal module exposes nearly everything that is exposed from C++ to Blueprints in your Editor environment. It's not pre-generated; it automatically reflects whatever is available in Blueprints in your Editor. As you enable new plugins in the Unreal Editor, anything those plugins expose to Blueprints also becomes available in Python as well. The same goes for any C++ code that you write in your Project and expose to Blueprints.

       也就是说,PythonScriptPlugin使用了蓝图相同的代码导出方法,两者都是基于反射实现。对于任何一个UClassUScriptStruct,都可以使用UTypeName::StaticClass()FTypeName::StaticStruct()来查询其类型。而对一个UClassUScriptStruct,可以使用TFieldIterator来查询其方法和属性。

TFieldIterator中的模板参数是一个UField,其树形派生关系如下


       到此为止思路就很清晰了,封装一个binding函数。然后收集所有需要导出的UObject的信息,之后遍历其UFunctionUProperty,调用binding函数完成导出。

PythonScriptPlugin中C++ reflect导出过程分析 

       在PythonScriptPlugin module初始化的部分,可以发现如下代码。

感觉很可疑,所以调试一下,会发现很有意思的东西

ObjectsToProcess应该就是要找的东西了,不过为了确认还是仔细查看一下

       可以看到,ObjectsToProcess就是所有需要导出的UField信息了,之后就是调用函数GenerateWrappedTypeForObject 和 GenerateWrappedTypesForReferences 来完成变量的 wrap 并导入到 python module 中。GenerateWrappedTypeForObject 里也可以看到变量 UClass/UStruct 的属性和方法完成binding的代码,这个过程还是挺复杂的,有兴趣的可以自己看一下。

   从上面查看变量可以发现,就连插件中的代码也完成了导出(3765开始的UClass就是PythonScriptPlugin自己的类)。这可以说是一个相当理想的情况。对于开头提到的那个哥们来说,只要正常开发插件的方式,python就可以调用,并不需要额外手写binding代码。

结语

   通过对PythonScriptPlugin中,c++将UObject导出给python使用的过程分析,相信大家对于蓝图如何调用C++应该有了新的认识。对于网络通信使用xml/json信息spwan actor这种需求有了新的想法。甚至有了自己编写UE4到lua/ruby/js etc. binding的打算。希望本文对大家有所帮助。这篇文章我忽略了一些细节,如果你感觉到有什么模糊或者错误的地方请一定提出来,我尽快改正

UE4 反射机制使用(进阶文章)的评论 (共 条)

分享到微博请遵守国家法律