>论坛>灵感交流>教程中心>帖子本版发帖返回[BE教程]附加包教程:46.自定义组件(一)Cat_A***Cat_A***当前离线UID82897性别保密经验 EP铁粒 粒回帖0主题精华在线时间 小时注册时间2021-7-23最后登录1970-1-1查看:4232|回复:9
发表于 2024-8-20 11:07:59 来自手机|只看该作者|正序浏览|阅读模式 IP:山西省 本帖最后由 Cat_Anchor 于 2025-1-15 00:02 编辑 注意:此页面所述功能是方块和物品事件的新版本,也就是假日创作者实验移除后的正式特性。由于作者刚学 JavaScript,内容可能有误,我会标注代码的游戏内效果和漏洞。前言实验性玩法“假日创作者功能”的移除可谓是一次巨变。然而,它只是官方正常的开发周期,因为假日创作者功能的功能已经走出了实验性玩法,而一部分内容使用了脚本实现而已。相对于复杂的方块和物品事件语法,脚本是实现复杂逻辑的更优选择。
这次更新会使开发附加包的门槛提高一些,附加包的上限也会提高一些,但这个幅度不会很大,只有方块和物品的技术会提升。不过这次更新会削弱一些只会 JSON 而不会 JavaScript 的开发者,比如曾经的我。那么这是否意味着低质的附加包就完全不会出现,或者很少了呢?答案是不会,因为假日创作者功能的移除只是意味着方块和物品事件系统要被写为脚本,而基础的方块和物品仍然可以用 JSON 定义。
还有一个影响,那就是大部分旧版附加包都会失效,不能正常工作。除非它们的作者继续维护这些附加包,部分无人维护的优质附加包将永远停留在 1.21.2 这个正式版,有点像 Java 版 1.12.2。有些附加包体量过于巨大,靠社区维护可能需要很久。脚本模块为了使用自定义组件,我们首先需要定义附加包的脚本模块,在 manifest.json 的 modules 字段下,如以下数据。{ "type": "script", "uuid": "20240810-e7b7-bbe8-a1a5-e8849ae69cac", //请替换为其他 UUID "version": [ 1, 0, 0 ], //模块的版本 "language": "javascript", "entry": "scripts/main.js" //脚本的接入点文件}复制代码
现在我们需要绑定我们要用的脚本模块和它的版本。比如大部分服务端逻辑都在 @minecraft/server 模块,而现在它的最新版本是 2.0.0-alpha。这个操作使用 dependencies 字段,如以下数据。"dependencies": [ { "module_name": "@minecraft/server", //模块名称 "version": "2.0.0-alpha" //模块版本 }]复制代码
为了使用脚本的额外功能,还可以在 capabilities 数组中添加 script_eval 字符串。
以下是所有可用的模块和它们的最新版本。名称版本@minecraft/common1.2.0@minecraft/debug-utilities1.0.0-beta@minecraft/math1.4.0@minecraft/server1.18.0-beta@minecraft/server-admin1.0.0-beta@minecraft/server-editor0.1.0-beta@minecraft/server-gametest1.0.0-beta@minecraft/server-net1.0.0-beta@minecraft/server-ui1.4.0-beta@minecraft/vanilla-data1.21.30-preview.23(此版本号随游戏更新而变)整个 manifest.json 最后可以是这样的。{ "format_version": 2, "header": { "description": " ", "name": " ", "uuid": "20240428-e59b-a0e4-b8ba-e783ade788b1", //请替换为其他 UUID "version": [ 1, 0, 0 ], "min_engine_version": [ 1, 21, 30 ] }, "modules": [ { "type": "data", "uuid": "20240428-e689-80e4-bba5-e5889be980a0", //请替换为其他 UUID "version": [ 1, 0, 0 ] }, { "type": "script", "uuid": "20240810-e7b7-bbe8-a1a5-e8849ae69cac", "version": [ 1, 0, 0 ], "language": "javascript", "entry": "scripts/main.js" } ], "dependencies": [ { "module_name": "@minecraft/server", "version": "2.0.0-alpha" } ], "capabilities": [ "script_eval" ]}复制代码脚本文件在 scripts 文件夹中创建一个名为 main.js 的文件,现在可以在这个文件里写 JavaScript 了。首先导入模块,可以导入模块的一部分,例如:import { world, system } from '@minecraft/server';复制代码
此时我们可以直接以 world,system 为开头写代码。
或者整个模块,例如:import * as mcs from "@minecraft/server";复制代码其中 mcs 可以自定义。此时使用模块中的类时需要添加 mcs. 前缀,比如 mcs.world。
注册自定义组件的过程是在世界初始化前完成的,所以我们首先订阅世界初始化之前事件:world.beforeEvents.worldInitialize.subscribe();复制代码
括号里的写法是 (参数名) => {代码},这里的参数名可以是任意字符串,比如 event。这里我使用 i,现在代码成了这样:world.beforeEvents.worldInitialize.subscribe((i) => {});复制代码
而我们知道,自定义组件由组件名和触发器两部分组成。所以我们可以定义一个数组,遍历这个数组来注册数组里的所有自定义组件,这样我们就不用每次注册自定义组件都要写一遍 world.beforeEvents.worldInitialize.subscribe 里面的代码了。
为了实现这一点,我们首先定义一个常量数组,就叫 blockComponents:const blockComponents = [];复制代码
现在给数组里加入一个对象:const blockComponents = [{}];复制代码
接着,我们可以定义组件名叫 id,而触发器叫 trigger:const blockComponents = [{ id: "supplementary:invert_texture_shadow", //这里填写自定义组件名,我填写了 supplementary:invert_texture_shadow 作为组件名 trigger: {}}];复制代码
接下来,我们就可以定义它到底拥有怎样的 trigger(触发器),也可以定义触发事件之后会发生什么事了。比如定义一个玩家与方块互动的触发器:const blockComponents = [{ id: "supplementary:invert_texture_shadow", //这里填写自定义组件名,我填写了 supplementary:invert_texture_shadow 作为组件名 trigger: { onPlayerInteract: (e) => {} }}];复制代码
这里的 onPlayerInteract 就相当于以前的 minecraft:on_interact 触发器组件。等等,是不是有点眼熟?(e) => {},这不就是上文提到的 (参数名) => {代码} 吗?没错,就是这样,现在我们又可以自定义一个参数名,这里是 e,和它的代码了。
回到 blockComponents 数组,现在我们可以定义很多个自定义组件了,如下:const blockComponents = [{ id: "supplementary:invert_texture_shadow", trigger: { onPlayerInteract: (e) => { 我是代码 } }},{ id: "supplementary:up_connected_detector", trigger: { onTick: (e) => { 我也是代码 } }}];复制代码
现在还有一个问题,如何注册这些自定义组件?为了注册这些自定义组件,我们要回到这行代码:world.beforeEvents.worldInitialize.subscribe((i) => {});复制代码
现在是时候填充 {} 了。我们可以用 for ... of 循环遍历刚才的数组,如下:world.beforeEvents.worldInitialize.subscribe((i) => { for (const c of blockComponents) {}});复制代码
这行代码的意思是遍历 blockComponents 数组,其中 c 是从 blockComponents 中接收到的值,而 {} 是每次迭代要执行的语句。
所以我们要执行什么语句?当然是注册自定义组件的语句。world.beforeEvents.worldInitialize.subscribe((i) => { for (const c of blockComponents) { i.blockComponentRegistry.registerCustomComponent(); }});复制代码
这里的 blockComponentRegistry 是注册方块组件的代码,如果要注册物品组件,请使用 itemComponentRegistry。注意,这两个方法必须在 world.beforeEvents.worldInitialize.subscribe 中执行。
blockComponentRegistry 需要两个参数,一个是组件名,另一个是触发器,正好与我们的数组对应。因为每次迭代都接收到了数组中的一个对象,我们可以用 c.id 和 c.trigger 指代组件名和触发器,于是代码成了这样:world.beforeEvents.worldInitialize.subscribe((i) => { for (const c of blockComponents) { i.blockComponentRegistry.registerCustomComponent(c.id, c.trigger); }});复制代码
现在我们可以通过修改数组来定义新的自定义组件了!至于如何将自定义组件应用于方块,请看附加包教程第 11 期的“与脚本相关的组件”部分。全部代码如下:import { world, system, Block, BlockEvent, BlockComponentPlayerInteractEvent, BlockComponentTickEvent, EquipmentSlot, ItemStack, Player, EntityComponentTypes } from '@minecraft/server';const blockComponents = [{ id: "supplementary:invert_texture_shadow", trigger: { onPlayerInteract: (e) => { 我是代码 } }},{ id: "supplementary:up_connected_detector", trigger: { onTick: (e) => { 我也是代码 } }}];world.beforeEvents.worldInitialize.subscribe((i) => { for (const c of blockComponents) { i.blockComponentRegistry.registerCustomComponent(c.id, c.trigger); }});复制代码以上代码,经过我的测试,是可以运行的,没有任何问题。现在,我们只需要定义触发器对应的事件就行了,这部分内容放在下期。总结这一期,我们知道了如何注册自定义组件。我的代码可能有误,或者不完善,或者可以优化,欢迎指出错误并提出建议。第四十五期 第四十六期 第四十七期评分 参与人数 1铁粒 +100收起理由 YesN*** + 100期待更多教程!查看全部评分
分享到: QQ好友和群收藏11支持4帖子永久地址: 点击复制苦力怕论坛 - 论坛版权1、本主题所有言论和图片纯属会员个人意见,与本论坛立场无关
2、本站所有主题由该帖子作者发表,该帖子作者享有帖子相关版权
3、其他单位或个人使用、转载或引用本文时必须同时征得该帖子作者的同意
4、帖子作者须承担一切因本文发表而直接或间接导致的民事或刑事法律责任
5、本帖部分内容转载自其它媒体,但并不代表本站赞同其观点和对其真实性负责
6、如本帖侵犯到任何版权问题,请立即告知本站,本站将及时予与删除并致以最深的歉意
7、Minecraft(我的世界)苦力怕论坛管理员和版主有权不事先通知发贴者而删除本文苦力怕论坛,感谢有您~回复使用道具举报
提升卡观察者Yu_Zh***Yu_Zh***当前离线UID323119性别保密经验 EP铁粒 粒回帖0主题精华在线时间 小时注册时间2022-3-18最后登录1970-1-16#
发表于 2025-7-18 11:03:16 来自手机|只看该作者 IP:广东省
我很好奇"capabilities": [
"script_eval"]有什么用6#2025-7-18 11:03:16回复(0)收起回复我要说一句苦力怕论坛,感谢有您~回复支持 使用道具举报
观察者呼啸***呼啸***当前离线UID15672性别保密经验 EP铁粒 粒回帖0主题精华在线时间 小时注册时间2020-10-1最后登录1970-1-15#
发表于 2024-8-31 22:32:58 来自手机|只看该作者 IP:贵州省评论复审中...编号:107513075#2024-8-31 22:32:58回复(2)收起回复Cat_Anchor2024-9-1 06:12IP:天津回复举报实体事件没有移除,物品和方块差不多呼啸泰坦2024-9-20 12:38IP:贵州省回复举报实际上实体事件不能执行指令了,不过dataDrivenEntityTrigger即可我要说一句苦力怕论坛,感谢有您~回复支持 使用道具举报
观察者指令***指令***当前离线UID683950性别保密经验 EP铁粒 粒回帖0主题精华在线时间 小时注册时间2022-10-30最后登录1970-1-14#
发表于 2024-8-20 23:05:32 来自手机|只看该作者 IP:山西省评论复审中...编号:107209204#2024-8-20 23:05:32回复(1)收起回复Cat_Anchor2024-8-21 06:57IP:山西省回复举报是的,这个在下一期提到了我要说一句苦力怕论坛,感谢有您~回复支持 使用道具举报
观察者Cat_A***Cat_A***当前离线UID82897性别保密经验 EP铁粒 粒回帖0主题精华在线时间 小时注册时间2021-7-23最后登录1970-1-13#
楼主|
发表于 2024-8-20 14:47:34 来自手机|只看该作者 IP:山西省评论复审中...编号:107192953#2024-8-20 14:47:34回复(0)收起回复我要说一句苦力怕论坛,感谢有您~回复支持 使用道具举报
观察者星空***星空***当前离线UID1595448性别保密经验 EP铁粒 粒回帖0主题精华在线时间 小时注册时间2024-2-16最后登录1970-1-12#
发表于 2024-8-20 12:46:39 来自手机|只看该作者 IP:山东省评论复审中...编号:107188172#2024-8-20 12:46:39回复(1)收起回复Cat_Anchor2024-8-20 14:11IP:山西省回复举报那些触发器组件(用来触发事件的组件)可以用脚本复原,其他的组件有少部分可以,大部分很难很难我要说一句苦力怕论坛,感谢有您~回复支持 使用道具举报
观察者