【综述&教程】基于GameTest框架编写模组

注意
此文发布于2021年06月27日
第一次修订于2021年11月01日
请关注您当下的阅读时间以确保其时效性
阅读本文要求您对附加包开发的基础知识具有一定了解

导读
此文为基岩版GameTest框架发展现状、应用及使用教程的综述,主要分为四个章节。
第一章为绪论部分,主要综述了GameTest框架是什么,包含什么内容,及其发展现状。
第二章为使用GameTest框架编写模组的简易入门教程,它可以帮助您快速上手。
第三章为本文的总结及对GameTest框架未来发展的展望,个人拙见,望轻喷。
关键词:GameTest框架,Plugin系统,附加包,模组,Minecraft基岩版。

目录
第一章 绪论
1.1 引言
1.2 GameTest框架
1.3 mojang-gametest模块
1.4 mojang-minecraft模块
1.5 发展现状
第二章 简易入门
2.1 清单文件配置
2.2 脚本编写
结语及展望

第一章 绪论
1.1 引言
2021年初,官方开放了GameTest框架接口,旨在提供开发者一个方便的游戏内容测试途径,当然,当时谁也没想到这玩意儿能拿来写模组。可经历了不到半年的发展后,官方不仅为其添加了一定数量的接口函数,甚至引入了事件订阅系统,这时候,GameTest框架用于模组编写这一话题逐渐引起了社区内开发者的关注与讨论。鉴于目前国内社区该领域资料较为稀缺,多数开发者对其也知之甚少,故而特撰此文,对GameTest框架应用于模组编写领域这一课题本人目前的所知所感进行一个系统的综述。本人水平有限,望大佬们不吝斧正。
1.2 GameTest框架
GameTest框架(en: GameTest Framework)是Mojang官方提供给开发者们使用其开放接口的一种方式,归属于官方API一类,全平台可用(目前原主机端除外)。其与脚本引擎类似,通过在清单文件中添加类型为“javascript”的模块,依托于行为包产生效用。官方目前暂未公开对该系统做出正式命名,而是将其归在了GameTest框架的范畴内,且官方表示未来“GameTest框架”作为这个脚本系统的名字肯定是不合适。其目前在社区内也有称呼其为“Plugin系统”的(discord社区中有些官方人员也是这么称呼它的)。关于Plugin这一名称的起源,最初该模块类型的值为“plugin”,后Mojang将其更改为“javascript”,但Plugin这一名称却被沿用了下来。
相较于脚本引擎,GameTest框架是基于另一个JS引擎,QuickJs引擎,采取不同方式编写的一套脚本API。GameTest框架开放接口的方式主要表现为口类——即通过提供接口类来暴露方法及预制类。接口类可以分为两种:一种是静态接口类,这种接口类没有构造函数,不可实例化,不可被继承,其中储存了各种方法或是一些子接口类,例如MinecraftBlockTypes就是一个静态接口类:

另一种接口类则是拥有构造函数的、可实例化的类,开发者可通过这种接口类创建相应的实例对象,例如BlockLocation就是一个可实例化的接口类。

相比脚本引擎的“ECS架构”,此模式更加模块化,语法上相对更为简洁,一定程度上可减轻脚本编写过程中由架构导致的代码冗杂问题。
GameTest框架目前包含了两个接口模块:mojang-gametest与mojang-minecraft,它们本质上是官方开放的两个接口类。mojang-gametest模块是用于测试游戏内容的主要接口模块,gametest功能也就是这个模块实现的。gametest功能是官方提供的通过gametest指令执行脚本函数来测试游戏内容一个工具箱。mojang-minecraft模块则储存了官方提供的有关游戏内容的各种接口,目前已更新了一定数量的接口类。
1.3 mojang-gametest模块
mojang-gametest模块是GameTest框架中的一大模块,其主要的用途就是实现了gametest功能。gametest功能是官方提供的一个工具箱,可用于构建和测试创造者们添加到游戏内的任何新内容。举个例子,假设某开发者在其附加包中新增了某个会主动捡起掉落在地上盔甲并装佩的生物,想要对该生物的行为进行测试,检验其是否符合预期(即在附近有掉落盔甲时会主动捡起并装佩),此时他便可通过GameTest框架中的mojang-gametest模块构建一个特定的gametest测试单元来进行测试,在代码中通过断言类函数(mojang-gametest模块提供的一类函数,一般以assert开头,作为测试条件存在,如:assertEntityHasArmor() 函数,断言实体佩戴有某种盔甲,如无,则抛出错误)与达成类函数(用于判定测试是否成功的函数,一般以succeed开头,使用时会以特定规则执行传入的函数,如函数执行完毕后未抛出错误,则返回测试成功,反之,返回测试失败)设置当该生物佩戴了指定盔甲时即测试成功。此时如果测试失败,则会输出失败提示及相关的一些游戏信息,帮助开发者迅速定位问题所在。当然这个例子显然较为简单,实际上开发者可自定义更加复杂的游戏测试单元,并通过输出的测试信息得到一定的反馈,以达到快速改进或完善内容的目的。

