Unlua源码解析(一) 通过 UE 命名空间访问C++类型

Unlua源码解析(一) 通过 UE 命名空间访问C++类型
最新回答
诸多诱惑

2021-09-13 12:24:47

Unlua源码解析(一):通过 UE 命名空间访问C++类型

在Unlua框架中,通过UE命名空间访问C++类型是一个核心功能。这一功能允许Lua脚本直接调用UE4(Unreal Engine 4)中的C++方法和属性。下面,我们将详细解析这一过程是如何实现的。

1. UE 命名空间的初始化

在Unlua中,UE实际上是一个全局表_G的别名,并且它的元表是global_mt,其中Index元方法被设置为global_index。这意味着当Lua尝试访问UE命名空间下的某个属性或方法时,会触发global_index元方法。

  • global_index 方法解析

    当Lua访问UE下的某个索引k时,global_index方法会首先检查k的首字母是否是U或E。

    如果是U,则调用RegisterClass方法注册类;如果是E,则调用RegisterEnum方法注册枚举。

    接着,使用rawget方法尝试从UE表中直接获取索引k的值(不使用Index元方法)。

    如果rawget失败,说明UE表中还没有该索引的值,此时会进一步处理,如调用RegisterClass或RegisterEnum来注册相应的C++类型或枚举。

2. UE4.UKismetSystemLibrary 的注册过程

当Lua脚本尝试访问UE4.UKismetSystemLibrary时,由于UE4是全局表,Lua会尝试在UE4表中查找UKismetSystemLibrary。由于这是第一次访问,UE4表中还没有UKismetSystemLibrary的值,因此会触发UE4表的Index元方法,即global_index。

  • RegisterClass 方法

    RegisterClass方法会根据传入的类名(如UKismetSystemLibrary),使用UE4的反射系统生成该类的描述信息FClassDesc。

    然后,将FClassDesc存储到UnLua的全局反射数据对象GReflectionRegistry中。

    接着,在Lua中为该类注册一个表,并设置该表的元表为自己,同时往表中添加一些元方法。

3. UE4.UKismetSystemLibrary.PrintString 的访问过程

在UE4.UKismetSystemLibrary表注册完成后,Lua脚本可以访问该表下的方法和属性。当访问PrintString方法时,由于UE4.UKismetSystemLibrary表中还没有PrintString的值,会触发该表的Index元方法(在注册类时设置)。

  • Class_Index 方法

    Class_Index方法会尝试从类的描述信息FClassDesc中获取PrintString方法或属性的描述信息(如FFunctionDesc或FPropertyDesc)。

    如果找到的是方法描述信息FFunctionDesc,则会在Lua表中注册一个闭包,该闭包包含调用C++方法的逻辑(通过Class_CallUFunction)。

    注册的闭包会将FFunctionDesc作为upvalue,以便在调用时能够找到正确的C++方法。

4. UE4.UKismetSystemLibrary.PrintString("Hello") 的调用过程

当Lua脚本调用UE4.UKismetSystemLibrary.PrintString("Hello")时,实际上是在调用之前注册的闭包。

  • Class_CallUFunction 方法

    Class_CallUFunction方法会根据传入的参数(如Lua字符串"Hello")和FFunctionDesc,将Lua参数转换成C++参数。

    然后,使用UE4的反射系统调用真正的C++方法(如UKismetSystemLibrary::PrintString)。

    调用完成后,将C++方法的返回值转换成Lua返回值,并推入Lua栈中返回给Lua脚本。

总结

通过上述过程,Unlua实现了通过UE命名空间访问C++类型的功能。这一功能的核心在于利用Lua的元表机制、UE4的反射系统以及C++与Lua之间的参数转换逻辑。通过这些机制,Lua脚本能够方便地调用UE4中的C++方法和属性,从而实现更加灵活和强大的游戏逻辑和脚本功能。

以下是相关代码和类图的展示:

这些图片展示了Unlua框架中相关类和方法的注册、调用过程,以及它们之间的关系。通过这些图片和上述解析,我们可以更加深入地理解Unlua如何通过UE命名空间访问C++类型的实现机制。