zoukankan      html  css  js  c++  java
  • [译]Godot 引擎 GDNative 架构初探

    GDNative的架构从最早叫“DLScript”的时候到目前为止已经发生了很大的变化。随着Godot 3.0版本接近最终发布以及API越来越稳定,是时候对GDNative目前的形态作一个概述了。

    GDNATIVELIBRARY

    GDNativeLibrary是一种资源类型。它是对每种平台所需的实际二进制文件的一种抽象:包含一些属性、“入口”库加载路径清单及“入口”库所依赖库的清单。

    这些清单是一套功能特性标记的简单映射形式 - 一般是一个文件路径;如果有依赖关系的话,就是一组路径。

    特性标记

    Godot有一套特性标记系统。特性标记表示拥有对应的特定的属性或功能,例如Windows, X11, 32, 64, mobile等等。在导出游戏时,你也可以自行定义标记,从而可能改变游戏的运行方式。

    更多关于特性标记的信息,可以去http://docs.godotengine.org/en/latest/learning/workflow/export/feature_tags.html查看。

    GDNativeLibrary资源中的列表由键值对形式组成,键中根据需要可以包含多个特性标记,以英文句点“.”分隔。

    例如一个支持64位Linux机器的库,它的键名即“X11.64”,如果对应的是Windows的机器,则键名为“Windows.64”。

    Godot编辑器提供了GUI来更人性化的进行这种资源的定义和编辑。

    它会从上而下的对所有入口进行检测,并跳过那些不存在的特性标记。在所有可用的标记中,第一个会被用作入口,所以排序很重要。

    SINGLETON 库

    GDNativeLibrary中有一个属性是用于定义其是否支持单例形式使用的。单例库会在Godot启动期间尽可能早地载入,且会调用库中的gdnative_singleton函数。这种库常用于需要提供与Godot紧密结合的功能。

    GDNATIVE

    GDNative对象代表所载入的库,至于具体要加载哪个库就要从GDNativeLibrary资源文件中匹配了,Godot环境下的C++代码可以去调用该库中的函数。由于这种方式去调用函数太过灵活、底层且不安全,所以是不建议从GDScript这些脚本语言中去调的。

    如果真想从脚本语言环境直接调用相应功能,可以用GDNative.call_native方法来满足需求。对于这种函数指针调用的底层细节,抽象出了一种所谓的“调用类型”来进行描述。目前仅有一种预定义调用类型:standard_varcall - 要求被调用的函数签名为 godot_variant function_name(godot_array *) 。单例库可以按需注册新的调用类型。

    GDNATIVE/GODOT API

    如果某个库想调用Godot的一些功能,它就需要去调用Godot的代码。而各种C++编译器之间的移植性非常有问题,所以我们选择用C语言API的形式来封装对C++的调用。这开启了多种语言访问API的可能性,但也带来了一些冗余性。

    API 结构

    一个库为了访问那些用C封装的函数,它首先要知道那些函数的位置。最直接的想法是留空,然后让操作系统的库加载机制来处理。

    不幸的是,这种方式不能在所有平台正常运作(此处Windows可能要尴尬的咳两声),所以为了保证在所有平台设置GDNative库用同样的代码和步骤,我们决定采取另一种途径:在加载函数时,以函数指针结构(struct)的形式传递。

    该结构存在于Godot中,并包含版本信息、将来的API改动字段及扩展API列表。

    struct godot_gdnative_api_struct {
        unsigned int type;
        godot_gdnative_api_version version;
        const godot_gdnative_api_struct *next;
    };
    
    struct godot_gdnative_core_api_struct {
        unsigned int type;
        godot_gdnative_api_version version;
        const godot_gdnative_api_struct *next;
        unsigned int num_extensions;
    const godot_gdnative_api_struct **extensions;
        // ...
    };
    

    库可以从这种struct中访问所需的函数,也就意味着不再是编写 godot_some_function();这种形式了,而是api->godot_some_function();

    有些人喜欢简单的通过函数名而不是struct来访问函数,所以在有需要时,Godot的构建系统会生成一个静态库,来包裹所有的同名函数指针为静态函数。

    扩展

    GDNative 扩展是一种给库提供GDNative/Godot API 之外功能的方式。它们可以不同方式应用,下面会列出几种当前支持的形式的扩展。

    扩展通常带有C语言API,可能还伴随着有自定义数据类型。Godot里通常有用于包裹那些和其它功能密切结合的C函数的C++类/方法。

    每个扩展都有它自己的子API结构,其中包含了版本信息及未来API修改信息的字段。

    ARVR

    采用GDNative来实现一种VR驱动的所有API可以参考文档: file。

    这套API的起点是 godot_arvr_register_interface 函数,它需要从一个单例库进行调用。那些要被Godot调用的函数则组织成一个结构以参数的形式传递过去。

    目前有 null-driver 的实现、 OpenVR 的实现 和 WIP OpenHMD 的实现。

    NATIVESCRIPT

    GDNative的早期开发生涯里,它仅被计划用于脚本化编程,后来被发掘出更多灵活和有用的地方,脚本化编程能力现在仅仅是其中一个扩展。

    NativeScript 实现了一套“脚本语言” - 在Godot中可以这么叫,但其实是用GDNative库而不是像GDScript那样的文本和文件的形式来保存相关逻辑。

    NativeScript会调用库中的一个函数 nativescript_init - 告知Godot哪些类和方法是可用的。在要用到那些类和方法的时候,NativeScript就能很简单的去调用这个库来实现相应功能。

    因为 NativeScript 仅对库进行操作,它并不关心这些库是用什么语言构建的,如果开发者要用自己喜欢的编程语言进行库的开发,就使得 NativeScript 成为 Godot 里的一种最佳选择,尽管在这个基础上还要付出很多努力。

    那想要更灵活且更像脚本的感觉的话,就应该考虑用一下 PluginScript 了。

    PLUGINSCRIPT

    PluginScript也是一个扩展,它给Godot加入了封装脚本语言实现的特性。对Godot而言,它是一种运行良好且完全集成的脚本语言,但所有逻辑都是在一个库中实现的。

    NativeScript 把库都当作脚本用,而PluginScript是用库来定义脚本。也就是只要在你的Godot项目中添加一些文件,就可以添加一种新的脚本语言支持。

    目前为止,这种“野生”的主要应用还只有一个 godot-python项目。

    与ARVR扩展类似,PluginScript的API也是非常小巧,仅有一个需要调用的函数 godot_pluginscript_register_language。该函数接受一个struct作为参数,struct里包含函数指针及脚本语言的其它信息。

    Godot编辑器重启后,就能生效了。

    计划

    我们正在计划创建更多的扩展,如可插拔式音视频解码器。

    对于GDNative当前的架构,我们已经相当满意了,下一步主要是完善文档和改善语言绑定。

  • 相关阅读:
    bootstrap table load属性
    Jquery中hide()、show()、remove()特性
    Jquery精准计算
    .nojekyll 文件是什么
    快来用 Nuxt 开发静态网站
    CI:持续集成
    把组件库发布到 npm
    JS的各种模块化规范
    打包发布:让组件库支持按需加载
    docz: 组件库文档 so easy!
  • 原文地址:https://www.cnblogs.com/x3d/p/8274412.html
Copyright © 2011-2022 走看看