断言类函数(截止1.17.20.20版本)

在实际使用中,开发者通过 /gametest 指令来执行指定的测试单元。而这里的测试单元本质上就是通过mojang-gametest模块注册的脚本代码,其本质上只是一个javascript函数,里面包含了如测试结构(由游戏中结构方块导出的结构文件)的设置、判定断言及测试执行的时长限定等内容。
1.4 mojang-minecraft模块
mojang-minecraft模块是GameTest框架中的另一模块,也是GameTest框架用于编写模组的关键所在。该模块包含了与游戏内容相关的一些接口,用于帮助开发者获取游戏内容并与之进行交互。下面是截止1.17.20.20版本已加入的接口类列表。

同时,mojang-minecraft模块已提供了事件订阅功能,开发者可通过该功能进行游戏事件(包括但不仅仅包括游戏刻事件、天气改变事件、玩家发送聊天信息事件、爆炸事件、方块被活塞推动会事件、生物被添加药水效果事件等等)的订阅。事件订阅的加入意味着GameTest框架拥有了用于编写模组的潜力,但目前可订阅的事件种类较少,游戏内容相关函数也并不完善,暂时不足以满足编写模组的需求,随着mojang的更新,更多事件及函数的加入将使得GameTest框架逐渐具备对游戏玩法进行深入定制的能力,未来可期。
1.5 发展现状
GameTest框架的开发仍处于初级阶段,Mojang工作室近期在此方面的开发与更新也较为活跃。截止本文最后一次修订之日,已更新了11个事件,其中大致可以分为两列:普通事件和before类事件,before类事件允许开发者通过设定返回的事件对象的cancel属性值来取消相应的事件发生,例如通过设定BeforeChatEvent对象的cancel属性为true可取消已发送聊天信息在消息栏的显示。

同时,官方人员曾透露称,他们会考虑在新的API中加入数据储存相关的内容(注意是考虑,而非承诺XD),但为了保证安全性,肯定不会允许自由的读写文件。
截止目前,GameTest框架的API接口并不完善,但已有开发者使用这些相对简单的接口制作了一些有趣的小玩意儿。

第二章 简易入门
由于GameTest框架本质还是属于附加包中行为包的一部分,所以开发相关内容要求您对附加包开发的基础知识有一定了解,此处不再赘述。
2.1 清单文件配置
GameTest框架是依托于行为包产生效用的,开发者可通过在行为包的清单文件(manifest.json)中添加一个类型为javascript的模块来启用它,如下所示:
与其他模块的定义类似,javascript模块同样需要定义描述、uuid、版本号等内容,不同的是,这里的模块类型需要设置为javascript,同时,相比其他模块,javascript模块多了一个entry属性,用于指定入口脚本文件所在路径,也就是被游戏执行的脚本文件,如未指定,则游戏不会运行,该路径必须指向行为包根目录中的scripts文件夹内的某个目录(可含子文件夹),示例中指定的文件为scripts文件夹下的main.js文件。也就是说,对于您的脚本文件来说它的根目录至少也得是行为包根目录的scripts文件夹内。
同时,想要使用mojang-minecraft模块与mojang-gametest模块的接口,您必须在清单文件中添加对这两个模块的依赖:
注意:此处的版本号与uuid都是固定的值,照抄即可,请勿更改。对于版本号,在未来可能会随着游戏版本的更新而更新,请注意关注官方的文档以防止过时的版本号可能带来的未知问题。
此处完整的清单文件如下(注意使用自己的uuid):
2.2 脚本编写
配置好清单文件后,就可以开始写代码了。根据自古以来的惯例(x),此处实现一个Hello World的实例。按照entry指定的路径创建好文件夹与js文件,此处我们在行为包根目录下新建一个scripts文件夹,并在其中新建一个main.js脚本文件,文件结构如下:
向main.js中写入如下代码:
上面的代码实现了当玩家进入游戏后,在主世界内会不停向聊天栏输出一个Hello World信息的效果,由于是使用了tick事件,所以输出的频率为20次/秒。大致执行过程是:玩家进入游戏=>tick事件以20次/秒的频率被触发=>onTick函数以相同频率被回调。
当然由于此处只是订阅了tick事件,并未对回调函数做出什么操作,所以onTick函数和之后的订阅语句二者也可以简写成匿名函数的形式:
将行为包打包并导入游戏中,新建一个世界,应用刚导入的行为包并将GameTest框架实验玩法打开,进入游戏便可看到满屏的Hello World了。


此处只是提供了一个简单的入门教程,更多接口内容请查阅官方的文档(见参考文献部分)。

结语与展望
本文综述了GameTest框架是什么及其目前的发展状况,总的来说GameTest框架还是个新生的事物,还需要官方的开发与完善,但从目前寥寥几个接口中我们也不难看出,它的潜力是巨大的。由于GameTest框架是全平台可用(目前原主机平台除外)的接口,这意味着移动端也可使用此接口集合,这为其在国内基岩版社区的发展提供了良好的基础,对于国内基岩版爪机党玩家来说也是一个福音。同时,就目前已更新的接口来看,GameTest框架对游戏玩法的定制能力无疑会比脚本引擎更加强大,官方开发者memcpy曾在社区中表示:“/gametest指令与脚本(的开发进度)是齐头并进的......这(GameTest框架)是一个新的API集合,独立于2018版(注:此处“2018版”指脚本引擎)”。从这段话中,至少可以确定的是,GameTest框架与脚本引擎之间的关系是相互独立的,就我个人的观点来看,甚至是迭代关系(修订按:这一观点在本文发布不久后的社区问答中被证实了hhh)。至于GameTest框架是否真的会取代脚本引擎,就让时间来告诉我们答案吧。

本文发布不久后(2021.08.06),在官方举办一场关于GT框架的问答会上,官方人员也表示脚本引擎将在GameTest框架覆盖其现有内容后被移除,这也标志着脚本引擎这一旧脚本系统进入了退出基岩版历史舞台的倒计时,而GameTest框架作为基岩版的新一代脚本系统,也正大踏步向前走去,基岩版附加包接口中的一颗新星,正在冉冉升起,还请各位擦亮双眼,一同见证它的成长吧。

参考文献
[1] 微软官方.创作者文档.2021.https://docs.microsoft.com/en-us/minecraft/creator/
[2] Discord社群聊天记录:Bedrock Addon频道
[3] Minecraft Wiki.2021.https://minecraft.fandom.com/wiki/Minecraft_Wiki

致谢
感谢Mojang Studio的开发与工作,设计提供了架构更加合理,功能更加强大的新一代脚本API给社区,并提供了一些文档供社区开发者学习,在GameTest框架的接口方面,官方的文档给予了我很大帮助,同时Mojang工作人员与在社区的活跃发言及对新API相关问题的解答也使得我对GameTest框架有了更加深入的了解,为此文的撰写提供了基础。
同时在此文的撰写上,我也受到了许多开发者同僚的帮助:感谢 @方法放寒假 提供的部分资料支持,咩咩对很多开发技术相关内容都很熟悉,在GameTest框架的发展历史这块内容的编写上也多亏了他在群里提供的一些资料(知识储备)才能够写好。感谢 @yq 提供的部分资料(知识储备)与灵感,感谢参与部分技术性名词译名敲定讨论的开发者们。
感谢各位花时间阅此拙作,希望能给各位带来了些什么。